[Bug 287302] www/mod_perl2: panic: MUTEX_LOCK (22) [Magic.xs:525] during global destruction.

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 17 Jul 2026 16:01:34 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=287302

Emil <emil.nachev@e-card.bg> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |emil.nachev@e-card.bg

--- Comment #8 from Emil <emil.nachev@e-card.bg> ---
Created attachment 272935
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=272935&action=edit
Patch for devel/p5-Variable-Magic (hopefully) fixing bug 287302

Here's a patch for devel/p5-Variable-Magic that seems to fix this issue, at
least on the test environment I set up to replicate it. 

I'm not familiar with Perl internals, so I got Claude to identify the cause.
Here's the relevant part from that back-and-forth:

---

xsh_user_global_teardown runs from call_atexit(xsh_teardown, ...) — Perl's
exit-list mechanism, which fires very early in perl_destruct(), before the
ordinary sweep that
frees the rest of your program's global/persistent SVs (and hence before all
outstanding
Variable::Magic wizards attached to them get freed). If PL_perl_destruct_level
is 0 at
that point, the module destroys vmg_vtable_refcount_mutex right then — not
deferred. Any
wizard SV that gets freed later in the same teardown — which is exactly what's
landing in
vmg_vtable_free() — then tries to lock a mutex that's already gone.
pthread_mutex_lock
on an already-destroyed mutex is precisely what FreeBSD's libthr reports as
EINVAL.
This also explains why neither PL_dirty nor PL_phase == PERL_PHASE_DESTRUCT
fixed it:
those flags describe when in the teardown we are, but the actual hazard is
whether this specific mutex
object still exists. Those are two different things, and nothing before now was
checking the right one.
The module author clearly saw this hazard — that's why the "late registration"
branch exists for
destruct_level != 0. But under mod_perl2 (embedded interpreter,
PL_perl_destruct_level commonly left at its default of 0), you land in the
unsafe immediate-
destroy branch.

---

The patch is simple enough. It takes care of the immediate problem by
explicitly tracking the mutex; however, I'm not sure it's the best way to
address it (again, not familiar with Perl internals).

-- 
You are receiving this mail because:
You are the assignee for the bug.