[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