{
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);
}
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);
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++;
}
{
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;
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;
/* 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 */
};
}
-plan tests => 528; # Update this when adding/deleting tests.
+plan tests => 529; # Update this when adding/deleting tests.
run_tests() unless caller;
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