diff --git a/regcomp.c b/regcomp.c index 660be76858fe..850a6c1544ba 100644 --- a/regcomp.c +++ b/regcomp.c @@ -6133,10 +6133,13 @@ S_free_codeblocks(pTHX_ struct reg_code_blocks *cbs) { int n; - if (cbs->attached) + if (--cbs->refcnt > 0) return; - for (n = 0; n < cbs->count; n++) - SvREFCNT_dec(cbs->cb[n].src_regex); + for (n = 0; n < cbs->count; n++) { + REGEXP *rx = cbs->cb[n].src_regex; + cbs->cb[n].src_regex = NULL; + SvREFCNT_dec(rx); + } Safefree(cbs->cb); Safefree(cbs); } @@ -6148,7 +6151,7 @@ S_alloc_code_blocks(pTHX_ int ncode) struct reg_code_blocks *cbs; Newx(cbs, 1, struct reg_code_blocks); cbs->count = ncode; - cbs->attached = FALSE; + cbs->refcnt = 1; SAVEDESTRUCTOR_X(S_free_codeblocks, cbs); if (ncode) Newx(cbs->cb, ncode, struct reg_code_block); @@ -7168,8 +7171,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, if (pm_flags & PMf_IS_QR) { ri->code_blocks = pRExC_state->code_blocks; if (ri->code_blocks) - /* disarm earlier SAVEDESTRUCTOR_X */ - ri->code_blocks->attached = TRUE; + ri->code_blocks->refcnt++; } { @@ -19533,10 +19535,8 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx) if (ri->u.offsets) Safefree(ri->u.offsets); /* 20010421 MJD */ #endif - if (ri->code_blocks) { - ri->code_blocks->attached = FALSE; + if (ri->code_blocks) S_free_codeblocks(aTHX_ ri->code_blocks); - } if (ri->data) { int n = ri->data->count; @@ -19764,7 +19764,7 @@ Perl_regdupe_internal(pTHX_ REGEXP * const rx, CLONE_PARAMS *param) reti->code_blocks->cb[n].src_regex = (REGEXP*) sv_dup_inc((SV*)(ri->code_blocks->cb[n].src_regex), param); reti->code_blocks->count = ri->code_blocks->count; - reti->code_blocks->attached = TRUE; + reti->code_blocks->refcnt = 1; } else reti->code_blocks = NULL; diff --git a/regexp.h b/regexp.h index 601a214207df..9a2b61a18efc 100644 --- a/regexp.h +++ b/regexp.h @@ -88,7 +88,7 @@ struct reg_code_block { /* array of reg_code_block's plus header info */ struct reg_code_blocks { - bool attached; /* we're attached to a regex (don't need freeing) */ + int refcnt; /* we may be pointed to from a regex and from the savestack */ int count; /* how many code blocks */ struct reg_code_block *cb; /* array of reg_code_block's */ }; diff --git a/t/re/pat_re_eval.t b/t/re/pat_re_eval.t index a51d1d3e03fb..4df88aff575c 100644 --- a/t/re/pat_re_eval.t +++ b/t/re/pat_re_eval.t @@ -22,7 +22,7 @@ BEGIN { } -plan tests => 528; # Update this when adding/deleting tests. +plan tests => 529; # Update this when adding/deleting tests. run_tests() unless caller; @@ -1244,6 +1244,15 @@ sub run_tests { pass "RT #129140"; } + # RT #130650 code blocks could get double-freed during a pattern + # compilation croak + + { + # this used to panic or give ASAN errors + eval 'qr/(?{})\6/'; + like $@, qr/Reference to nonexistent group/, "RT #130650"; + } + } # End of sub run_tests