FIXME: obsolete

1. About

This document describes GC protection for on-stack objects safe against an irregular stack layout such as stack-smashing protection performs.

2. The Problem

Working on the previous stack protection strategy, following problem occurs.(the explanation is based on Anthy-dev 2273 by Jun Inoue, and assumes that the stack grows downward).

Take a look in following code fragment.

{
    ...
    exp = "(number->string (* 32 1024))";
    {
        ScmObj stack_start;
        ScmObj str_port;
        ScmObj obj;

        scm_gc_protect_stack(&stack_start);

        str_port = scm_make_string_port(exp);
        obj = scm_read(str_port);
        obj = SCM_EVAL(obj, SCM_INTERACTION_ENV);

        scm_gc_unprotect_stack(stack_start);
    }

    return SCM_STRING_STR(obj);
}

The previous strategy assumes that stack_start is certainly located at lower than str_port and obj to cover them on the mark-and-sweep stage. But the actual layout breaks the assumption as follows.

At the breakpoint immediately before scm_gc_protect_stack() of the code compiled with gcc4 ((GCC) 4.0.1 20050617 (prerelease) (Debian 4.0.0-10) (IA32)), actual stack layout had been 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.

3. Solution

To accomplish it, a series of macros which turns a function into stack-protected. See following steps to know how to use it.

1) Split the code fragment off into a function. No stack protection handling is needed here.

static const char *
eval_str(const char *exp)
{
    ScmObj str_port;
    ScmObj obj;

    str_port = scm_make_string_port(exp);
    obj = scm_read(str_port);
    obj = SCM_EVAL(obj, SCM_INTERACTION_ENV);
    return SCM_STRING_STR(obj);
}

2) Call the function prepared in 1) with the macro SCM_GC_PROTECTED_CALL() as follows. The macro handles all of the GC protection issues. Once the function returned, the stack protection is disabled again. To protect another function call, apply the macro to the call.

Use SCM_GC_PROTECTED_CALL_VOID() instead if the calee function returns void.

{
    const char *exp, *ret;
    ...
    exp = "(number->string (* 32 1024))";
    SCM_GC_PROTECTED_CALL(ret, const char *, eval_str, (exp));
    return ret;
}