summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-08-04 14:28:15 +0100
committerDavid Mitchell <davem@iabyn.com>2017-08-04 14:33:30 +0100
commit622c613e12cef84c93c5df207a321fe13d0f2a7f (patch)
tree6269bb97139666af24e2eec64fc489588ef7528d /sv.c
parent89042fa4090fc5634ff775e753c58b0827ad6af8 (diff)
downloadperl-622c613e12cef84c93c5df207a321fe13d0f2a7f.tar.gz
PVLV-as-REGEXP: avoid PVX double free
With v5.27.2-30-gdf6b4bd, I changed the way that PVLVs store a regexp value (by making the xpv_len field point to a regexp struct). There was a bug in this, which caused the PVX buffer to be double freed. Several REGEXP SVs can share a PVX buffer. Only one of them will have a non-zero xpv_len field, and that SV gets to free the buffer. After the commit above, the non-zero xpv_len was triggering an extra free. This was showing up in smokes as failures in re/recompile.t when invoked with PERL_DESTRUCT_LEVEL=2 (which t/TEST does).
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/sv.c b/sv.c
index b32db9632b..055f891016 100644
--- a/sv.c
+++ b/sv.c
@@ -6624,7 +6624,6 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
goto freescalar;
case SVt_REGEXP:
/* FIXME for plugins */
- freeregexp:
pregfree2((REGEXP*) sv);
goto freescalar;
case SVt_PVCV:
@@ -6703,7 +6702,16 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
}
else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV** */
SvREFCNT_dec(LvTARG(sv));
- if (isREGEXP(sv)) goto freeregexp;
+ if (isREGEXP(sv)) {
+ /* SvLEN points to a regex body. Free the body, then
+ * set SvLEN to whatever value was in the now-freed
+ * regex body. The PVX buffer is shared by multiple re's
+ * and only freed once, by the re whose len in non-null */
+ STRLEN len = ReANY(sv)->xpv_len;
+ pregfree2((REGEXP*) sv);
+ SvLEN_set((sv), len);
+ goto freescalar;
+ }
/* FALLTHROUGH */
case SVt_PVGV:
if (isGV_with_GP(sv)) {