Skip to content

Commit b1f270f

Browse files
committed
SvPV_shrink_to_cur: don't be unrealistic, do include space for COW
The `SvPV_shrink_to_cur` macro shrinks an allocation to `SvCUR(sv) + 1`, which does not include an additional byte for Copy-On-Write (COW). GH#22116 - a902d92 - short-circuited constant folding on CONST OPs, as this should be unnecessary. However, Dave Mitchell noticed that it had the inadvertent effect of disabling COW on SVs holding UTF8 string literals (e.g. `"\x{100}abcd"`). When a CONST OP is created, `Perl_ck_svconst` should mark its SV as being COW-able. But SVs built via `S_scan_const`, when that has called `SvPV_shrink_to_cur`, have resulting `SvLEN(sv)` values that fail the `SvCANCOW(sv)` test. Previously, constant folding had the effect of copying the literal into a buffer large enough for COW. This commit modifies `SvPV_shrink_to_cur` so that it adds an additional byte to allow for subsequent direct COWing. The macro has also been modified to use the new `expected_size` macro, so that reallocation will not be attempted if the resulting buffer size is not going to be any smaller. The intended saving is compared with SvLEN(sv), rather than SvCUR(sv), as this also helps in cases such as SvCUR(sv) having previously been set to zero and a size smaller than PERL_STRLEN_NEW_MIN is requested. This will also enable some size checks at call sites to be simplified.
1 parent c6b821f commit b1f270f

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

sv.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,9 +1590,22 @@ L</C<SV_CHECK_THINKFIRST_COW_DROP>> before calling this.
15901590
=cut
15911591
*/
15921592

1593-
#define SvPV_shrink_to_cur(sv) STMT_START { \
1594-
const STRLEN _lEnGtH = SvCUR(sv) + 1; \
1595-
SvPV_renew(sv, _lEnGtH); \
1593+
/* Notes: Ensure the buffer is big enough to be COWed in the future, so
1594+
+ 1 for the trailing null byte + 1 for the COW count.
1595+
* The `expected_size` call will, at worst, ensure that the buffer size
1596+
* is no smaller than the expected minimim allocation and that the given
1597+
* size is rounded up to the closest PTRSIZE boundary. Depending on
1598+
* per-malloc implementation, it might return the exact size that would
1599+
* be allocated for the specified _lEnGtH. If the return value from
1600+
* `expected_size` is not smaller than the current buffer allocation,
1601+
* there is no point in calling SvPV_renew.
1602+
*/
1603+
1604+
#define SvPV_shrink_to_cur(sv) STMT_START { \
1605+
const STRLEN _lEnGtH = SvCUR(sv) + 2; \
1606+
const STRLEN _eXpEcT = expected_size(_lEnGtH); \
1607+
if (SvLEN(sv) > _eXpEcT) \
1608+
SvPV_renew(sv, _eXpEcT); \
15961609
} STMT_END
15971610

15981611
/*

0 commit comments

Comments
 (0)