stop S_forget_pmop() SEGVing
authorDavid Mitchell <davem@iabyn.com>
Tue, 13 Mar 2012 14:24:15 +0000 (14:24 +0000)
committerDavid Mitchell <davem@iabyn.com>
Tue, 13 Mar 2012 14:24:15 +0000 (14:24 +0000)
Commit 5bec93be re-purposed the SvMAGIC field of hashes being freed, on
the grounds that (a) any magic had been freed, (b) the refcnt was zero, so
no-one else could mess with the hash.

Unfortunately in the non-threaded case, PMOPs for m?? regexes have a
non-refcounted link back to their stash. When the stash is freed, any subs
in the stash are freed, which frees the PMOPs, which then see the freed
stash, and assume it still has magic because SvMAGIC is non-null.

The quick fix is to check the SvMAGICAL flags first; a longer term fix
would be to avoid the weak ref (e.g. by always using the threaded variant
of PmopSTASH, which stores the stash's *name* rather than a pointer to the
stash).

op.c

diff --git a/op.c b/op.c
index cf3fec0..3bbe4f1 100644 (file)
--- a/op.c
+++ b/op.c
@@ -730,7 +730,7 @@ S_forget_pmop(pTHX_ PMOP *const o
 
     PERL_ARGS_ASSERT_FORGET_PMOP;
 
-    if (pmstash && !SvIS_FREED(pmstash)) {
+    if (pmstash && !SvIS_FREED(pmstash) && SvMAGICAL(pmstash)) {
        MAGIC * const mg = mg_find((const SV *)pmstash, PERL_MAGIC_symtab);
        if (mg) {
            PMOP **const array = (PMOP**) mg->mg_ptr;