Most checksum code in pp_unpack checks against bits_in_uv to decide
to use an UV or a double to collect the checksum. The "C" format
doesn't however. It's needed though, since even on a 32-bit perl
it's perfectly feasable to overflow an UV as soon as you have a string
of more than 2**24 bytes. Even worse, the "U" code reuses part of the
"C" code, and the "U" code *HAS* the switch, so you can cause perl to
fetch the checksum from the wrong variable.
Before:
perl -wle 'print for unpack("C0%128U", "abcd")'
0
After:
./perl -Ilib -wle 'print for unpack("C0%128U", "abcd")'
97
Patch is relative to 5.8.6:
--- pp_pack.c.old Sat Jan 29 13:26:27 2005
+++ pp_pack.c Sat Jan 29 14:13:25 2005
@@ -827,7 +827,10 @@
uchar_checksum:
while (len-- > 0) {
auint = *s++ & 255;
- cuv += auint;
+ if (checksum > bits_in_uv)
+ cdouble += (NV)auint;
+ else
+ cuv += auint;
}
}
else {
@@ -1651,7 +1654,7 @@
sv = NEWSV(42, 0);
if (strchr("fFdD", datumtype) ||
(checksum > bits_in_uv &&
- strchr("csSiIlLnNUvVqQjJ", datumtype&0xFF)) ) {
+ strchr("cCsSiIlLnNUvVqQjJ", datumtype&0xFF)) ) {
NV trouble;
adouble = (NV) (1 << (checksum & 15));