This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix chop formats with non PV vars
authorDavid Mitchell <davem@iabyn.com>
Thu, 7 Nov 2013 12:17:26 +0000 (12:17 +0000)
committerDavid Mitchell <davem@iabyn.com>
Mon, 11 Nov 2013 11:21:40 +0000 (11:21 +0000)
commit9b4bdfd44e0e6d44a447f231c281f967c7ca35c9
treefaa5f43fb5fc1b063fc2328572ffbe00a53f7cf0
parent4a73dc0bc2ea5e1c3bd27a27acd3942dc6aa6c1e
fix chop formats with non PV vars

[perl #119847],  [perl #119849], [perl #119851]

Strange vars like ties, overloads, or stringified refs (and in recent
perls, pure NOK vars) would generally do the wrong thing in formats
when the var is treated as a string and repeatedly chopped, as in
^<<<~~ and similar. This would manifest itself in infinite loops, utf8
errors etc. A recent change that stopped a stringified NOK getting
converted into a POK made the same badness happen for plain NVs too.

This commit contains two main fixes. First, the chopping was done
using sv_chop(), which only worked on POK strings. If its !POK, we now do
sv_setpvn() instead, which is less efficient, but will ensure the right
thing is always done.

Secondly, we make sure that the sv is accessed only once per cycle,
doing s = SvPV(sv, len) or similar. After that, all access is done only
via s and len. One place was using SvPVX(sv), and several places
were using the sv for utf8<->byte length conversions, such as
sv_pos_b2u().

It turns out that all the complex utf8 handling could be enormously
simplified. Since the code that needed to do utf8/byte length conversions
already scanned the string looking for suitable split points (such as
spaces or \n or \r), it was easiest to include any utf8 processing in the
same loop - i.e. incrementing s by UTF8SKIP(s) each time, but incrementing
the character count by 1.

The original diagnosis and reporting of this issue was done by Nicholas
Clark, who also supplied most of the tests.
pp_ctl.c
t/op/write.t