[gambit-list] Tracking Down a Segfault

Marc Feeley feeley at iro.umontreal.ca
Fri Sep 5 11:21:35 EDT 2008


On 4-Sep-08, at 10:54 PM, Joel J. Adamson wrote:

> Thanks so much for the tips; I have some follow-up questions:
>
>>>>>> "MM" == Mikael More <mikael.more at gmail.com> writes:
>
>    MM>  - Throwing exceptions with no handler/catcher may sigsegv your
>    MM> app.
>
> Good to know, I was unaware of this.
>
>    MM>  - You should presuppose that ___argXX variables inside
>    MM> Scheme-to-C calls are trashed after C-to-Scheme calls. I.e.: If
>    MM> you have declared a c-define or c-lambda that takes parameters,
>    MM> these will appear as ___arg0, ___arg1 etc. in the C code of the
>    MM> c-define / c-lambda. These will have correct contents all until
>    MM> you invoke Scheme functions from the C code. not afterwards.
>
> Okay, take the following functions, that may be the source of the
> problem:

Indeed your code violates some invariants of Gambit.  The correct code  
is attached below.

The source of the problem is that you are storing references to Scheme  
objects (i.e. the ___SCMOBJ type) in places that the garbage collector  
has no knowledge of (i.e. C variables), so when there is a GC these  
references are not updated when the object referenced is moved by the  
GC.  [Side note: amusingly the code actually works for f64vectors of  
length greater or equal to 128 because those vectors are allocated as  
"still" objects that aren't moved by the GC!]

Here is the sequence of events that cause the problem to occur:

1) scm_vector_to_C receives the parameter f64vec which is a movable  
f64vector (lets call it V)
2) the code calls the C functions f64vector_length and f64vector_ref  
which jump back into Scheme
3) the Scheme code executed when f64vector_ref is called allocates a  
flonum
4) at some point the heap fills up with these flonums and the GC is  
called
5) ***the GC moves V but does not update f64vec in scm_vector_to_C***
6) when the for loop in scm_vector_to_C continues it calls  
f64vector_ref with f64vec, which has a stale reference (it points to  
where V used to be)

There are two solutions:

1) call the macro ___F64VECTORREF (from gambit.h) which does not  
allocate a flonum, and hence does not invoke the GC

2) use an inline code c-lambda where the vector is passed in one of  
the ___argxxx variables.  These variables ***are know to the GC and  
will be updated properly***.  But don't store their content in another  
C variable!

Marc


;;;;;; SOLUTION 1

(c-declare #<<end-of-c-declare

#include <stdlib.h>

#ifdef ___ORIGINAL_CODE___
/*  C function for transferring vectors */
int f64vector_length (___SCMOBJ);
double f64vector_ref (___SCMOBJ, int);
#endif

double * scm_vector_to_C (___SCMOBJ f64vec)
{
  /* initialize the length of the vector */
#ifdef ___ORIGINAL_CODE___
  int len = f64vector_length (f64vec);
#else
  int len = ___INT(___F64VECTORLENGTH(f64vec));
#endif
  /* initializes the new vector */
  double * newCvec = malloc (len*sizeof (double));
  /* declare a counter */
  int i;
  /* iterate over the length of the vector copying each object into
     the new vector */
  for (i = 0; i<len; i++)
    {
      /* could be re-written using pointer arithmetic */
#ifdef ___ORIGINAL_CODE___
      newCvec[i] = f64vector_ref (f64vec, i);
#else
      newCvec[i] = ___F64VECTORREF(f64vec, ___FIX(i));
#endif
    }
  return newCvec;
}
end-of-c-declare
)

;;;;;;;; SOLUTION 2

(define foo
   (c-lambda (scheme-object)
             (pointer double) #<<end-of-code
{
  /* initialize the length of the vector */
  int len = f64vector_length (___arg1);
  /* initializes the new vector */
  double * newCvec = malloc (len*sizeof (double));
  /* declare a counter */
  int i;
  /* iterate over the length of the vector copying each object into
     the new vector */
  for (i = 0; i<len; i++)
    {
      /* could be re-written using pointer arithmetic */
      newCvec[i] = f64vector_ref (___arg1, i);
    }
    ___result_voidstar = newCvec;
}
end-of-code
))





More information about the Gambit-list mailing list