summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2012-09-13 18:13:43 +0200
committerNicholas Clark <nick@ccl4.org>2012-09-14 08:34:18 +0200
commit6c31ff7434088c8eb1fd81ffe6b039a372bd9fc7 (patch)
tree34816515ee1de443587e3b738e8d73cbe0367fe1
parent77f8f7c12a17bc6246ab7d4fd8a427fae71040af (diff)
downloadperl-6c31ff7434088c8eb1fd81ffe6b039a372bd9fc7.tar.gz
Fix buggy -DPERL_POISON code in S_rxres_free(), exposed by a recent test.
The code had been buggily attempting to overwrite just-freed memory since PERL_POISON was added by commit 94010e71b67db040 in June 2005. However, no regression test exercised this code path until recently. Also fix the offset in the array of UVs used by PERL_OLD_COPY_ON_WRITE to store RX_SAVED_COPY(). It now uses p[2]. Previously it had used p[1], directly conflicting with the use of p[1] to store RX_NPARENS(). The code is too intertwined to meaningfully do these as separate commits.
-rw-r--r--pp_ctl.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index 1fc855d82a..ec03976882 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -366,13 +366,13 @@ Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
/* what (if anything) to free on croak */
*p++ = PTR2UV(RX_MATCH_COPIED(rx) ? RX_SUBBEG(rx) : NULL);
RX_MATCH_COPIED_off(rx);
+ *p++ = RX_NPARENS(rx);
#ifdef PERL_OLD_COPY_ON_WRITE
*p++ = PTR2UV(RX_SAVED_COPY(rx));
RX_SAVED_COPY(rx) = NULL;
#endif
- *p++ = RX_NPARENS(rx);
*p++ = PTR2UV(RX_SUBBEG(rx));
*p++ = (UV)RX_SUBLEN(rx);
*p++ = (UV)RX_SUBOFFSET(rx);
@@ -395,6 +395,7 @@ S_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
RX_MATCH_COPY_FREE(rx);
RX_MATCH_COPIED_set(rx, *p);
*p++ = 0;
+ RX_NPARENS(rx) = *p++;
#ifdef PERL_OLD_COPY_ON_WRITE
if (RX_SAVED_COPY(rx))
@@ -403,7 +404,6 @@ S_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
*p++ = 0;
#endif
- RX_NPARENS(rx) = *p++;
RX_SUBBEG(rx) = INT2PTR(char*,*p++);
RX_SUBLEN(rx) = (I32)(*p++);
RX_SUBOFFSET(rx) = (I32)*p++;
@@ -423,19 +423,23 @@ S_rxres_free(pTHX_ void **rsp)
PERL_UNUSED_CONTEXT;
if (p) {
-#ifdef PERL_POISON
void *tmp = INT2PTR(char*,*p);
- Safefree(tmp);
- if (*p)
- PoisonFree(*p, 1, sizeof(*p));
+#ifdef PERL_POISON
+#ifdef PERL_OLD_COPY_ON_WRITE
+ U32 i = 9 + p[1] * 2;
#else
- Safefree(INT2PTR(char*,*p));
+ U32 i = 8 + p[1] * 2;
#endif
+#endif
+
#ifdef PERL_OLD_COPY_ON_WRITE
- if (p[1]) {
- SvREFCNT_dec (INT2PTR(SV*,p[1]));
- }
+ SvREFCNT_dec (INT2PTR(SV*,p[2]));
#endif
+#ifdef PERL_POISON
+ PoisonFree(p, i, sizeof(UV));
+#endif
+
+ Safefree(tmp);
Safefree(p);
*rsp = NULL;
}