Hello-
I have a reproducible SEGV during GC of SMOBs on Guile 2.0.7.
It was also present in 2.0.6.
To reproduce compile main.c as
$ gcc -std=gnu99 -shared -o smobbug.so -Wall -Wextra `pkg-config guile-2.0
--cflags --libs` -fPIC main.c
Then with
$ LD_PRELOAD=./smobbug.so LD_LIBRARY_PATH=. GUILE_LOAD_PATH=. guile
;; At the repl, load the lib
(use-modules (smobbug))
;; Make a SMOB to be GC'd
(handlesmob-init)
;; Trigger a GC from the GC thread
(string-length (make-string 1000))
This gives
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7d98b40 (LWP 20488)]
0xb7f251ab in smob_mark (addr=0x8608ff0, mark_stack_ptr=0xb7d90308,
mark_stack_limit=0xb7d982f0, env=0) at smob.c:325
325 SCM_I_CURRENT_THREAD-current_mark_stack_ptr = mark_stack_ptr;
Here's what's happening internally. When Guile starts up, it creates 3
threads
* Initial thread
* GC thread from scm_storage_prehistory GC_INIT()
* signal delivery thread
That second thread is the one from which automatic garbage collection
occurs. The way that thread gets created, it has an
scm_i_current_thread == NULL, apparently.
So dereferencing scm_i_current_thread causes null dereference.
And smob_mark() will dereference scm_i_current_thread when collecting a
smob with a mark function.
-Mike
(define-module (smobbug)
#:export (
handlesmob-init
))
(load-extension smobbug smobbug_init)
(define (handlesmob-init)
docstring
(%handlesmob-init))
#define _GNU_SOURCE
#include stdio.h
#include libguile.h
static scm_t_bits handlesmob_tag;
void smobbug_init (void);
SCM mark_handle (SCM x);
SCM handlesmob_init ()
{
SCM s_handlesmob;
char *handle;
handle = malloc (1);
return SCM_NEWSMOB (s_handlesmob, handlesmob_tag, handle);
}
SCM
mark_handlesmob (SCM x)
{
// No SCMs in the handle type: nothing to do here.
return (SCM_BOOL_F);
}
size_t
free_handlesmob (SCM handle)
{
SCM_ASSERT (SCM_SMOB_PREDICATE (handlesmob_tag, handle), handle, SCM_ARG1, free-handlesmob);
char *m = SCM_SMOB_DATA (handle);
if (m != NULL)
free (m);
return 0;
}
int
print_handlesmob (SCM x, SCM port, scm_print_state *pstate)
{
char *frm = (char *) SCM_SMOB_DATA (x);
char *str;
scm_puts (#handlesmob , port);
if (frm == (char *) NULL)
{
scm_puts ((freed), port);
}
else
{
if (asprintf (str, %p, frm) 0)
scm_puts (???, port);
else
scm_puts (str, port);
}
scm_puts (, port);
// non-zero means success
return 1;
}
void
smobbug_init ()
{
handlesmob_tag = scm_make_smob_type (handlesmob, sizeof (char *));
scm_set_smob_mark (handlesmob_tag, mark_handlesmob);
scm_set_smob_free (handlesmob_tag, free_handlesmob);
scm_set_smob_print (handlesmob_tag, print_handlesmob);
scm_c_define_gsubr (%handlesmob-init, 0, 0, 0, handlesmob_init);
}