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));

Reply via email to