[uim-commit] r1450 - branches/r5rs/sigscheme

yamaken at freedesktop.org yamaken at freedesktop.org
Wed Sep 7 05:14:25 PDT 2005


Author: yamaken
Date: 2005-09-07 05:14:22 -0700 (Wed, 07 Sep 2005)
New Revision: 1450

Added:
   branches/r5rs/sigscheme/storage-protection.c
Modified:
   branches/r5rs/sigscheme/Makefile.am
   branches/r5rs/sigscheme/datas.c
   branches/r5rs/sigscheme/io.c
   branches/r5rs/sigscheme/main.c
   branches/r5rs/sigscheme/sigscheme.c
   branches/r5rs/sigscheme/sigscheme.h
Log:
* This commit adds a GCC4-ready stack protection feature to
  resolve the problem reported in [Anthy-dev 2273] by Jun Inoue
  (Thank you a lot). See the description of storage-protection.c
  for further information.

  Currently the feature is disabled by default since various
  uim-scm related code is not yet support the new
  interface. define SCM_GCC4_READY_GC as 1 to enable it, and
  please try with sscm.

* sigscheme/storage-protection.c
  - New file
  - Add description
  - (SCM_GC_CALL_PROTECTED_FUNC): New macro
  - (gc_protect_stack, gc_unprotect_stack): New static function
  - (SigScm_GC_CallProtectedFunc0, SigScm_GC_CallProtectedFunc1,
    SigScm_GC_CallProtectedFunc2, SigScm_GC_CallProtectedFunc3,
    SigScm_GC_CallProtectedFunc4, SigScm_GC_CallProtectedFunc5): New
    function
* sigscheme/sigscheme.h
  - (ScmGCFunc0, ScmGCFunc1, ScmGCFunc2, ScmGCFunc3, ScmGCFunc4,
    ScmGCFunc5): New type
  - (SCM_GCC4_READY_GC): New macro. Currently defaults to 0
  - (SCM_NOINLINE, SCM_GC_PROTECTED_FUNC,
    SCM_DECLARE_GC_PROTECTED_FUNC_BODY,
    SCM_DEFINE_GC_PROTECTED_FUNC_BODY, SCM_DEFINE_GC_PROTECTED_FUNC0,
    SCM_DEFINE_GC_PROTECTED_FUNC1, SCM_DEFINE_GC_PROTECTED_FUNC2,
    SCM_DEFINE_GC_PROTECTED_FUNC3, SCM_DEFINE_GC_PROTECTED_FUNC4,
    SCM_DEFINE_GC_PROTECTED_FUNC5): New macro
  - (SigScm_Initialize): Change return type void to void * when
    SCM_GCC4_READY_GC is true
  - (SigScm_GC_ProtectStack, SigScm_GC_UnprotectStack): Enclose into
    #if !SCM_GCC4_READY_GC
  - (SigScm_GC_CallProtectedFunc0, SigScm_GC_CallProtectedFunc1,
    SigScm_GC_CallProtectedFunc2, SigScm_GC_CallProtectedFunc3,
    SigScm_GC_CallProtectedFunc4, SigScm_GC_CallProtectedFunc5): New
    function
* sigscheme/datas.c
  - (SigScm_GC_ProtectStack, SigScm_GC_UnprotectStack): Enclose into
    #if !SCM_GCC4_READY_GC
  - (Scm_eval_c_string): Support SCM_GCC4_READY_GC
* sigscheme/sigscheme.c
  - (SigScm_Initialize): Support SCM_GCC4_READY_GC
* sigscheme/main.c
  - (repl): Ditto
* sigscheme/io.c
  - (SigScm_load, ScmOp_require): Ditto
* sigscheme/Makefile.am
  - (libsscm_la_SOURCES): Add storage-protection.c


Modified: branches/r5rs/sigscheme/Makefile.am
===================================================================
--- branches/r5rs/sigscheme/Makefile.am	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/Makefile.am	2005-09-07 12:14:22 UTC (rev 1450)
@@ -1,6 +1,6 @@
 lib_LTLIBRARIES  = libsscm.la
 libsscm_la_SOURCES = \
-		datas.c debug.c \
+		datas.c storage-protection.c debug.c \
 		encoding.c error.c \
 		eval.c io.c \
 		operations.c \

Modified: branches/r5rs/sigscheme/datas.c
===================================================================
--- branches/r5rs/sigscheme/datas.c	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/datas.c	2005-09-07 12:14:22 UTC (rev 1450)
@@ -575,6 +575,7 @@
     scm_freelist = scm_new_freelist;
 }
 
+#if !SCM_GCC4_READY_GC
 void SigScm_GC_ProtectStack(ScmObj *stack_start)
 {
     if (!scm_stack_start_pointer)
@@ -586,6 +587,7 @@
     if (scm_stack_start_pointer == stack_start)
         scm_stack_start_pointer = NULL;
 }
+#endif /* !SCM_GCC4_READY_GC */
 
 /*===========================================================================
   Allocate Structure Functions
@@ -870,14 +872,21 @@
     return sym;
 }
 
+#if SCM_GCC4_READY_GC
+SCM_DEFINE_GC_PROTECTED_FUNC1(, ScmObj, Scm_eval_c_string, const char *, exp)
+{
+#else
 ScmObj Scm_eval_c_string(const char *exp)
 {
     ScmObj stack_start = NULL;
+#endif /* SCM_GCC4_READY_GC */
     ScmObj str_port    = SCM_NULL;
     ScmObj ret         = SCM_NULL;
 
+#if !SCM_GCC4_READY_GC
     /* start protecting stack */
     SigScm_GC_ProtectStack(&stack_start);
+#endif
 
     str_port = Scm_NewStringPort(exp);
 
@@ -888,8 +897,10 @@
     scm_return_value = ret;
 #endif
 
+#if !SCM_GCC4_READY_GC
     /* now no need to protect stack */
     SigScm_GC_UnprotectStack(&stack_start);
+#endif
 
     return ret;
 }

Modified: branches/r5rs/sigscheme/io.c
===================================================================
--- branches/r5rs/sigscheme/io.c	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/io.c	2005-09-07 12:14:22 UTC (rev 1450)
@@ -411,15 +411,22 @@
 /*===========================================================================
   R5RS : 6.6 Input and Output : 6.6.4 System Interface
 ===========================================================================*/
+#if SCM_GCC4_READY_GC
+SCM_DEFINE_GC_PROTECTED_FUNC1(, ScmObj, SigScm_load, const char *, filename)
+{
+#else
 ScmObj SigScm_load(const char *filename)
 {
     ScmObj stack_start  = NULL;
+#endif /* SCM_GCC4_READY_GC */
     ScmObj port         = SCM_NULL;
     ScmObj s_expression = SCM_NULL;
     char  *filepath     = create_valid_path(filename);
 
+#if !SCM_GCC4_READY_GC
     /* start protecting stack */
     SigScm_GC_ProtectStack(&stack_start);
+#endif
 
     /* sanity check */
     /*
@@ -445,8 +452,10 @@
     /* close port */
     ScmOp_close_input_port(port);
 
+#if !SCM_GCC4_READY_GC
     /* now no need to protect stack */
     SigScm_GC_UnprotectStack(&stack_start);
+#endif
 
     /* free str */
     free(filepath);
@@ -514,16 +523,23 @@
  * - provide SIOD compatible behavior about return value when SCM_COMPAT_SIOD
  *   is true
  */
+#if SCM_GCC4_READY_GC
+SCM_DEFINE_GC_PROTECTED_FUNC1(, ScmObj, ScmOp_require, ScmObj, filename)
+{
+#else
 ScmObj ScmOp_require(ScmObj filename)
 {
     ScmObj stack_start = NULL;
+#endif /* SCM_GCC4_READY_GC */
     ScmObj loaded_str  = SCM_NULL;
 
     if (!STRINGP(filename))
         SigScm_ErrorObj("require : string required but got ", filename);
 
+#if !SCM_GCC4_READY_GC
     /* start protecting stack */
     SigScm_GC_ProtectStack(&stack_start);
+#endif
 
     /* construct loaded_str */
     loaded_str = create_loaded_str(filename);
@@ -536,8 +552,10 @@
         SCM_SYMBOL_VCELL(SigScm_features) = CONS(loaded_str, SCM_SYMBOL_VCELL(SigScm_features));
     }
 
+#if !SCM_GCC4_READY_GC
     /* now no need to protect stack */
     SigScm_GC_UnprotectStack(&stack_start);
+#endif
 
     return SCM_TRUE;
 }

Modified: branches/r5rs/sigscheme/main.c
===================================================================
--- branches/r5rs/sigscheme/main.c	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/main.c	2005-09-07 12:14:22 UTC (rev 1450)
@@ -55,16 +55,23 @@
 =======================================*/
 
 /* Very simple repl, please rewrite. */
+#if SCM_GCC4_READY_GC
+SCM_DEFINE_GC_PROTECTED_FUNC0(static, void *, repl)
+{
+#else
 static void repl(void)
 {
     ScmObj stack_start = NULL;
+#endif /* SCM_GCC4_READY_GC */
     ScmObj stdin_port  = SCM_NULL;
     ScmObj stdout_port = SCM_NULL;
     ScmObj s_exp  = SCM_NULL;
     ScmObj result = SCM_NULL;
 
+#if !SCM_GCC4_READY_GC
     /* start protecting stack */
     SigScm_GC_ProtectStack(&stack_start);
+#endif
 
     /* init variable */
     stdin_port  = Scm_NewFilePort(stdin,  "stdin",  PORT_INPUT);
@@ -88,8 +95,12 @@
     ScmOp_close_input_port(stdin_port);
     ScmOp_close_input_port(stdout_port);
 
+#if SCM_GCC4_READY_GC
+    return NULL;
+#else
     /* now no need to protect stack */
     SigScm_GC_UnprotectStack(&stack_start);
+#endif
 }
 
 /*=======================================

Modified: branches/r5rs/sigscheme/sigscheme.c
===================================================================
--- branches/r5rs/sigscheme/sigscheme.c	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/sigscheme.c	2005-09-07 12:14:22 UTC (rev 1450)
@@ -72,11 +72,16 @@
 /*=======================================
   Function Implementations
 =======================================*/
+#if SCM_GCC4_READY_GC
+SCM_DEFINE_GC_PROTECTED_FUNC0(, void *, SigScm_Initialize)
+{
+#else
 void SigScm_Initialize(void)
 {
     ScmObj stack_start = NULL;
 
     SigScm_GC_ProtectStack(&stack_start);
+#endif /* SCM_GCC4_READY_GC */
 
     /*=======================================================================
       Etc Variable Initialization
@@ -376,7 +381,11 @@
     scm_return_value = SCM_NULL;
 #endif
 
+#if SCM_GCC4_READY_GC
+    return NULL;
+#else
     SigScm_GC_UnprotectStack(&stack_start);
+#endif
 }
 
 void SigScm_Finalize()

Modified: branches/r5rs/sigscheme/sigscheme.h
===================================================================
--- branches/r5rs/sigscheme/sigscheme.h	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/sigscheme.h	2005-09-07 12:14:22 UTC (rev 1450)
@@ -53,7 +53,14 @@
 /*=======================================
    Struct Declarations
 =======================================*/
-typedef void (*ScmCFunc) (void);
+typedef void (*ScmCFunc)(void);
+typedef void *(*ScmGCFunc0)(void);
+typedef void *(*ScmGCFunc1)(void *arg0);
+typedef void *(*ScmGCFunc2)(void *arg0, void *arg1);
+typedef void *(*ScmGCFunc3)(void *arg0, void *arg1, void *arg2);
+typedef void *(*ScmGCFunc4)(void *arg0, void *arg1, void *arg2, void *arg3);
+typedef void *(*ScmGCFunc5)(void *arg0, void *arg1, void *arg2, void *arg3,
+                            void *arg4);
 
 /* type declaration */
 #include "sigschemetype.h"
@@ -78,6 +85,7 @@
 #define SCM_STRICT_R5RS         0  /* use strict R5RS check */
 #define SCM_STRICT_ARGCHECK     0  /* enable strict argument check */
 #define SCM_ACCESSOR_ASSERT     0  /* enable strict type check with accessor */
+#define SCM_GCC4_READY_GC       0  /* use experimental gcc4-ready stack protection */
 
 /* dependency resolution */
 #if SCM_COMPAT_SIOD
@@ -88,6 +96,12 @@
 #define SCM_COMPAT_SIOD_BUGS    0
 #endif /* SCM_COMPAT_SIOD */
 
+#ifdef __GNUC__
+#define SCM_NOINLINE __attribute__((noinline))
+#else
+#define SCM_NOINLINE
+#endif /* __GNUC__ */
+
 int SigScm_Die(const char *msg, const char *filename, int line); /* error.c */
 #define SCM_ASSERT(cond) \
     (cond ? 0 : SigScm_Die("assertion failed.", __FILE__, __LINE__))
@@ -113,6 +127,103 @@
     (SCM_SYMBOL_SET_VCELL(Scm_Intern(newsym),                                \
                           SCM_SYMBOL_VCELL(Scm_Intern(sym))))
 
+/*
+ * Function Definition With Automatic Stack Protection
+ *
+ * Users should use SCM_DEFINE_GC_PROTECTED_FUNCn only.
+ */
+#if SCM_GCC4_READY_GC
+
+#define SCM_GC_PROTECTED_FUNC(func) SigScm_GC_ProtectedFunc_##func
+
+#define SCM_DECLARE_GC_PROTECTED_FUNC_BODY(ret_type, func, args)             \
+    ret_type SCM_GC_PROTECTED_FUNC(func) args SCM_NOINLINE;
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, args)              \
+    ret_type                                                                 \
+    SCM_GC_PROTECTED_FUNC(func) args
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC0(sclass, ret_type, func)                \
+    SCM_DECLARE_GC_PROTECTED_FUNC_BODY(ret_type, func, (void))               \
+    sclass ret_type                                                          \
+    func(void)                                                               \
+    {                                                                        \
+        ScmGCFunc0 body = (ScmGCFunc0)SCM_GC_PROTECTED_FUNC(func);           \
+        SigScm_GC_CallProtectedFunc0(body);                                  \
+        return (ret_type)SigScm_GC_CallProtectedFunc0(body);                 \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (void))
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC1(sclass, ret_type, func,                \
+                                      arg0_type, arg0)                       \
+    SCM_DECLARE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0))     \
+    sclass ret_type                                                          \
+    func(arg0_type arg0)                                                     \
+    {                                                                        \
+        ScmGCFunc1 body = (ScmGCFunc1)SCM_GC_PROTECTED_FUNC(func);           \
+        return (ret_type)SigScm_GC_CallProtectedFunc1(body, (void *)arg0);   \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0))
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC2(sclass, ret_type, func,                \
+                                      arg0_type, arg0, arg1_type, arg1)      \
+    sclass ret_type                                                          \
+    func(arg0_type arg0, arg1_type arg1)                                     \
+    {                                                                        \
+        ScmGCFunc2 body = (ScmGCFunc2)SCM_GC_PROTECTED_FUNC(func);           \
+        return (ret_type)SigScm_GC_CallProtectedFunc2(body, arg0, arg1);     \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0,       \
+                                                       arg1_type arg1))
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC3(sclass, ret_type, func,                \
+                                      arg0_type, arg0, arg1_type, arg1,      \
+                                      arg2_type, arg2)                       \
+    sclass ret_type                                                          \
+    func(arg0_type arg0, arg1_type arg1, arg2_type arg2)                     \
+    {                                                                        \
+        ScmGCFunc3 body = (ScmGCFunc3)SCM_GC_PROTECTED_FUNC(func);           \
+        return (ret_type)SigScm_GC_CallProtectedFunc3(body, arg0, arg1,      \
+                                                      arg2);                 \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0,       \
+                                                       arg1_type arg1,       \
+                                                       arg2_type arg2))
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC4(sclass, ret_type, func,                \
+                                      arg0_type, arg0, arg1_type, arg1,      \
+                                      arg2_type, arg2, arg3_type, arg3)      \
+    sclass ret_type                                                          \
+    func(arg0_type arg0, arg1_type arg1, arg2_type arg2, arg3_type arg3)     \
+    {                                                                        \
+        ScmGCFunc4 body = (ScmGCFunc4)SCM_GC_PROTECTED_FUNC(func);           \
+        return (ret_type)SigScm_GC_CallProtectedFunc4(body, arg0, arg1,      \
+                                                      arg2, arg3);           \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0,       \
+                                                       arg1_type arg1,       \
+                                                       arg2_type arg2,       \
+                                                       arg3_type arg3))
+
+#define SCM_DEFINE_GC_PROTECTED_FUNC5(sclass, ret_type, func,                \
+                                      arg0_type, arg0, arg1_type, arg1,      \
+                                      arg2_type, arg2, arg3_type, arg3,      \
+                                      arg4_type, arg4)                       \
+    sclass ret_type                                                          \
+    func(arg0_type arg0, arg1_type arg1, arg2_type arg2, arg3_type arg3,     \
+         arg4_type arg4)                                                     \
+    {                                                                        \
+        ScmGCFunc5 body = (ScmGCFunc5)SCM_GC_PROTECTED_FUNC(func);           \
+        return (ret_type)SigScm_GC_CallProtectedFunc5(body, arg0, arg1,      \
+                                                      arg2, arg3, arg4);     \
+    }                                                                        \
+    SCM_DEFINE_GC_PROTECTED_FUNC_BODY(ret_type, func, (arg0_type arg0,       \
+                                                       arg1_type arg1,       \
+                                                       arg2_type arg2,       \
+                                                       arg3_type arg3,       \
+                                                       arg4_type arg4))
+#endif /* SCM_GCC4_READY_GC */
+
 /*=======================================
    Function Declarations
 =======================================*/
@@ -120,7 +231,11 @@
    SigScheme : Core Functions
 ===========================================================================*/
 /* sigscheme.c */
+#if SCM_GCC4_READY_GC
+void *SigScm_Initialize(void);
+#else
 void SigScm_Initialize(void);
+#endif
 void SigScm_Finalize(void);
 void Scm_RegisterFunc0(const char *name, ScmFuncType0 func);
 void Scm_RegisterFunc1(const char *name, ScmFuncType1 func);
@@ -137,8 +252,10 @@
 void   SigScm_InitStorage(void);
 void   SigScm_FinalizeStorage(void);
 void   SigScm_GC_Protect(ScmObj *var);
+#if !SCM_GCC4_READY_GC
 void   SigScm_GC_ProtectStack(ScmObj *stack_start);
 void   SigScm_GC_UnprotectStack(ScmObj *stack_start);
+#endif
 ScmObj Scm_NewCons(ScmObj a, ScmObj b);
 ScmObj Scm_NewInt(int val);
 ScmObj Scm_NewSymbol(char *name, ScmObj v_cell);
@@ -163,6 +280,28 @@
 ScmObj Scm_return_value(void);
 #endif
 
+/* storage-protection.c */
+#if SCM_GCC4_READY_GC
+/*
+ * Ordinary programs does not need calling these functions directly. Use
+ * SCM_DEFINE_GC_PROTECTED_FUNCn() instead.
+ */
+void  *SigScm_GC_CallProtectedFunc0(ScmGCFunc0 func) SCM_NOINLINE;
+void  *SigScm_GC_CallProtectedFunc1(ScmGCFunc1 func,
+                                    void *arg0) SCM_NOINLINE;
+void  *SigScm_GC_CallProtectedFunc2(ScmGCFunc2 func,
+                                    void *arg0, void *arg1) SCM_NOINLINE;
+void  *SigScm_GC_CallProtectedFunc3(ScmGCFunc3 func,
+                                    void *arg0, void *arg1,
+                                    void *arg2) SCM_NOINLINE;
+void  *SigScm_GC_CallProtectedFunc4(ScmGCFunc4 func,
+                                    void *arg0, void *arg1,
+                                    void *arg2, void *arg3) SCM_NOINLINE;
+void  *SigScm_GC_CallProtectedFunc5(ScmGCFunc5 func,
+                                    void *arg0, void *arg1, void *arg2,
+                                    void *arg3, void *arg4) SCM_NOINLINE;
+#endif /* SCM_GCC4_READY_GC */
+
 /* eval.c */
 ScmObj ScmOp_eval(ScmObj obj, ScmObj env);
 ScmObj ScmOp_apply(ScmObj args, ScmObj env);

Added: branches/r5rs/sigscheme/storage-protection.c
===================================================================
--- branches/r5rs/sigscheme/storage-protection.c	2005-09-07 05:15:46 UTC (rev 1449)
+++ branches/r5rs/sigscheme/storage-protection.c	2005-09-07 12:14:22 UTC (rev 1450)
@@ -0,0 +1,290 @@
+/*===========================================================================
+ *  FileName : storage-protection.c
+ *  About    : GC protection interface
+ *
+ *  Copyright (C) 2005      by YamaKen
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of authors nor the names of its contributors
+ *     may be used to endorse or promote products derived from this software
+ *     without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *  =========================================================================*/
+
+/*
+ * **** THE FUNCTIONS OF THIS FILE MUST NOT BE INLINED INTO CALLER ****
+ *
+ * This file is intentionally separated from datas.c to make the SigScheme GC
+ * safe against an advanced storage layout optimization on stack. At least GCC
+ * 4.0 performs such optimization (reported in [Anthy-dev 2273] by Jun
+ * Inoue. Thank you a lot).
+ *
+ *
+ * The Problem
+ *
+ *   On the previous stack protection strategy, following problem occurs.(the
+ *   explanation is based on [Anthy-dev 2273]).
+ *
+ *   Take a look in following code fragment.
+ *
+ *   {
+ *       ScmObj stack_start;
+ *       ScmObj str_port = SCM_FALSE;
+ *       ScmObj ret = SCM_FALSE;
+ *
+ *       SigScm_GC_ProtectStack(&stack_start);
+ *
+ *       str_port = Scm_NewStringPort(exp);
+ *       ret = SigScm_Read(str_port);
+ *       ret = EVAL(ret, SCM_NULL);
+ *
+ *       SigScm_GC_UnprotectStack(stack_start);
+ *   }
+ *
+ *   The previous strategy assumes that stack_start is certainly located at
+ *   lower than str_port and ret. But the optimization breaks the assumption as
+ *   follows.
+ *
+ *   At the breakpoint immediately before SigScm_GC_ProtectStack() of the code
+ *   compiled with gcc4 ((GCC) 4.0.1 20050617 (prerelease) (Debian 4.0.0-10)
+ *   (IA32)), actual storage layout had reported as follows.
+ *
+ *   (gdb) p &stack_start
+ *   $6 = (ScmObj *) 0xbfffe7d8
+ *   (gdb) p &str_port
+ *   $7 = (ScmObj *) 0xbfffe7dc
+ *   (gdb) p $sp
+ *   $12 = (void *) 0xbfffe7d0
+ *
+ *   This result indicates the storage location order inversion:
+ *
+ *     expected: %esp < &str_port < &stack_start
+ *     actual:   %esp < &stack_start < &str_port
+ *
+ *   So str_port is not protected in the case.
+ *
+ *
+ * Solution
+ *
+ *   - Allocate the stack_start dummy variable in a separated function
+ *
+ *   - Ensure that a code fragment that its stack must be protected is
+ *     certainly executed on the stack higher than stack_start
+ *
+ *   To achieve it, a series of macros which turns a function into
+ *   stack-protected. See following steps to know how to use it.
+ *
+ *   1) Split a code fragment that its stack must be protected off into a
+ *      function. No stack treatment is appried here. The function must return
+ *      a value and cannot be void. Return dummy value if return value is not
+ *      needed.
+ *
+ *      static const char *eval_str(const char *exp)
+ *      {
+ *          ScmObj str_port = SCM_FALSE;
+ *          ScmObj ret = SCM_FALSE;
+ *
+ *          str_port = Scm_NewStringPort(exp);
+ *          ret = SigScm_Read(str_port);
+ *          ret = EVAL(ret, SCM_NULL);
+ *          return SCM_STRING_STR(ret);
+ *      }
+ *
+ *   2) Rewrite 1) with the macro as follows. Select appropriate one that
+ *      accepts same number of arguments of the function. In this case, single
+ *      argument version is selected. Where to be rewritten is only the
+ *      function header. Function body is kept untouched. If the function has
+ *      no storage class specifier such as static, make 1st argument empty.
+ *
+ *      SCM_DEFINE_GC_PROTECTED_FUNC1(static, const char *,
+ *                                    eval_str, const char *, exp)
+ *      {
+ *          ScmObj str_port = SCM_FALSE;
+ *          ScmObj ret = SCM_FALSE;
+ *
+ *          str_port = Scm_NewStringPort(exp);
+ *          ret = SigScm_Read(str_port);
+ *          ret = EVAL(ret, SCM_NULL);
+ *          return SCM_STRING_STR(ret);
+ *      }
+ *
+ *   3) To apply stack protection to the function, simply call it as ordinary
+ *      function. The protection is implicitly performed by hidden code
+ *      fragments embedded in the function by the macro. See following code
+ *      fragment for instance.
+ *
+ *      caller:
+ *      {
+ *          const char *str;
+ *
+ *          <stack is not protected before the function invocation>
+ *
+ *          str = eval_str("(number->string (* 32 1024))");
+ *
+ *          <stack is not protected after the function invocation>
+ *      }
+ *
+ *
+ * Design Considerations
+ *
+ *   - Why don't you merge this file into datas.c?
+ *
+ *     To prevent implicit inlining of the functions. Although the noinline
+ *     attribute is specified for GCC, other platforms needs another
+ *     method. Compiling into a separated object file is an easy way to prevent
+ *     the inlining.
+ *
+ *
+ *   - Why SCM_DEFINE_GC_PROTECTED_FUNCn() does not support void for return
+ *     type?
+ *
+ *     Since my macro programming skill is not enough orz. Would you help me?
+ *
+ *
+ *   - Why don't you use variadic macro?
+ *
+ *     To support C89 environments. Please don't assume that newest GCC on an
+ *     UNIX flavor is the only platform of SigScheme
+ *
+ *
+ *   - Why don't you use SCM_GC_CALL_PROTECTED_FUNC() in client-side code
+ *     directly?
+ *
+ *     Although following form can perform separated gc_protect_stack() and set
+ *     the stack_start pointer appropriately, a corruption may occur.
+ *
+ *       SCM_GC_CALL_PROTECTED_FUNC(str, eval_str("(number->string 32)"));
+ *
+ *     In this case, the target function (eval_str) may be expanded into the
+ *     calee code. This means that its local variables may be relocated into
+ *     caller's own stack frame. Once such relocation has occurred, the
+ *     stack_start pointer will be set to a wrong point upper then the target's
+ *     local variables.
+ *
+ *     To avoid this condition, gc_protect_stack() and gc_unprotect_stack()
+ *     must certainly be invoked in a separated function which will not be
+ *     inlined. So SigScm_GC_CallProtectedFuncn() are prepared as function.
+ *
+ *  -- YamaKen 2005-09-07
+ */
+
+#if SCM_GCC4_READY_GC
+
+/*=======================================
+  System Include
+=======================================*/
+
+/*=======================================
+  Local Include
+=======================================*/
+#include "sigscheme.h"
+#include "sigschemeinternal.h"
+
+/*=======================================
+  File Local Struct Declarations
+=======================================*/
+
+/*=======================================
+  File Local Macro Declarations
+=======================================*/
+#define SCM_GC_CALL_PROTECTED_FUNC(func_invocation)                          \
+    do {                                                                     \
+        void *ret = NULL;                                                    \
+        ScmObj *stack_start;                                                 \
+                                                                             \
+        stack_start = gc_protect_stack();                                    \
+        ret = (func_invocation);                                             \
+        gc_unprotect_stack(stack_start);                                     \
+                                                                             \
+        return ret;                                                          \
+    } while (/* CONSTCOND */ 0)
+
+/*=======================================
+  Variable Declarations
+=======================================*/
+
+/*=======================================
+  File Local Function Declarations
+=======================================*/
+static ScmObj *gc_protect_stack(void);
+static void gc_unprotect_stack(ScmObj *stack_start);
+
+/*=======================================
+  Extern Function Declarations
+=======================================*/
+
+/*=======================================
+  Function Implementations
+=======================================*/
+static ScmObj *gc_protect_stack(void)
+{
+    ScmObj stack_start = NULL;
+
+    if (!scm_stack_start_pointer)
+        scm_stack_start_pointer = &stack_start;
+
+    /* intentionally returning invalidated local address */
+    return &stack_start;
+}
+
+static void gc_unprotect_stack(ScmObj *stack_start)
+{
+    if (scm_stack_start_pointer == stack_start)
+        scm_stack_start_pointer = NULL;
+}
+
+void *SigScm_GC_CallProtectedFunc0(ScmGCFunc0 func)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func());
+}
+
+void *SigScm_GC_CallProtectedFunc1(ScmGCFunc1 func, void *arg0)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func(arg0));
+}
+
+void *SigScm_GC_CallProtectedFunc2(ScmGCFunc2 func, void *arg0, void *arg1)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func(arg0, arg1));
+}
+
+void *SigScm_GC_CallProtectedFunc3(ScmGCFunc3 func, void *arg0, void *arg1,
+                                   void *arg2)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func(arg0, arg1, arg2));
+}
+
+void *SigScm_GC_CallProtectedFunc4(ScmGCFunc4 func, void *arg0, void *arg1,
+                                   void *arg2, void *arg3)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func(arg0, arg1, arg2, arg3));
+}
+
+void *SigScm_GC_CallProtectedFunc5(ScmGCFunc5 func, void *arg0, void *arg1,
+                                   void *arg2, void *arg3, void *arg4)
+{
+    SCM_GC_CALL_PROTECTED_FUNC(func(arg0, arg1, arg2, arg3, arg4));
+}
+
+#endif /* SCM_GCC4_READY_GC */



More information about the uim-commit mailing list