![]() |
|
もう謎ですね…
NullReferenceExceptionが起こる原因は、メソッドの引数に渡される
ポインタがNULLだったからなので、stackallocがNULLを返しているのかなぁと思って
if (p == 0) throw new StackOverflowException();
という風に、NULLかどうかチェックするコードを入れたら、動くようになる…
C#の言語仕様にはstackallocで十分なメモリ領域が確保できない場合は、
StackOverflowExceptionが発生すると書いてある。ということはNULLが返る可能性は無いと思っていいのかな。
なんか、もう…
前のエントリで、0で埋めれば動くと書いたけど、
さらに調べてみると、0で埋めるメソッドの中身を全部コメントアウトしても動くようになった。
前のエントリで例外が発生するメソッドを詳しくみると、stackallocにより確保したメモリが初期化されていなくても、
利用する前にきちんと各要素に値を代入するようになってた。
というか、NullReferenceExceptionは流石に発生しないよね?
さて…起きて遊びに行って帰ってきたら、まぢめに原因を探すかな…
$ make exec && mono Executable.exe
とし、Mono trunk(r111351)で動かしてみたら、x86なのにSystem.IndexOutOfRangeExceptionが…
$ mono --optimize=-all Executable.exe
とすると、System.NullReferenceExceptionが発生する。
例外が発生しているメソッドでは uint* を利用しているので、
uint* hoge = stackalloc uint[SIZE]; → uint[] hoge = new uint[SIZE];
と書き換えると、正常に動作する。ということはインデックスを超えてアクセスしているわけではないのか…
そして、いつぞやのCamelliaの実装のバグを思い出した。
あれは、stackallocで確保されるメモリ領域は初期化されていないため、
適当な値が初期値として入っていることが原因で発生するバグだった。
あのバグはMSの.NET Frameworkではほぼ100%に近い確率でstackallocで確保した
領域の中身が0で初期化されているため、.NET Frameworkでは発生しなかったのだが、
Monoではそうではないため、発生する。今の状況はまさにその通り。
もしやとおもい、stackalloc後に0で初期化するコードを埋め込んだら
動くようになった。結局、僕のプログラムのバグかよ…orz
というわけで、近いうちに修正版をリリースします…
といっても、僕以外に誰も使っていないと思うけどね ;)