if (!dsv)
dsv = (REGEXP*) newSV_type(SVt_REGEXP);
else {
+ assert(SvTYPE(dsv) == SVt_REGEXP || (SvTYPE(dsv) == SVt_PVLV));
+
+ /* our only valid caller, sv_setsv_flags(), should have done
+ * a SV_CHECK_THINKFIRST_COW_DROP() by now */
+ assert(!SvOOK(dsv));
+ assert(!SvIsCOW(dsv));
+ assert(!SvROK(dsv));
+
+ if (SvPVX_const(dsv)) {
+ if (SvLEN(dsv))
+ Safefree(SvPVX(dsv));
+ SvPVX(dsv) = NULL;
+ }
+ SvLEN_set(dsv, 0);
+ SvCUR_set(dsv, 0);
SvOK_off((SV *)dsv);
+
if (islv) {
/* For PVLVs, the head (sv_any) points to an XPVLV, while
* the LV's xpvlenu_rx will point to a regexp body, which
require './test.pl';
}
-plan(tests => 34);
+plan(tests => 37);
sub r {
return qr/Good/;
};
}
pass("PVLV-as-REGEXP double-free of PVX");
+
+# a non-cow SVPV leaked it's string buffer when a REGEXP was assigned to
+# it. Give valgrind/ASan something to work on
+{
+ my $s = substr("ab",0,1); # generate a non-COW string
+ my $r1 = qr/x/;
+ $s = $$r1; # make sure "a" isn't leaked
+ pass("REGEXP leak");
+
+ my $dest = 0;
+ sub Foo99::DESTROY { $dest++ }
+
+ # ditto but make sure we don't leak a reference
+ {
+ my $ref = bless [], "Foo99";
+ my $r2 = qr/x/;
+ $ref = $$r2;
+ }
+ is($dest, 1, "REGEXP RV leak");
+
+ # and worse, assigning a REGEXP to an PVLV that had a string value
+ # caused an assert failure. Same code, but using $_[0] which is an
+ # lvalue, rather than $s.
+
+ my %h;
+ sub {
+ $_[0] = substr("ab",0,1); # generate a non-COW string
+ my $r = qr/x/;
+ $_[0] = $$r; # make sure "a" isn't leaked
+ }->($h{foo}); # passes PVLV to sub
+ is($h{foo}, "(?^:x)", "REGEXP PVLV leak");
+}