diff --git a/NEWS b/NEWS index 0a9ff0e29..bd820a609 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,8 @@ available: Guile is now always configured in "maintainer mode". ** Fix build failure on Debian hppa architecture (bad stack growth detection) ** Fix `gcd' when called with a single, negative argument. ** Fix `Stack overflow' errors seen when building on some platforms +** Fix bug when `scm_with_guile ()' was called several times from the + same thread Changes in 1.8.5 (since 1.8.4) diff --git a/libguile/threads.c b/libguile/threads.c index 1e327c31b..35b54a65d 100644 --- a/libguile/threads.c +++ b/libguile/threads.c @@ -593,10 +593,19 @@ scm_i_init_thread_for_guile (SCM_STACKITEM *base, SCM parent) { /* This thread is already guilified but not in guile mode, just resume it. - - XXX - base might be lower than when this thread was first - guilified. - */ + + A user call to scm_with_guile() will lead us to here. This could + happen from anywhere on the stack, and in particular lower on the + stack than when it was when this thread was first guilified. Thus, + `base' must be updated. */ +#if SCM_STACK_GROWS_UP + if (base < t->base) + t->base = base; +#else + if (base > t->base) + t->base = base; +#endif + scm_enter_guile ((scm_t_guile_ticket) t); return 1; } diff --git a/test-suite/standalone/.gitignore b/test-suite/standalone/.gitignore index dcc8ae303..78af3047c 100644 --- a/test-suite/standalone/.gitignore +++ b/test-suite/standalone/.gitignore @@ -6,3 +6,4 @@ /test-unwind /test-with-guile-module /test-use-srfi +/test-scm-with-guile diff --git a/test-suite/standalone/Makefile.am b/test-suite/standalone/Makefile.am index dd2f3e724..3f591dae5 100644 --- a/test-suite/standalone/Makefile.am +++ b/test-suite/standalone/Makefile.am @@ -121,9 +121,14 @@ test_with_guile_module_LDADD = ${top_builddir}/libguile/libguile.la check_PROGRAMS += test-with-guile-module TESTS += test-with-guile-module +test_scm_with_guile_CFLAGS = ${test_cflags} +test_scm_with_guile_LDADD = ${top_builddir}/libguile/libguile.la +check_PROGRAMS += test-scm-with-guile +TESTS += test-scm-with-guile + else -EXTRA_DIST += test-with-guile-module.c +EXTRA_DIST += test-with-guile-module.c test-scm-with-guile.c endif diff --git a/test-suite/standalone/test-scm-with-guile.c b/test-suite/standalone/test-scm-with-guile.c new file mode 100644 index 000000000..7fe16b351 --- /dev/null +++ b/test-suite/standalone/test-scm-with-guile.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* Test whether `scm_with_guile ()' can be called several times from a given + thread, but from a different stack depth. Up to 1.8.5, `scm_with_guile + ()' would not update the thread's `base' field, which would then confuse + the GC. + + See http://lists.gnu.org/archive/html/guile-devel/2008-11/msg00037.html + for a detailed report. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +static void * +entry_point (void *arg) +{ + /* Invoke the GC. If `THREAD->base' is incorrect, then Guile will just + segfault somewhere in `scm_mark_locations ()'. */ + scm_gc (); + + return NULL; +} + +static void +go_deeper_into_the_stack (unsigned level) +{ + /* The assumption is that the compiler is not smart enough to optimize this + out. */ + if (level > 0) + go_deeper_into_the_stack (level - 1); + else + scm_with_guile (entry_point, NULL); +} + + +int +main (int argc, char *argv[]) +{ + /* Invoke `scm_with_guile ()' from someplace deep into the stack. */ + go_deeper_into_the_stack (100); + + /* Invoke it from much higher into the stack. This time, Guile is expected + to update the `base' field of the current thread. */ + scm_with_guile (entry_point, NULL); + + return 0; +}