summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pod/perlguts.pod7
-rw-r--r--sv.c6
2 files changed, 10 insertions, 3 deletions
diff --git a/pod/perlguts.pod b/pod/perlguts.pod
index 422549e616..fa05c23560 100644
--- a/pod/perlguts.pod
+++ b/pod/perlguts.pod
@@ -261,9 +261,10 @@ somewhere inside the PV, and it discards everything before the
pointer. The efficiency comes by means of a little hack: instead of
actually removing the characters, C<sv_chop> sets the flag C<OOK>
(offset OK) to signal to other functions that the offset hack is in
-effect, and it puts the number of bytes chopped off into the IV field
-of the SV. It then moves the PV pointer (called C<SvPVX>) forward that
-many bytes, and adjusts C<SvCUR> and C<SvLEN>.
+effect, and it moves the PV pointer (called C<SvPVX>) forward
+by the number of bytes chopped off, and adjusts C<SvCUR> and C<SvLEN>
+accordingly. (A portion of the space between the old and new PV
+pointers is used to store the count of chopped bytes.)
Hence, at this point, the start of the buffer that we allocated lives
at C<SvPVX(sv) - SvIV(sv)> in memory and the PV pointer is pointing
diff --git a/sv.c b/sv.c
index 8d23a3a678..e949b3d0c4 100644
--- a/sv.c
+++ b/sv.c
@@ -5075,8 +5075,14 @@ Perl_sv_chop(pTHX_ SV *const sv, const char *const ptr)
evacp = p - evacn;
#endif
+ /* This sets 'delta' to the accumulated value of all deltas so far */
delta += old_delta;
assert(delta);
+
+ /* If 'delta' fits in a byte, store it just prior to the new beginning of
+ * the string; otherwise store a 0 byte there and store 'delta' just prior
+ * to that, using as many bytes as a STRLEN occupies. Thus it overwrites a
+ * portion of the chopped part of the string */
if (delta < 0x100) {
*--p = (U8) delta;
} else {