Jun Inoue
jun.l****@gmail*****
2005年 8月 24日 (水) 09:57:28 JST
plugin.c で Scm_eval_c_string でクラッシュするバグの原因がわかりました。 以前太田さんが言ってたのは port が sweep されるという事なので多分別物? string port は '\0' を終端マーカーに採用しているようですが、read.c の コードは EOF (== -1) にしか対応していないのに、SCM_PORT_GETC() は 0 を EOF に変換してくれていないので、バッファオーバーランで死にます。 ;; しかも運悪く '\0' 以降に止めてくれる文字があれば ;; クラッシュせずに走りつづける… それから ScmPortInfo の ungottenchar は int 型であるべきです。不都合は EOF読む → unget → 読み直す → 0xff と EOF が区別できない、ぐらいですが、 char が符号無しの処理系では EOF を 0xff と取り違えるので難しいバグになり そうです。 これの追跡中に確認してみたのですが、スタック保護が正しく使えていません。例えば Scm_eval_c_string() に次のようなコードがありますが、 ScmObj stack_start; ScmObj str_port = SCM_NIL; ScmObj ret = SCM_NIL; SigScm_gc_protect_stack(&stack_start); これを gcc (GCC) 4.0.1 20050617 (prerelease) (Debian 4.0.0-10) (IA32) で コンパイルして、protect の直前で状態を調べると (gdb) p &stack_start $6 = (ScmObj *) 0xbfffe7d8 (gdb) p &str_port $7 = (ScmObj *) 0xbfffe7dc (gdb) p $sp $12 = (void *) 0xbfffe7d0 で、%esp < &stack_start < &str_port となっていて、str_port が保護されて いません。 スタック保護は uim_init() で有効にして、ずっとつけっぱなしにしたほうがい いと思います。限界まで conservative GC の false positive を減らしたい人 の為に protect, unprotect は export したままでいいと思いますが、uim はそ れにあたりませんので。 他の方法でこれを解決するなら、uim の uim-scm.c で全ての uim-scheme API について -- Jun Inoue jun.l****@gmail***** -------------- next part -------------- diff -ur sigscheme/read.c ../.r5rs/sigscheme/read.c --- sigscheme/read.c 2005-08-22 13:04:10.000000000 -0700 +++ ../.r5rs/sigscheme/read.c 2005-08-23 17:30:21.000000000 -0700 @@ -52,23 +52,25 @@ /*======================================= File Local Macro Declarations =======================================*/ -#define SCM_PORT_GETC(port, c) \ - do { \ - if (SCM_PORTINFO_UNGOTTENCHAR(port)) { \ - c = SCM_PORTINFO_UNGOTTENCHAR(port); \ - SCM_PORTINFO_UNGOTTENCHAR(port) = 0; \ - } else { \ - switch (SCM_PORTINFO_PORTTYPE(port)) { \ - case PORT_FILE: \ - c = getc(SCM_PORTINFO_FILE(port)); \ - break; \ - case PORT_STRING: \ - c = (*SCM_PORTINFO_STR_CURRENT(port)); \ - SCM_PORTINFO_STR_CURRENT(port)++; \ - break; \ - } \ - SCM_PORTINFO_UNGOTTENCHAR(port) = 0; \ - } \ +#define SCM_PORT_GETC(port, c) \ + do { \ + if (SCM_PORTINFO_UNGOTTENCHAR(port)) { \ + c = SCM_PORTINFO_UNGOTTENCHAR(port); \ + SCM_PORTINFO_UNGOTTENCHAR(port) = 0; \ + } else { \ + switch (SCM_PORTINFO_PORTTYPE(port)) { \ + case PORT_FILE: \ + c = getc(SCM_PORTINFO_FILE(port)); \ + if (c == '\n') SCM_PORTINFO_LINE(port)++; \ + break; \ + case PORT_STRING: \ + c = (*SCM_PORTINFO_STR_CURRENT(port)); \ + SCM_PORTINFO_STR_CURRENT(port)++; \ + break; \ + } \ + if (c == '\0') c = EOF; \ + SCM_PORTINFO_UNGOTTENCHAR(port) = 0; \ + } \ } while (0); #define SCM_PORT_UNGETC(port,c ) \ @@ -127,19 +129,11 @@ while (1) { SCM_PORT_GETC(port, c); if (c == '\n') { - if (SCM_PORTINFO_PORTTYPE(port) == PORT_FILE) { - SCM_PORTINFO_LINE(port)++; - } break; } if (c == EOF ) return c; } continue; - } else if(c == '\n') { - if (SCM_PORTINFO_PORTTYPE(port) == PORT_FILE) { - SCM_PORTINFO_LINE(port)++; - } - continue; } else if(isspace(c)) { continue; } diff -ur sigscheme/sigschemetype.h ../.r5rs/sigscheme/sigschemetype.h --- sigscheme/sigschemetype.h 2005-08-22 13:04:10.000000000 -0700 +++ ../.r5rs/sigscheme/sigschemetype.h 2005-08-23 16:59:50.000000000 -0700 @@ -110,7 +110,7 @@ } str_port; } info; - char ungottenchar; + int ungottenchar; }; typedef struct _ScmContInfo ScmContInfo;