[Anthy-dev 2273] r5rs: Scm_eval_c_string バグ, スタック保護

Back to archive index

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;


Anthy-dev メーリングリストの案内
Back to archive index