Skip to content

Commit cf4c4c8

Browse files
committed
test a regexp doesn't COW an inappropriate SV
1 parent 2d66a3a commit cf4c4c8

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
@@ -5190,6 +5190,7 @@ ext/XS-APItest/t/sv_numeq.t Test sv_numeq
51905190
ext/XS-APItest/t/sv_streq.t Test sv_streq
51915191
ext/XS-APItest/t/svcat.t Test sv_catpvn
51925192
ext/XS-APItest/t/svcatpvf.t Test sv_catpvf argument reordering
5193+
ext/XS-APItest/t/svcow.t Test COW
51935194
ext/XS-APItest/t/sviscow.t Test SvIsCOW
51945195
ext/XS-APItest/t/svpeek.t XS::APItest extension
51955196
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
@@ -3158,6 +3158,17 @@ sv_setsv_cow_hashkey_core()
31583158
bool
31593159
sv_setsv_cow_hashkey_notcore()
31603160

3161+
void
3162+
sv_grow(SV *sv, UV len)
3163+
CODE:
3164+
sv_force_normal(sv);
3165+
SvGROW(sv, len);
3166+
3167+
void
3168+
sv_force_normal(SV *sv)
3169+
CODE:
3170+
sv_force_normal(sv);
3171+
31613172
void
31623173
sv_set_deref(SV *sv, SV *sv2, int which)
31633174
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
@@ -4931,7 +4931,7 @@ Perl_sv_setsv_cow(pTHX_ SV **pdsv, SV *ssv)
49314931
(!CHECK_COWBUF_THRESHOLD(cur, len)
49324932
|| ! CHECK_COW_THRESHOLD(cur, len))) {
49334933
DEBUG_C(PerlIO_printf(Perl_debug_log,
4934-
"Fast copy on write: Sizes not appropriate to COW\n"));
4934+
"Fast copy on write: Sizes %zu/%zu not appropriate to COW\n", cur, len));
49354935
return FALSE;
49364936
}
49374937
if (dsv) {

0 commit comments

Comments
 (0)