Subject: bug#46796: Cuirass & pointer finalization.

From: Mathieu Othacehe <[email-masked]>
Date: Tue, 02 Mar 2021 09:08:56 +0100

Hey Ludo,

Many thanks for your help here, it feels great to have your support as
always.

> First, is this function idempotent?  (Is it OK to close an msg_t
> multiple times.)

The zmq_msg_close function is mostly responsible of freeing the memory
allocated by ZMQ to store the data associated with the message. I think
it is safe to use it multiple times and from different threads.

It is not responsible of freeing the zmq_msg_t structure itself which is
allocated by the user, usually on the stack in C programs.

I have written a small reproducer of the situation:

--8<---------------cut here---------------start------------->8---
(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)))
--8<---------------cut here---------------end--------------->8---

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:

--8<---------------cut here---------------start------------->8---
int
test_close (void *x)
{
	int i;
	char *v = x;

	for (i = 0; i < 64; i++) {
		v[i] = '1';
	}

	return 0;
}
--8<---------------cut here---------------end--------------->8---

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.

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.

Any clues :)?

Thanks,

Mathieu