diff options
author | Nicholas Clark <nick@ccl4.org> | 2005-01-21 16:46:49 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2005-01-21 16:46:49 +0000 |
commit | 78d46eaae9d8413e104f494881b97489e46e1fd4 (patch) | |
tree | 4a75ac5fd02180d736cae265ab1a15931bacca42 /pp_pack.c | |
parent | 0b6a08b277db5e6f28a0032a7a0467c048570624 (diff) | |
download | perl-78d46eaae9d8413e104f494881b97489e46e1fd4.tar.gz |
Make the length overrun checking and stack extension table driven.
(Shaves about 3k off pp_pack.o)
p4raw-id: //depot/perl@23853
Diffstat (limited to 'pp_pack.c')
-rw-r--r-- | pp_pack.c | 490 |
1 files changed, 212 insertions, 278 deletions
@@ -239,6 +239,163 @@ S_mul128(pTHX_ SV *sv, U8 m) # define DO_BO_PACK_N(var, type) BO_CANT_DOIT(pack, type) #endif +#define PACK_SIZE_CANNOT_CSUM 0x80 +#define PACK_SIZE_CANNOT_ONLY_ONE 0x40 +#define PACK_SIZE_MASK 0x3F + + +struct packsize_t { + const char *array; + int first; + int size; +}; + +#define PACK_SIZE_NORMAL 0 +#define PACK_SIZE_SHRIEKING 1 + +/* These tables are regenerated by genpacksizetables.pl (and then hand pasted + in). You're unlikely ever to need to regenerate them. */ +#if 'J'-'I' == 1 +/* ASCII */ +unsigned char size_normal[53] = { + /* C */ sizeof(unsigned char), + /* D */ LONG_DOUBLESIZE, + 0, + /* F */ NVSIZE, + 0, 0, + /* I */ sizeof(unsigned int), + /* J */ UVSIZE, + 0, + /* L */ SIZE32, + 0, + /* N */ SIZE32, + 0, 0, + /* Q */ sizeof(Uquad_t), + 0, + /* S */ SIZE16, + 0, + /* U */ sizeof(char), + /* V */ SIZE32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c */ sizeof(char), + /* d */ sizeof(double), + 0, + /* f */ sizeof(float), + 0, 0, + /* i */ sizeof(int), + /* j */ IVSIZE, + 0, + /* l */ SIZE32, + 0, + /* n */ SIZE16, + 0, + /* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM, + /* q */ sizeof(Quad_t), + 0, + /* s */ SIZE16, + 0, 0, + /* v */ SIZE16, + /* w */ sizeof(char) | PACK_SIZE_CANNOT_CSUM +}; +unsigned char size_shrieking[46] = { + /* I */ sizeof(unsigned int), + 0, 0, + /* L */ sizeof(unsigned long), + 0, + /* N */ SIZE32, + 0, 0, 0, 0, + /* S */ sizeof(unsigned short), + 0, 0, + /* V */ SIZE32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* i */ sizeof(int), + 0, 0, + /* l */ sizeof(long), + 0, + /* n */ SIZE16, + 0, 0, 0, 0, + /* s */ sizeof(short), + 0, 0, + /* v */ SIZE16 +}; +struct packsize_t packsize[2] = { + {size_normal, 67, 53}, + {size_shrieking, 73, 46} +}; +#else +/* EBCDIC (or bust) */ +unsigned char size_normal[99] = { + /* c */ sizeof(char), + /* d */ sizeof(double), + 0, + /* f */ sizeof(float), + 0, 0, + /* i */ sizeof(int), + 0, 0, 0, 0, 0, 0, 0, + /* j */ IVSIZE, + 0, + /* l */ SIZE32, + 0, + /* n */ SIZE16, + 0, + /* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM, + /* q */ sizeof(Quad_t), + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* s */ SIZE16, + 0, 0, + /* v */ SIZE16, + /* w */ sizeof(char) | PACK_SIZE_CANNOT_CSUM, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + /* C */ sizeof(unsigned char), + /* D */ LONG_DOUBLESIZE, + 0, + /* F */ NVSIZE, + 0, 0, + /* I */ sizeof(unsigned int), + 0, 0, 0, 0, 0, 0, 0, + /* J */ UVSIZE, + 0, + /* L */ SIZE32, + 0, + /* N */ SIZE32, + 0, 0, + /* Q */ sizeof(Uquad_t), + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* S */ SIZE16, + 0, + /* U */ sizeof(char), + /* V */ SIZE32 +}; +unsigned char size_shrieking[93] = { + /* i */ sizeof(int), + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* l */ sizeof(long), + 0, + /* n */ SIZE16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* s */ sizeof(short), + 0, 0, + /* v */ SIZE16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* I */ sizeof(unsigned int), + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* L */ sizeof(unsigned long), + 0, + /* N */ SIZE32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* S */ sizeof(unsigned short), + 0, 0, + /* V */ SIZE32 +}; +struct packsize_t packsize[2] = { + {size_normal, 131, 99}, + {size_shrieking, 137, 93} +}; +#endif + + /* Returns the sizeof() struct described by pat */ STATIC I32 S_measure_struct(pTHX_ register tempsym_t* symptr) @@ -331,96 +488,58 @@ S_measure_struct(pTHX_ register tempsym_t* symptr) len = (len + 1)/2; size = 1; break; - case 's' | TYPE_IS_SHRIEKING: -#if SHORTSIZE != SIZE16 - size = sizeof(short); - break; -#else - /* FALL THROUGH */ -#endif - case 's': - size = SIZE16; + + + case 'P': + len = 1; + /* FALL THROUGH */ + case 'p': + size = sizeof(char*); break; + + case 's' | TYPE_IS_SHRIEKING: case 'S' | TYPE_IS_SHRIEKING: -#if SHORTSIZE != SIZE16 - size = sizeof(unsigned short); - break; -#else - /* FALL THROUGH */ -#endif case 'v' | TYPE_IS_SHRIEKING: case 'n' | TYPE_IS_SHRIEKING: - case 'v': - case 'n': - case 'S': - size = SIZE16; - break; case 'i' | TYPE_IS_SHRIEKING: - case 'i': - size = sizeof(int); - break; case 'I' | TYPE_IS_SHRIEKING: - case 'I': - size = sizeof(unsigned int); - break; - case 'j': - size = IVSIZE; - break; - case 'J': - size = UVSIZE; - break; case 'l' | TYPE_IS_SHRIEKING: -#if LONGSIZE != SIZE32 - size = sizeof(long); - break; -#else - /* FALL THROUGH */ -#endif - case 'l': - size = SIZE32; - break; case 'L' | TYPE_IS_SHRIEKING: -#if LONGSIZE != SIZE32 - size = sizeof(unsigned long); - break; -#else - /* FALL THROUGH */ -#endif case 'V' | TYPE_IS_SHRIEKING: case 'N' | TYPE_IS_SHRIEKING: + case 'i': + case 'I': + case 'j': + case 'J': + case 'l': + case 's': + case 'v': + case 'n': + case 'S': case 'V': case 'N': case 'L': - size = SIZE32; - break; - case 'P': - len = 1; - /* FALL THROUGH */ - case 'p': - size = sizeof(char*); - break; #ifdef HAS_QUAD case 'q': - size = sizeof(Quad_t); - break; case 'Q': - size = sizeof(Uquad_t); - break; #endif case 'f': - size = sizeof(float); - break; case 'd': - size = sizeof(double); - break; case 'F': - size = NVSIZE; - break; #if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE) case 'D': - size = LONG_DOUBLESIZE; - break; #endif + { + int which = (symptr->code & TYPE_IS_SHRIEKING) + ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL; + int offset + = TYPE_NO_MODIFIERS(symptr->code) - packsize[which].first; + assert (offset >= 0); + assert (offset < packsize[which].size); + size = packsize[which].array[offset] & PACK_SIZE_MASK; + assert(size); + break; + } } total += len * size; } @@ -758,6 +877,32 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c redo_switch: beyond = s >= strend; + { + int which = (symptr->code & TYPE_IS_SHRIEKING) + ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL; + int offset = TYPE_NO_MODIFIERS(datumtype) - packsize[which].first; + + if (offset >= 0 && offset < packsize[which].size) { + /* Data about this template letter */ + unsigned char data = packsize[which].array[offset]; + + if (data) { + /* data nonzero means we can process this letter. */ + long size = data & PACK_SIZE_MASK; + long howmany = (strend - s) / size; + if (len > howmany) + len = howmany; + + if (!checksum || (data & PACK_SIZE_CANNOT_CSUM)) { + if (len && unpack_only_one && + !(data & PACK_SIZE_CANNOT_ONLY_ONE)) + len = 1; + EXTEND(SP, len); + EXTEND_MORTAL(len); + } + } + } + } switch(TYPE_NO_ENDIANNESS(datumtype)) { default: Perl_croak(aTHX_ "Invalid type '%c' in unpack", (int)TYPE_NO_MODIFIERS(datumtype) ); @@ -951,14 +1096,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c XPUSHs(sv_2mortal(sv)); break; case 'c': - if (len > strend - s) - len = strend - s; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { aint = *s++; if (aint >= 128) /* fake up signed chars */ @@ -978,8 +1115,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c symptr->flags &= ~FLAG_UNPACK_DO_UTF8; break; } - if (len > strend - s) - len = strend - s; if (checksum) { uchar_checksum: while (len-- > 0) { @@ -988,10 +1123,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } } else { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); while (len-- > 0) { auint = *s++ & 255; PUSHs(sv_2mortal(newSViv((IV)auint))); @@ -1005,14 +1136,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } if ((symptr->flags & FLAG_UNPACK_DO_UTF8) == 0) goto unpack_C; - if (len > strend - s) - len = strend - s; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0 && s < strend) { STRLEN alen; auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANYUV)); @@ -1029,15 +1152,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 's' | TYPE_IS_SHRIEKING: #if SHORTSIZE != SIZE16 - along = (strend - s) / sizeof(short); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPYNN(s, &ashort, sizeof(short)); DO_BO_UNPACK(ashort, s); @@ -1055,15 +1169,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c /* Fallthrough! */ #endif case 's': - along = (strend - s) / SIZE16; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY16(s, &ai16); DO_BO_UNPACK(ai16, 16); @@ -1083,15 +1188,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'S' | TYPE_IS_SHRIEKING: #if SHORTSIZE != SIZE16 - along = (strend - s) / sizeof(unsigned short); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPYNN(s, &aushort, sizeof(unsigned short)); DO_BO_UNPACK(aushort, s); @@ -1111,15 +1207,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c case 'v': case 'n': case 'S': - along = (strend - s) / SIZE16; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY16(s, &au16); DO_BO_UNPACK(au16, 16); @@ -1143,15 +1230,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'v' | TYPE_IS_SHRIEKING: case 'n' | TYPE_IS_SHRIEKING: - along = (strend - s) / SIZE16; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY16(s, &ai16); s += SIZE16; @@ -1174,15 +1252,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'i': case 'i' | TYPE_IS_SHRIEKING: - along = (strend - s) / sizeof(int); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &aint, 1, int); DO_BO_UNPACK(aint, i); @@ -1198,15 +1267,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'I': case 'I' | TYPE_IS_SHRIEKING: - along = (strend - s) / sizeof(unsigned int); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &auint, 1, unsigned int); DO_BO_UNPACK(auint, i); @@ -1221,15 +1281,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'j': - along = (strend - s) / IVSIZE; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &aiv, 1, IV); #if IVSIZE == INTSIZE @@ -1250,15 +1301,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'J': - along = (strend - s) / UVSIZE; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &auv, 1, UV); #if UVSIZE == INTSIZE @@ -1280,15 +1322,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'l' | TYPE_IS_SHRIEKING: #if LONGSIZE != SIZE32 - along = (strend - s) / sizeof(long); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPYNN(s, &along, sizeof(long)); DO_BO_UNPACK(along, l); @@ -1306,15 +1339,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c /* Fallthrough! */ #endif case 'l': - along = (strend - s) / SIZE32; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY32(s, &ai32); DO_BO_UNPACK(ai32, 32); @@ -1334,15 +1358,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'L' | TYPE_IS_SHRIEKING: #if LONGSIZE != SIZE32 - along = (strend - s) / sizeof(unsigned long); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPYNN(s, &aulong, sizeof(unsigned long)); DO_BO_UNPACK(aulong, l); @@ -1362,15 +1377,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c case 'V': case 'N': case 'L': - along = (strend - s) / SIZE32; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY32(s, &au32); DO_BO_UNPACK(au32, 32); @@ -1394,15 +1400,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; case 'V' | TYPE_IS_SHRIEKING: case 'N' | TYPE_IS_SHRIEKING: - along = (strend - s) / SIZE32; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { COPY32(s, &ai32); s += SIZE32; @@ -1424,11 +1421,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'p': - along = (strend - s) / sizeof(char*); - if (len > along) - len = along; - EXTEND(SP, len); - EXTEND_MORTAL(len); while (len-- > 0) { if (sizeof(char*) > strend - s) break; @@ -1442,10 +1434,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'w': - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); { UV auv = 0; U32 bytes = 0; @@ -1500,15 +1488,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; #ifdef HAS_QUAD case 'q': - along = (strend - s) / sizeof(Quad_t); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { assert (s + sizeof(Quad_t) <= strend); Copy(s, &aquad, 1, Quad_t); @@ -1525,15 +1504,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'Q': - along = (strend - s) / sizeof(Uquad_t); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { assert (s + sizeof(Uquad_t) <= strend); Copy(s, &auquad, 1, Uquad_t); @@ -1552,15 +1522,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c #endif /* float and double added gnb@melba.bby.oz.au 22/11/89 */ case 'f': - along = (strend - s) / sizeof(float); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &afloat, 1, float); DO_BO_UNPACK_N(afloat, float); @@ -1574,15 +1535,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'd': - along = (strend - s) / sizeof(double); - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &adouble, 1, double); DO_BO_UNPACK_N(adouble, double); @@ -1596,15 +1548,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c } break; case 'F': - along = (strend - s) / NVSIZE; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &anv, 1, NV); DO_BO_UNPACK_N(anv, NV); @@ -1619,15 +1562,6 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c break; #if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE) case 'D': - along = (strend - s) / LONG_DOUBLESIZE; - if (len > along) - len = along; - if (!checksum) { - if (len && unpack_only_one) - len = 1; - EXTEND(SP, len); - EXTEND_MORTAL(len); - } while (len-- > 0) { Copy(s, &aldouble, 1, long double); DO_BO_UNPACK_N(aldouble, long double); |