There is a particularly nasty crash scenario invloving the garbage collector. The problem is that the dbi free routine calls the dbi close routine, which tries to alloc new SCM nodes. This is bad, because one should not alloc while the garbage collector is running. So add a flag, incidating that a free is in progress. The DBD layers will have to honour this flag. (also fixes one more mem leak). Signed-off-by: Linas Vepstas --- include/guile-dbi/guile-dbi.h | 1 + src/guile-dbi.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) Index: guile-dbi-2.0.0/include/guile-dbi/guile-dbi.h =================================================================== --- guile-dbi-2.0.0.orig/include/guile-dbi/guile-dbi.h 2008-09-16 21:36:22.000000000 -0500 +++ guile-dbi-2.0.0/include/guile-dbi/guile-dbi.h 2008-09-16 21:40:30.000000000 -0500 @@ -34,6 +34,7 @@ typedef struct g_db_handle SCM closed; /* boolean, TRUE if closed otherwise FALSE */ void* handle; void* db_info; + int in_free; } gdbi_db_handle_t; /* end guile smob struct */ Index: guile-dbi-2.0.0/src/guile-dbi.c =================================================================== --- guile-dbi-2.0.0.orig/src/guile-dbi.c 2008-09-16 21:40:24.000000000 -0500 +++ guile-dbi-2.0.0/src/guile-dbi.c 2008-09-16 21:40:30.000000000 -0500 @@ -53,6 +53,8 @@ SCM_DEFINE (make_g_db_handle, "dbi-open" g_db_handle->bcknd = bcknd; g_db_handle->constr = conn_string; g_db_handle->handle = NULL; + g_db_handle->closed = SCM_BOOL_T; + g_db_handle->in_free = 0; g_db_handle->db_info = NULL; bcknd_str = scm_to_locale_string (bcknd); @@ -189,6 +191,9 @@ free_db_handle (SCM g_db_handle_smob) struct g_db_handle *g_db_handle = NULL; g_db_handle = (struct g_db_handle*)SCM_SMOB_DATA(g_db_handle_smob); + if (g_db_handle->in_free) return 0; + g_db_handle->in_free = 1; + close_g_db_handle(g_db_handle_smob); if (g_db_handle != NULL) @@ -325,7 +330,8 @@ __gdbi_dbd_wrap(gdbi_db_handle_t* dbh, c 20))) == NULL) { free(bcknd); - dbh->status = (SCM) scm_cons(scm_from_int(errno), + if (dbh->in_free) return; /* do not SCM anything while in GC */ + dbh->status = scm_cons(scm_from_int(errno), scm_makfrom0str(strerror(errno))); return; } @@ -335,6 +341,8 @@ __gdbi_dbd_wrap(gdbi_db_handle_t* dbh, c if((ret = dlerror()) != NULL) { free(bcknd); + free(func); + if (dbh->in_free) return; /* do not SCM anything while in GC */ dbh->status = (SCM) scm_cons(scm_from_int(1), scm_makfrom0str(ret)); return; @@ -345,8 +353,10 @@ __gdbi_dbd_wrap(gdbi_db_handle_t* dbh, c { free(bcknd); } + + if (dbh->in_free) return; /* do not SCM anything while in GC */ /* todo: error msg to be translated */ - dbh->status = (SCM) scm_cons(scm_from_int(0), + dbh->status = scm_cons(scm_from_int(0), scm_makfrom0str("symbol loaded")); return; }