WebGL-Native: Unityクラッシュする問題
prev: https://zenn.dev/okuoku/scraps/06bf07df1a36a9
next: https://zenn.dev/okuoku/scraps/e085f787df3550
これはマジで解ける気がしない
というわけで諸々対応してUnityを起動してみたが、なぜか起動時に不正なC++仮想関数を実行してクラッシュしてしまう。
Invalid function pointer called with signature 'iiii'. Perhaps this is an invali
d value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling
a function with an incorrect type, which will fail? (it is worth building your s
ource files with -Werror (warnings are errors), as warnings can indicate undefin
ed behavior which can cause this)
Build with ASSERTIONS=2 for more info.
51
51
failed to asynchronously prepare wasm: Error: abort(51) at Error
at jsStackTrace (eval at boot_unity (C:\cygwin64\home\oku\repos\cwgl\jstesta
pp\index.js:568:5), <anonymous>:739:12)
at stackTrace (eval at boot_unity (C:\cygwin64\home\oku\repos\cwgl\jstestapp
\index.js:568:5), <anonymous>:753:11)
at abort (eval at boot_unity (C:\cygwin64\home\oku\repos\cwgl\jstestapp\inde
x.js:568:5), <anonymous>:19:44)
at nullFunc_iiii (eval at boot_unity (C:\cygwin64\home\oku\repos\cwgl\jstest
app\index.js:568:5), <anonymous>:14349:2)
at cb (C:\cygwin64\home\oku\repos\cwgl\jstestapp\nccc-node.js:125:27)
at Object.<anonymous> (C:\cygwin64\home\oku\repos\cwgl\jstestapp\node_module
s\ffi-napi\lib\callback.js:66:27)
at Object.ffi_call (<anonymous>)
at proxy (C:\cygwin64\home\oku\repos\cwgl\jstestapp\node_modules\ffi-napi\li
b\_foreign_function.js:61:14)
at C:\cygwin64\home\oku\repos\cwgl\jstestapp\nccc-node.js:325:21
at eval (eval at boot_unity (C:\cygwin64\home\oku\repos\cwgl\jstestapp\index
.js:568:5), <anonymous>:22318:79)
落ちている関数を特定する
とりあえず -g3
でデバッグ情報を付け、更に該当する関数にclangの組込み関数である __builtin_trap()
を挟んで止めてみることにした。 VisualStudioのデバッガはDWARFも読めるようだ。 そもそも clang が COFF + PDB を出力しているようだ。。偉いね。
バックトレースのシンボルから、メモリマネージャっぽいことはわかる。バックトレースのnode → ネイティブ呼出しの始端である __GLOBAL__sub_I_PlatformDependent_WebGL_Source_2_cpp
がWASM的なエクスポートで、これはEmscriptenの __ATINIT__
配列に登録されているようだ。
NULL ポインタの生成箇所を探す
ねっとりとステップ実行したところ、 NULL
になっているのは↓の位置だった。
ブレークポイントを仕掛けているところから、矢印の場所まで実行する間に呼ばれたJavaScript側の関数は、
DO_call 0 0 [] __GLOBAL__sub_I_PlatformDependent_WebGL_Source_2_cpp
Called _getpagesize
In 321906464496 321906464480 _getpagesize
★↓↓ ここから
Call []
Called _getpagesize
In 321906463440 321906463424 _getpagesize
Call []
Called ___syscall192
In 321906462616 321906462600 ___syscall192
Call [ 192, 2346448 ]
DO_call 3 1 [ 16384, 1097728 ] _memalign
Called getTotalMemory
In 321906455232 321906455216 getTotalMemory
Call []
DO_call end
DO_call 4 1 [ 7592336, 0, 1097728 ] _memset
DO_call end
Called ___syscall91
In 321906462664 321906462648 ___syscall91
Call [ 91, 2346448 ]
Called ___syscall91
In 321906462664 321906462648 ___syscall91
Call [ 91, 2346448 ]
★★↑↑ ここまで
つまり、これらのAPIに console.log
を仕込んで、Node.JSのWebAssemblyで実行した場合と結果を比較してみるのが良いかな。 syscall91
= munmap
、 syscall192
= mmap2
。
memalignが正常に動作していない
まず wasm2c
:
======= START INIT ======
Getpagesize 16384
Getpagesize 16384
GetTotalMemory 33554432
syscall192 memory 7592336 ★ 0x73D990 なので明かにページ境界に居ない
syscall192 success 7592336
Munmap 7592336 { malloc: 7592336, len: 1097728, allocated: true, fd: -1, flags: 34 }
Munmap 8650752 undefined
同じログをNode.JSのWebAssemblyで取ると:
======= START INIT ======
Getpagesize 16384
Getpagesize 16384
GetTotalMemory 33554432
syscall192 memory 7602176 ★ 0x740000 なのでアラインは取れている
syscall192 success 7602176
Munmap 8650752 undefined
Getpagesize 16384
======= END ======
つまり、 mmap
で ページ境界に整列されていないアドレスが取れてしまっている 。これだと正常に動作しない。WebAssemblyでは mmap
に相当する操作は実装できないのでこれはEmscriptenでエミュレートされていて、実際のアドレスの振り出しは memalign
で行われるようになっている。
... たしかに memalign
の第一引数(arg0
: アライン単位)にゼロが渡っている。これは未定義挙動になる。
治った
... というわけで、findIndexで検索するにあたって false
を詰めておいたら 0
でもヒットしてしまったという凡ミスだった。。初期値を -1
にしてゼロが当たるのを回避。
これでUnityのbootまで進んだけど超クッソ激烈に遅く全然起動しない。。流石に ffi-napi
では限界を感じるのでちゃんと N-API なstubを用意した方が良いかな。。