Subject: Re: bug#58732: installer: finalizers & device destroy segfault

From: Mathieu Othacehe <[email-masked]>
Date: Mon, 07 Nov 2022 17:37:24 +0100

Hola,

> Finalizers are set on pointer objects, so they’re invoked when the
> pointer object goes out of scope.  But:
>
>   (eq? (make-pointer 123) (make-pointer 123))
>   => #f

I agree, but somehow this works:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> ,use (parted)
scheme@(guile-user)> (eq? (get-device "/tmp/test.img") (get-device "/tmp/test.img"))
$3 = #t
--8<---------------cut here---------------end--------------->8---

denoting that the "pointer->device!" procedure is working correctly and
the underlying pointer object returned by pointer->procedure is the
same.

> So a possible mistake is to add one finalizer on each pointer object and
> have several pointer objects aliasing the same C object; that’s how you
> can get the same “free” function called several times on the same C
> object.

I don't think that what's happening. I have monitored closely the
%devices weak hash table and it never exceeds the total device count.

We have multiple finalizers registered for the same C pointer but that's
because the weak hash table may be cleaned by (gc) calls, leaving the
opportunity for multiple finalizers registration on the same C pointer.

I attached a reproducer that exposes the double free issue.

--8<---------------cut here---------------start------------->8---
sudo -E guile ~/tmp/parted-bug.scm
double free or corruption (!prev)
Aborted
--8<---------------cut here---------------end--------------->8---

We could save up somewhere which pointers have registered finalizers but
that would prevent the devices garbage collection, in the same way as if
%device was a plain hash table and not a weak one.

That could well be a solution, as I cannot see at the moment how we
could preserve this mechanism and avoid multiple finalization.

Thanks,

Mathieu