Subject: Re: bug#46796: Cuirass & pointer finalization.

From: Ludovic Courtès <[email-masked]>
Date: Tue, 02 Mar 2021 14:50:01 +0100

Hi!

Mathieu Othacehe <[email-masked]> skribis:

> I have written a small reproducer of the situation:
>
> (use-modules (system foreign)
>              (rnrs bytevectors))
>
> (define close
>   (dynamic-func "test_close" (dynamic-link "/home/mathieu/tmp/libtest")))
>
> (let loop ()
>   (let* ((bv (make-bytevector 64))
>          (ptr (bytevector->pointer bv)))
>     (set-pointer-finalizer! ptr close)
>     (loop)))
>
>
> this program creates a bytevector of 64 bytes and attaches the C
> function "test_close" as a pointer finalizer to the bytevector pointer.
>
> This function looks like:
>
> int
> test_close (void *x)
> {
> 	int i;
> 	char *v = x;
>
> 	for (i = 0; i < 64; i++) {
> 		v[i] = '1';
> 	}
>
> 	return 0;
> }
>
> It overrides the bytevector content, that should cause a segmentation
> error if the bytevector is already freed.
>
> And it does indeed, which makes me think that despite the weak reference
> between the pointer object and the bytevector, the bytevector is already
> GC'd when the finalizer is called.

Hmm I think the bytevector and the pointer object can be finalized in
the same GC cycle; when that happens, you have no guarantee as to the
order in which they are finalized.

IOW, I think you cannot assume, from the pointer finalizer, that the
bytevector is still reachable.

But… is it really similar to your ZMQ issue?  There you had message
object wrappers (as per ‘define-wrapped-pointer-type’) and a pointer
object to the underlying C object, right?

> I'm now using guardians in Guile-Simple-ZMQ instead of pointer
> finalizers, and do not experience crashes anymore, but I would really
> like to understand what's happening here.

Guardians are finalizers; it’s just a different interface.

Ludo’.