Skip to content

Commit f078ccd

Browse files
committed
test a regexp doesn't COW an inappropriate SV
1 parent 89553a3 commit f078ccd

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5157,6 +5157,7 @@ ext/XS-APItest/t/sv_numeq.t Test sv_numeq
51575157
ext/XS-APItest/t/sv_streq.t Test sv_streq
51585158
ext/XS-APItest/t/svcat.t Test sv_catpvn
51595159
ext/XS-APItest/t/svcatpvf.t Test sv_catpvf argument reordering
5160+
ext/XS-APItest/t/svcow.t Test COW
51605161
ext/XS-APItest/t/sviscow.t Test SvIsCOW
51615162
ext/XS-APItest/t/svpeek.t XS::APItest extension
51625163
ext/XS-APItest/t/svpv.t More generic SvPVbyte and SvPVutf8 tests

ext/XS-APItest/APItest.xs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3129,6 +3129,17 @@ sv_setsv_cow_hashkey_core()
31293129
bool
31303130
sv_setsv_cow_hashkey_notcore()
31313131

3132+
void
3133+
sv_grow(SV *sv, UV len)
3134+
CODE:
3135+
sv_force_normal(sv);
3136+
SvGROW(sv, len);
3137+
3138+
void
3139+
sv_force_normal(SV *sv)
3140+
CODE:
3141+
sv_force_normal(sv);
3142+
31323143
void
31333144
sv_set_deref(SV *sv, SV *sv2, int which)
31343145
CODE:

ext/XS-APItest/t/svcow.t

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!perl
2+
use strict;
3+
use warnings;
4+
use XS::APItest;
5+
use B;
6+
7+
use Test::More tests => 11;
8+
9+
{
10+
# github #21877
11+
# the regexp engine would COW an SV that had a large
12+
# SvLEN() in cases where sv_setsv() wouldn't.
13+
# This led to some surprises.
14+
# - On cywgin this produced some strange performance problems
15+
# - In general it meant the (large) buffer of the SV remained
16+
# allocated for longer than it otherwise would.
17+
# Also, since the SV became CoW, further copies would also
18+
# be CoW, for example, code like:
19+
#
20+
# while (<>) { # sv_getsv() currently allocates a large-ish buffer
21+
# /regex that (captures)/; # CoW large buffer
22+
# push @save, $_; # copy in @save still has that large buffer
23+
# }
24+
my $x = "Something\n" x 1000;
25+
cmp_ok(length $x, '>=', 1250,
26+
"need to be at least 1250 to be COWed");
27+
sv_grow($x, 1_000_000);
28+
my $ref = B::svref_2object(\$x);
29+
cmp_ok($ref->LEN, '>=', 1_000_000,
30+
"check we got it longer");
31+
ok(!SvIsCOW($x), "not cow before");
32+
is($ref->REFCNT, 1, "expected reference count");
33+
ok($x =~ /me(.)hing/, "match");
34+
ok(!SvIsCOW($x), "not cow after");
35+
36+
# make sure reasonable SVs are COWed
37+
my $y = "Something\n" x 1000;
38+
sv_force_normal($y);
39+
cmp_ok(length $y, '>=', 1250,
40+
"need to be at least 1250 to be COWed");
41+
my $ref2 = B::svref_2object(\$y);
42+
ok(!SvIsCOW($y), "not cow before");
43+
is($ref2->REFCNT, 1, "expected reference count");
44+
ok($y =~ /me(.)hing/, "match");
45+
ok(SvIsCOW($y), "is cow after");
46+
}

sv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4916,7 +4916,7 @@ Perl_sv_setsv_cow(pTHX_ SV **pdsv, SV *ssv)
49164916
(!CHECK_COWBUF_THRESHOLD(cur, len)
49174917
|| ! CHECK_COW_THRESHOLD(cur, len))) {
49184918
DEBUG_C(PerlIO_printf(Perl_debug_log,
4919-
"Fast copy on write: Sizes not appropriate to COW\n"));
4919+
"Fast copy on write: Sizes %zu/%zu not appropriate to COW\n", cur, len));
49204920
return FALSE;
49214921
}
49224922
if (dsv) {

0 commit comments

Comments
 (0)