in reply to Re: What difference between malloc and Newx, how attach a C string to SV directly?
in thread What difference between malloc and Newx, how attach a C string to SV directly?

Bug 1:

You are including the NUL in the buffer, and you are falsely claiming there is a trailing NUL after the buffer.

sv_usepvn_flags(x, dx, 8, SV_HAS_TRAILING_NUL);
should be
sv_usepvn_flags(x, dx, 7, SV_HAS_TRAILING_NUL);
and it should be written as
sv_usepvn_flags(x, dx, strlen(dx), SV_HAS_TRAILING_NUL);

Bug 2:

The buffer can't be modified, but you offer no protection. For example, $x =~ s/./a/s; will result in undefined behaviour (which fortunately segfaults on my machine).

Add the following:

SvREADONLY_on(x);

I found you can't enlarge the SV containing C string by using .=, no any error throw though.

I already mentioned that. Or rather, I mentioned that it causes the buffer to get replaced with a new one that contains a copy.

Before $x .= "a";:

SV = PV(0x3e1a1785e0) at 0x3e1a197528 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x35260c8bbd5 "dddddd" <-- Pointer into C static storage CUR = 6 LEN = 0 <-- Doesn't belong to Perl.

After $x .= "a";:

SV = PV(0x3e1a1785e0) at 0x3e1a197528 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x3e1a19fe50 "dddddda"\0 <-- New buffer (copy + "a") CUR = 7 LEN = 17 <-- Belongs to Perl.

However, SvREADONLY_on(x) will prevent this. So if you want to allow this, you'll need to remove the READONLY flag, which means you'll need to make a copy of the constant string.

Replies are listed 'Best First'.
Re^3: What difference between malloc and Newx, how attach a C string to SV directly?
by Anonymous Monk on Oct 01, 2019 at 02:00 UTC
    Many Thanks, ikegami, just one question, how perl decide to realloc pv or just make a copy?

      If the scalar's SvLEN is 0, the buffer exists outside of Perl's memory allocation system, so Perl must allocate a new buffer if it needs a larger buffer.

      If the scalar's copy-on-write count is larger than 1, that means two scalars are sharing the buffer, so Perl must allocate a new buffer if it needs to change the contents or size of the buffer.

      Unless I'm missing something, Perl should otherwise realloc if it needs more space, which will extend the existing buffer if possible.

      Note that Perl typically over-allocates to accommodate future growth.

      There are a couple of optimizations (copy-on-write, mortal buffer stealing) that will replace a scalar's buffer when you assign to it. But that's specifically done to avoid copying, so that's different.