小松です。

mswin32のruby-1.4.5でnmake testが失敗します。

C:\lang\ruby-1.4.5>ruby sample/test.rb ... bignum ok 1 ok 2 ok 3 ok 4 ok 5 ok 6 ok 7 ok 8 ok 9 ok 10 ok 11 ok 12 ok 13 ok 14 ←ここで、以下のエラーが発生する。 ruby.exe - アプリケーションエラー "0x1003a32b" の命令が "0x02c789d0" のメモリを参照しました。 メモリが "read" になることはできませんでした。
落ちているところは、bignum.cのrb_big_lshift()の*xdsの参照で、 numeric.cのfix_lshift()から呼ばれています。 落ちる原因は、bignew()を呼ぶ前にxの参照がなくなるので、VC 6.0SP3で -Oxだとoptimizerがスタック上のxをlenとして再利用するコードを生成し、 fix_lshift()がスタックに積んだrb_int2big(val)の参照がなくなって、 bignew()から呼ばれるGCで回収されてしまうからでした。 ということで、xdsを操作する前にxが再利用されて回収されないように xds = BDIGITS(x); を*xdsを参照する直前に持ってきたいのですが、いかがでしょうか? なお、参考までにrb_big_lshift()の生成コードをつけます。
□bignum.c VALUE rb_big_lshift(x, y) VALUE x, y; { ... xds = BDIGITS(x); len = RBIGNUM(x)->len; z = bignew(len+s1+1, RBIGNUM(x)->sign); ← この行以降はxの参照はない ... for (i=0; i<len; i++) { num = num | *xds++<<s2; ← ここの*xdsで落ちている *zds++ = BIGLO(num); num = BIGDN(num); } ... } □numeric.c static VALUE fix_lshift(x, y) VALUE x, y; { ... if (width > (sizeof(VALUE)*CHAR_BIT-1) || ((unsigned long)val)>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { return rb_big_lshift(rb_int2big(val), y); ← ここから呼ばれている } ... }
Fri Jun 23 22:34:51 2000 Katsuyuki Komatsu <komatsu / sarion.co.jp> * bignum.c (rb_big_lshift): reorder xds assignment to avoid reusing `x' as `len' by VC++ 6.0 SP3 compiler with -Ox switch.
diff -ru1p ruby-1.4.5.dist/bignum.c ruby-1.4.5/bignum.c --- ruby-1.4.5.dist/bignum.c Fri Jun 23 16:05:48 2000 +++ ruby-1.4.5/bignum.c Fri Jun 23 22:34:51 2000 @@ -1201,3 +1201,2 @@ rb_big_lshift(x, y) if (shift < 0) return rb_big_rshift(x, INT2FIX(-shift)); - xds = BDIGITS(x); len = RBIGNUM(x)->len; @@ -1208,2 +1207,3 @@ rb_big_lshift(x, y) } + xds = BDIGITS(x); for (i=0; i<len; i++) {
PUBLIC _rb_big_lshift _TEXT SEGMENT _x$ = 8 _y$ = 12 _s2$ = 12 _z$ = -4 _len$ = 8 _rb_big_lshift PROC NEAR ; Line 1192 push ecx ; Line 1194 mov eax, DWORD PTR _y$[esp] test al, 1 je SHORT $L56332 sar eax, 1 jmp SHORT $L56333 $L56332: push eax call _rb_num2long add esp, 4 $L56333: push ebx push esi push edi ; Line 1195 mov ebx, eax ; Line 1196 mov edi, eax ; Line 1198 xor esi, esi shr ebx, 4 and edi, 15 ; 0000000fH ; Line 1201 test eax, eax mov DWORD PTR _s2$[esp+12], edi jge SHORT $L55946 neg eax shl eax, 1 or al, 1 push eax mov eax, DWORD PTR _x$[esp+16] push eax call _rb_big_rshift add esp, 8 pop edi pop esi pop ebx ; Line 1216 pop ecx ret 0 $L55946: ; Line 1202 mov eax, DWORD PTR _x$[esp+12] push ebp ; Line 1203 mov ecx, DWORD PTR [eax+12] mov ebp, DWORD PTR [eax+16] ; Line 1204 movsx edx, BYTE PTR [eax+8] mov DWORD PTR _len$[esp+16], ecx ← ここでxが上書きされる lea eax, DWORD PTR [ecx+ebx+1] mov ecx, DWORD PTR _rb_cBignum push edx push eax push ecx call _bignew_1 ← xの参照がなくなるのでGCで回収される ; Line 1205 mov edx, DWORD PTR [eax+16] add esp, 12 ; 0000000cH ; Line 1206 test ebx, ebx mov DWORD PTR _z$[esp+20], eax jle SHORT $L55955 mov ecx, ebx xor eax, eax mov edi, edx lea edx, DWORD PTR [edx+ebx*2] shr ecx, 1 rep stosd adc ecx, ecx rep stosw mov edi, DWORD PTR _s2$[esp+16] $L55955: ; Line 1209 mov ebx, DWORD PTR _len$[esp+16] test ebx, ebx jle SHORT $L55960 $L55958: ; Line 1210 xor eax, eax mov ecx, edi mov ax, WORD PTR [ebp] ← xは回収されているのでここで落ちる add ebp, 2 shl eax, cl ; Line 1211 add edx, 2 or esi, eax mov WORD PTR [edx-2], si ; Line 1212 shr esi, 16 ; 00000010H dec ebx jne SHORT $L55958 $L55960: ; Line 1215 mov ecx, DWORD PTR _z$[esp+20] mov WORD PTR [edx], si push ecx call _bignorm add esp, 4 pop ebp pop edi pop esi pop ebx ; Line 1216 pop ecx ret 0 _rb_big_lshift ENDP -- 小松克行 / Katsuyuki Komatsu <komatsu / sarion.co.jp>