in reply to Re^4: [XS] sv_setpv change in behaviour with perl-5.42.0 and later
in thread [XS] sv_setpv change in behaviour with perl-5.42.0 and later

SvLEN is the size of the buffer currently referenced by SvPVX.

I didn't say a scalar's buffer couldn't be replaced with a smaller one (which would result in a reduction of a scalar's SvLEN). But even so, it doesn't replace a scalar's buffer unless necessary either.

That's why copying a short string over a long one in a buffer doesn't affect the buffer size (in any version of Perl).

use Devel::Peek qw( Dump ); $_ = "x" x 999; $_ .= "x"; # Force unsharing. Dump( $_ ); $_ = "abc"; Dump( $_ );
SV = PV(0x5b5d1f3fdee0) at 0x5b5d1f439bc8 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x5b5d1f441580 "xxx[...]xxx"\0 CUR = 1000 LEN = 1001 SV = PV(0x5b5d1f3fdee0) at 0x5b5d1f439bc8 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x5b5d1f441580 "abc"\0 <-- Same buffer CUR = 3 LEN = 1001 <-- Same size

And that's why the difference between when SvLEN goes down or not is whether Perl must allocate a fresh buffer or not.


OOK is a mechanism which can be used used to efficiently delete from the start of a string. Rather than shifting the entire contents of the buffer, OOK can be used to fake the start and size of the buffer instead.

use Devel::Peek qw( Dump ); $_ = "abcdefghi"; $_ .= "j"; # Force unsharing. Dump( $_ ); substr( $_ , 0 , 1 ) = ""; Dump( $_ );
SV = PV(0x600760853ee0) at 0x6007608a35d8 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x60076086a2e0 "abcdefghij"\0 CUR = 10 LEN = 16 SV = PV(0x600760853ee0) at 0x6007608a35d8 REFCNT = 1 FLAGS = (POK,OOK,pPOK) OFFSET = 1 PV = 0x60076086a2e1 ( "\x01" . ) "bcdefghij"\0 CUR = 9 LEN = 15

There's still a 16 byte buffer at 0x60076086a2e0, and the scalar's buffer was replaced with a a 15 byte virtual buffer at 0x60076086a2e1.


SvCUR is offered as a contrast. SvLENis the size of the buffer, and SvCUR is the portion used. Also, someone looking for SvCUR might have landed on SvLEN.

Replies are listed 'Best First'.
Re^6: [XS] sv_setpv change in behaviour with perl-5.42.0 and later
by Anonymous Monk on Jan 29, 2026 at 22:30 UTC

    What's the logic behind freeing the old buffer and re-allocating if the new length exceeds some limit (and why "1250"?)? For huge initial size, it should be insignificant if new content length is 1249 or 1250. In fact, the "1250" can be replaced with "1e8" (or "1e8 minus something small" if that matters) and again Perl re-allocates. I'd expect the opposite behaviour: if new content is the same or almost as big as container, then re-use the container. If it's couple of droplets in huge vessel, then replace the vessel.

    use Devel::Peek qw( Dump ); $Devel::Peek::pv_limit = $Devel::Peek::pv_limit = 10; my $n; $_ = "x" x 1e8; $_ .= "x"; # Force unsharing. Dump( $_ ); $n = 1249; $_ = "x" x $n; Dump( $_ ); $_ = "x" x 1e8; $_ .= "x"; # Force unsharing. Dump( $_ ); $n = 1250; $_ = "x" x $n; Dump( $_ ); __END__ 5.042000 SV = PV(0x21d90461a70) at 0x21d9049cb58 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x21d9dd19060 "xxxxxxxxxx"...\0 CUR = 100000001 LEN = 100000002 SV = PV(0x21d90461a70) at 0x21d9049cb58 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x21d9dd19060 "xxxxxxxxxx"...\0 CUR = 1249 LEN = 100000002 SV = PV(0x21d90461a70) at 0x21d9049cb58 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x21d9dd1e060 "xxxxxxxxxx"...\0 CUR = 100000001 LEN = 100000002 SV = PV(0x21d90461a70) at 0x21d9049cb58 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x21d90497bd0 "xxxxxxxxxx"...\0 CUR = 1250 LEN = 1256

      I don't know. But that does contradict my assertion that "Perl doesn't replace a scalar's buffer unless necessary either."