Hello,

Milos Nikic, le ven. 11 sept. 2026 13:33:02 -0700, a ecrit:
> Unfortunately, i only have the victim thread, not the destruction thread. Here
> is the backtrace of the crash:
> 
> Thread 26 (Thread 759.26):
> #7  0x08048650 in __assert_fail_base_backtrace (fmt=..., assertion=0x81e3fa0 
> "!
> (r.hard == 1 && r.weak == 0) || !\"refcount detected use-after-free!\""...) at
> ../../libshouldbeinlibc/assert-backtrace.c:59

Ah!

You should have given this backtrace before...

We have already discussed this a decade ago,
http://lists.gnu.org/archive/html/bug-hurd/2016-03/msg00034.html

with the same kind of workaround (but safer)

> I want to write a patch to make the destruction path more cautious but because
> dropping the refcount is atomic, and removing it from the ihash requires the
> write-lock, there is an inherent race window unless we acquire the write-lock
> before dropping the final reference (which would cause massive lock
> contention).
> 
> Do you have a preferred design in mind for how libports should safely hide
> these dying ports from the read-locked iterators without killing performance?

Actually here the assertion is erroneously raised: the entry was not
actually freed (it's still in the hashtables etc.)

The error is rather an improper use of reference counts: there is still
a reference to the port, in the hash tables.

I.e. we should be keeping a weak reference while the port is still in
the hash tables, i.e. make _ports_create_port_internal/ports_import_port
initialize the refcounts to 1, 1 instead of 1, 0. And then
ports_port_deref_weak/ports_port_deref should look for hard being 0 and
weak being 1, i.e. the only reference left is in the hashtable, in which
case we indeed try to complete the deallocation, and once we have the
wrlock we can check if it's indeed still 0 and 1, otherwise there was a
reacquisition through the hashtable, we then abort the deallocation.

Samuel

Reply via email to