環境
Xcode 8.3.2 (Swift 3.1)
動機
EXC_BAD_ACCESS on devices if nested structs are used with Xcode 8.3 and Swift 3.1
https://bugs.swift.org/browse/SR-4432
このバグを踏んだ。
コンパイルは通るがランタイムでその周辺を実行したときにクラッシュする系。(さいわい、最適化により回避されるので、デバッグ端末(しかもarm64に限る)でしか発生しない。)
内容は追っていないが、仮説としてstructのサイズが大きくなったとき、というのがあり、実際にBox化などでstructのサイズを減らすことで回避できた。
structサイズがトリガーとなる仮説に基づき、あるアプリで使っているstructを大きい順に並べたい。(4Kを超えているものがあればアプリ実行してみて確認したい)
メモリレイアウトサイズの取り出しかた
dSYMに含まれているDWARFファイルを dwarfdump
する。
structのメモリサイズ順に並べる全部入りのワンライナー:
f=path-to-.dSYM/Contents/Resources/DWARF/*; for a in $(dwarfdump -arch arm64 "$f" | grep 'TAG_structure_type' | cut -f1 -d:); do dwarfdump --debug-info=$a $f | grep -E '(AT_name|AT_byte_size)' | paste -d, -s - | awk '{print strtonum($5) "\t" $2}'; done | sort -g | uniq
出力例
:
721 "_TtRTC..."
721 "_TtTC..."
1185 "_TtRTC..."
1185 "_TtTC..."
2134 "..."
2134 "Optional"
2139 "Result"
2139 "_TtRGO..."
4537 "..."
4537 "_TtRV..."
最大で4537バイトのstructがあることがわかる。
(nominal以外の合成型も出現する)
解説
ただのgrep,awk芸だが‥
dwarfdump
すると含まれている各 TAG_*
が出力される。
struct
がほしいので TAG_structure_type
だけ取り出す (でいいのか?)。
TAG
の行にアドレスがあるので、それを各々 dwarfdump
に渡して、 AT_name
と AT_byte_size
を取り出して1行にして awk
整形、ソートする。
課題
dwarfdump
で TAG_structure_type
でフィルタしてその AT_name
と AT_byte_size
だけ取り出したい、みたいなオプションの書き方は分からなかった。
demangle
結果表示のなかでmanglingされている名前を戻したい場合は swift-demangle
を使う。
xcrun swift-demangle ...
他の方法
MemoryLayout<T>.size
をつかう
なんらかの方法で T
を収集し、デバッガで実行すればよいが、import
が必要だったり、遅かったり、ある数以上実行すると返ってこなくなったりで、使いづらかった。
コード内で print(MemoryLayout<T>.size)
するには、可視性の問題があった。
アプリの実行ファイル・frameworkのバイナリから取り出す
structのメモリレイアウトサイズは、実行バイナリに入っているのだろうか・・・?