tr///c: handle len(replacement charlist) > 32767
authorDavid Mitchell <davem@iabyn.com>
Fri, 12 Jan 2018 16:21:48 +0000 (16:21 +0000)
committerDavid Mitchell <davem@iabyn.com>
Fri, 19 Jan 2018 13:45:20 +0000 (13:45 +0000)
commit6d63cc8e88a2b96ed80956f16c0978d790bf4411
tree8f0a480fbc708d6d8752f40d4d7fd3adbee6ea16
parentc923a6996655868e1b5140e8e47c2514e006902b
tr///c: handle len(replacement charlist) > 32767

RT #132608

In the non-utf8 case, the /c (complement) flag to tr adds an implied
\x{100}-\x{7fffffff} range to the search charlist. If the replacement list
contains more chars than are paired with the 0-255 part of the search
list, then the excess chars are stored in an extended part of the table.
The excess char count was being stored as a short, which caused problems
if the replacement list contained more than 32767 excess chars: either
substituting the wrong char, or substituting for a char located up to
0xffff bytes in memory before the real translation table.

So change it to SSize_t.

Note that this is only a problem when the search and replacement charlists
are non-utf8, the replacement list contains around 0x8000+ entries, and
where the string being translated is utf8 with at least one codepoint >=
U+8000.
doop.c
ext/B/B.xs
lib/B/Deparse.pm
op.c
op.h
t/op/tr.t