mirror of
https://github.com/lua/lua
synced 2024-11-24 21:59:41 +03:00
Removed 'int' size limit for pack/unpack
This commit is contained in:
parent
e24ce8c2b3
commit
ec65ab878e
67
lstrlib.c
67
lstrlib.c
@ -1447,14 +1447,14 @@ typedef enum KOption {
|
|||||||
*/
|
*/
|
||||||
static int digit (int c) { return '0' <= c && c <= '9'; }
|
static int digit (int c) { return '0' <= c && c <= '9'; }
|
||||||
|
|
||||||
static int getnum (const char **fmt, int df) {
|
static size_t getnum (const char **fmt, size_t df) {
|
||||||
if (!digit(**fmt)) /* no number? */
|
if (!digit(**fmt)) /* no number? */
|
||||||
return df; /* return default value */
|
return df; /* return default value */
|
||||||
else {
|
else {
|
||||||
int a = 0;
|
size_t a = 0;
|
||||||
do {
|
do {
|
||||||
a = a*10 + (*((*fmt)++) - '0');
|
a = a*10 + (*((*fmt)++) - '0');
|
||||||
} while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
|
} while (digit(**fmt) && a <= (MAX_SIZE - 9)/10);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1462,14 +1462,14 @@ static int getnum (const char **fmt, int df) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Read an integer numeral and raises an error if it is larger
|
** Read an integer numeral and raises an error if it is larger
|
||||||
** than the maximum size for integers.
|
** than the maximum size of integers.
|
||||||
*/
|
*/
|
||||||
static int getnumlimit (Header *h, const char **fmt, int df) {
|
static int getnumlimit (Header *h, const char **fmt, int df) {
|
||||||
int sz = getnum(fmt, df);
|
size_t sz = getnum(fmt, df);
|
||||||
if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
|
if (l_unlikely((sz - 1u) >= MAXINTSIZE))
|
||||||
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
||||||
sz, MAXINTSIZE);
|
sz, MAXINTSIZE);
|
||||||
return sz;
|
return cast_int(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1486,7 +1486,7 @@ static void initheader (lua_State *L, Header *h) {
|
|||||||
/*
|
/*
|
||||||
** Read and classify next option. 'size' is filled with option's size.
|
** Read and classify next option. 'size' is filled with option's size.
|
||||||
*/
|
*/
|
||||||
static KOption getoption (Header *h, const char **fmt, int *size) {
|
static KOption getoption (Header *h, const char **fmt, size_t *size) {
|
||||||
/* dummy structure to get native alignment requirements */
|
/* dummy structure to get native alignment requirements */
|
||||||
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
||||||
int opt = *((*fmt)++);
|
int opt = *((*fmt)++);
|
||||||
@ -1508,8 +1508,8 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
||||||
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
||||||
case 'c':
|
case 'c':
|
||||||
*size = getnum(fmt, -1);
|
*size = getnum(fmt, cast_sizet(-1));
|
||||||
if (l_unlikely(*size == -1))
|
if (l_unlikely(*size == cast_sizet(-1)))
|
||||||
luaL_error(h->L, "missing size for format option 'c'");
|
luaL_error(h->L, "missing size for format option 'c'");
|
||||||
return Kchar;
|
return Kchar;
|
||||||
case 'z': return Kzstr;
|
case 'z': return Kzstr;
|
||||||
@ -1540,9 +1540,9 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
** despite its size.
|
** despite its size.
|
||||||
*/
|
*/
|
||||||
static KOption getdetails (Header *h, size_t totalsize,
|
static KOption getdetails (Header *h, size_t totalsize,
|
||||||
const char **fmt, int *psize, int *ntoalign) {
|
const char **fmt, size_t *psize, int *ntoalign) {
|
||||||
KOption opt = getoption(h, fmt, psize);
|
KOption opt = getoption(h, fmt, psize);
|
||||||
int align = *psize; /* usually, alignment follows size */
|
size_t align = *psize; /* usually, alignment follows size */
|
||||||
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
||||||
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
||||||
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
||||||
@ -1550,9 +1550,9 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||||||
if (align <= 1 || opt == Kchar) /* need no alignment? */
|
if (align <= 1 || opt == Kchar) /* need no alignment? */
|
||||||
*ntoalign = 0;
|
*ntoalign = 0;
|
||||||
else {
|
else {
|
||||||
if (align > h->maxalign) /* enforce maximum alignment */
|
if (align > cast_sizet(h->maxalign)) /* enforce maximum alignment */
|
||||||
align = h->maxalign;
|
align = h->maxalign;
|
||||||
if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */
|
if (l_unlikely(!ispow2(align))) /* not a power of 2? */
|
||||||
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
||||||
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
||||||
}
|
}
|
||||||
@ -1609,8 +1609,11 @@ static int str_pack (lua_State *L) {
|
|||||||
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
int ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
|
luaL_argcheck(L, size + ntoalign <= MAX_SIZE - totalsize, arg,
|
||||||
|
"result too long");
|
||||||
totalsize += ntoalign + size;
|
totalsize += ntoalign + size;
|
||||||
while (ntoalign-- > 0)
|
while (ntoalign-- > 0)
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
||||||
@ -1660,18 +1663,21 @@ static int str_pack (lua_State *L) {
|
|||||||
case Kchar: { /* fixed-size string */
|
case Kchar: { /* fixed-size string */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, len <= (size_t)size, arg,
|
luaL_argcheck(L, len <= size, arg, "string longer than given size");
|
||||||
"string longer than given size");
|
|
||||||
luaL_addlstring(&b, s, len); /* add string */
|
luaL_addlstring(&b, s, len); /* add string */
|
||||||
while (len++ < (size_t)size) /* pad extra space */
|
if (len < size) { /* does it need padding? */
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE);
|
size_t psize = size - len; /* pad size */
|
||||||
|
char *buff = luaL_prepbuffsize(&b, psize);
|
||||||
|
memset(buff, LUAL_PACKPADBYTE, psize);
|
||||||
|
luaL_addsize(&b, psize);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: { /* strings with length count */
|
case Kstring: { /* strings with length count */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, size >= (int)sizeof(size_t) ||
|
luaL_argcheck(L, size >= sizeof(lua_Unsigned) ||
|
||||||
len < ((size_t)1 << (size * NB)),
|
len < ((lua_Unsigned)1 << (size * NB)),
|
||||||
arg, "string length does not fit in given size");
|
arg, "string length does not fit in given size");
|
||||||
packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
|
packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
|
||||||
luaL_addlstring(&b, s, len);
|
luaL_addlstring(&b, s, len);
|
||||||
@ -1701,19 +1707,20 @@ static int str_pack (lua_State *L) {
|
|||||||
static int str_packsize (lua_State *L) {
|
static int str_packsize (lua_State *L) {
|
||||||
Header h;
|
Header h;
|
||||||
const char *fmt = luaL_checkstring(L, 1); /* format string */
|
const char *fmt = luaL_checkstring(L, 1); /* format string */
|
||||||
size_t totalsize = 0; /* accumulate total size of result */
|
lua_Integer totalsize = 0; /* accumulate total size of result */
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
int ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
||||||
"variable-length format");
|
"variable-length format");
|
||||||
size += ntoalign; /* total space used by option */
|
size += ntoalign; /* total space used by option */
|
||||||
luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
|
luaL_argcheck(L, totalsize <= LUA_MAXINTEGER - cast(lua_Integer, size),
|
||||||
"format result too large");
|
1, "format result too large");
|
||||||
totalsize += size;
|
totalsize += size;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, (lua_Integer)totalsize);
|
lua_pushinteger(L, totalsize);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1762,9 +1769,10 @@ static int str_unpack (lua_State *L) {
|
|||||||
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
int ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2,
|
luaL_argcheck(L, ntoalign + size <= ld - pos, 2,
|
||||||
"data string too short");
|
"data string too short");
|
||||||
pos += ntoalign; /* skip alignment */
|
pos += ntoalign; /* skip alignment */
|
||||||
/* stack space for item + next position */
|
/* stack space for item + next position */
|
||||||
@ -1801,7 +1809,8 @@ static int str_unpack (lua_State *L) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: {
|
case Kstring: {
|
||||||
size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
|
lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos,
|
||||||
|
h.islittle, size, 0);
|
||||||
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
||||||
lua_pushlstring(L, data + pos + size, len);
|
lua_pushlstring(L, data + pos + size, len);
|
||||||
pos += len; /* skip string */
|
pos += len; /* skip string */
|
||||||
|
@ -135,15 +135,15 @@ checkerror("variable%-length format", packsize, "z")
|
|||||||
-- overflow in option size (error will be in digit after limit)
|
-- overflow in option size (error will be in digit after limit)
|
||||||
checkerror("invalid format", packsize, "c1" .. string.rep("0", 40))
|
checkerror("invalid format", packsize, "c1" .. string.rep("0", 40))
|
||||||
|
|
||||||
if packsize("i") == 4 then
|
do
|
||||||
-- result would be 2^31 (2^3 repetitions of 2^28 strings)
|
local maxsize = (packsize("j") <= packsize("T")) and
|
||||||
local s = string.rep("c268435456", 2^3)
|
math.maxinteger or (1 << (packsize("T") * 8))
|
||||||
checkerror("too large", packsize, s)
|
assert (packsize(string.format("c%d", maxsize - 9)) == maxsize - 9)
|
||||||
-- one less is OK
|
checkerror("too large", packsize, string.format("c%dc10", maxsize - 9))
|
||||||
s = string.rep("c268435456", 2^3 - 1) .. "c268435455"
|
checkerror("too long", pack, string.format("xxxxxxxxxx c%d", maxsize - 9))
|
||||||
assert(packsize(s) == 0x7fffffff)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- overflow in packing
|
-- overflow in packing
|
||||||
for i = 1, sizeLI - 1 do
|
for i = 1, sizeLI - 1 do
|
||||||
local umax = (1 << (i * 8)) - 1
|
local umax = (1 << (i * 8)) - 1
|
||||||
@ -229,8 +229,9 @@ do
|
|||||||
assert(pack("c3", "123") == "123")
|
assert(pack("c3", "123") == "123")
|
||||||
assert(pack("c0", "") == "")
|
assert(pack("c0", "") == "")
|
||||||
assert(pack("c8", "123456") == "123456\0\0")
|
assert(pack("c8", "123456") == "123456\0\0")
|
||||||
assert(pack("c88", "") == string.rep("\0", 88))
|
assert(pack("c88 c1", "", "X") == string.rep("\0", 88) .. "X")
|
||||||
assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2))
|
assert(pack("c188 c2", "ab", "X\1") ==
|
||||||
|
"ab" .. string.rep("\0", 188 - 2) .. "X\1")
|
||||||
local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz")
|
local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz")
|
||||||
assert(a == "abcdefghi" and b == "xyz" and c == 14)
|
assert(a == "abcdefghi" and b == "xyz" and c == 14)
|
||||||
checkerror("longer than", pack, "c3", "1234")
|
checkerror("longer than", pack, "c3", "1234")
|
||||||
|
Loading…
Reference in New Issue
Block a user