in reply to Re^3: [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

... modifying the buffer does not shrink it

So what does SvLEN tell us about the buffer ?
According to perlapi documentation:
"SvLEN" Returns the size of the string buffer in the SV, not including any part attributable to "SvOOK". See "SvCUR".
Now, I don't understand the reference to "SvOOK" and "SvCUR", but the bit that says "Returns the size of the string buffer in the SV" means (to me) that if the value of LEN (ie SvLEN) has been reduced, then size of the buffer has been reduced - ie the buffer has been shrunk.
Not so ?

Cheers,
Rob

Replies are listed 'Best First'.
Re^5: [XS] sv_setpv change in behaviour with perl-5.42.0 and later
by dave_the_m (Monsignor) on Jan 29, 2026 at 13:23 UTC
    I think this is a matter of semantics. A particular buffer, once allocated, has size SvLEN() and never shrinks. However, that buffer can (under some circumstances) be freed and a different buffer allocated with a smaller SvLEN().

    Dave.

      However, that buffer can (under some circumstances) be freed and a different buffer allocated with a smaller SvLEN().

      Yep - and my first little demo is one that hits one of those "circumstances" when run on perl-5.42.0, but not when run on perl-5.40.0.
      (That's the change in behaviour that bothered me a little.)
      The fact (AFAIK) that it hasn't broken any modules on cpan suggests that this change is not something to be too concerned about.

      And we don't have to invoke XS to demonstrate the change. The following one liner will do that quite well:
      $ perl -MDevel::Peek -le '$x = "x" x 65; Dump $x; $x = "y"; Dump $x;'
      On perl-5.40.0, the Dump() shows that the address associated with $x's "PV" retains it's initial setting, and the value of $x's SvLEN remains at its original value.
      Neither of those 2 things hold on perl-5.42.0, with SvLEN being significantly reduced.

      Thanks guys.

      Cheers,
      Rob

        Yeah, you don't need XS. As I explained, the change was to make "x" x 65 behave the same as "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", and you never used XS for the "x" x 65 part.

Re^5: [XS] sv_setpv change in behaviour with perl-5.42.0 and later
by ikegami (Patriarch) on Jan 29, 2026 at 15:45 UTC

    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.

      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."