diff options
Diffstat (limited to 'lstrlib.c')
| -rw-r--r-- | lstrlib.c | 76 |
1 files changed, 52 insertions, 24 deletions
| @@ -60,23 +60,50 @@ static int str_len (lua_State *L) { | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | 62 | ||
| 63 | /* translate a relative string position: negative means back from end */ | 63 | /* |
| 64 | static lua_Integer posrelat (lua_Integer pos, size_t len) { | 64 | ** translate a relative initial string position |
| 65 | if (pos >= 0) return pos; | 65 | ** (negative means back from end): clip result to [1, inf). |
| 66 | else if (0u - (size_t)pos > len) return 0; | 66 | ** The length of any string in Lua must fit in a lua_Integer, |
| 67 | else return (lua_Integer)len + pos + 1; | 67 | ** so there are no overflows in the casts. |
| 68 | ** The inverted comparison avoids a possible overflow | ||
| 69 | ** computing '-pos'. | ||
| 70 | */ | ||
| 71 | static size_t posrelatI (lua_Integer pos, size_t len) { | ||
| 72 | if (pos > 0) | ||
| 73 | return (size_t)pos; | ||
| 74 | else if (pos == 0) | ||
| 75 | return 1; | ||
| 76 | else if (pos < -(lua_Integer)len) /* inverted comparison */ | ||
| 77 | return 1; /* clip to 1 */ | ||
| 78 | else return len + (size_t)pos + 1; | ||
| 79 | } | ||
| 80 | |||
| 81 | |||
| 82 | /* | ||
| 83 | ** Gets an optional ending string position from argument 'arg', | ||
| 84 | ** with default value 'def'. | ||
| 85 | ** Negative means back from end: clip result to [0, len] | ||
| 86 | */ | ||
| 87 | static size_t getendpos (lua_State *L, int arg, lua_Integer def, | ||
| 88 | size_t len) { | ||
| 89 | lua_Integer pos = luaL_optinteger(L, arg, def); | ||
| 90 | if (pos > (lua_Integer)len) | ||
| 91 | return len; | ||
| 92 | else if (pos >= 0) | ||
| 93 | return (size_t)pos; | ||
| 94 | else if (pos < -(lua_Integer)len) | ||
| 95 | return 0; | ||
| 96 | else return len + (size_t)pos + 1; | ||
| 68 | } | 97 | } |
| 69 | 98 | ||
| 70 | 99 | ||
| 71 | static int str_sub (lua_State *L) { | 100 | static int str_sub (lua_State *L) { |
| 72 | size_t l; | 101 | size_t l; |
| 73 | const char *s = luaL_checklstring(L, 1, &l); | 102 | const char *s = luaL_checklstring(L, 1, &l); |
| 74 | lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); | 103 | size_t start = posrelatI(luaL_checkinteger(L, 2), l); |
| 75 | lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); | 104 | size_t end = getendpos(L, 3, -1, l); |
| 76 | if (start < 1) start = 1; | ||
| 77 | if (end > (lua_Integer)l) end = l; | ||
| 78 | if (start <= end) | 105 | if (start <= end) |
| 79 | lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); | 106 | lua_pushlstring(L, s + start - 1, (end - start) + 1); |
| 80 | else lua_pushliteral(L, ""); | 107 | else lua_pushliteral(L, ""); |
| 81 | return 1; | 108 | return 1; |
| 82 | } | 109 | } |
| @@ -149,11 +176,10 @@ static int str_rep (lua_State *L) { | |||
| 149 | static int str_byte (lua_State *L) { | 176 | static int str_byte (lua_State *L) { |
| 150 | size_t l; | 177 | size_t l; |
| 151 | const char *s = luaL_checklstring(L, 1, &l); | 178 | const char *s = luaL_checklstring(L, 1, &l); |
| 152 | lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); | 179 | lua_Integer pi = luaL_optinteger(L, 2, 1); |
| 153 | lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); | 180 | size_t posi = posrelatI(pi, l); |
| 181 | size_t pose = getendpos(L, 3, pi, l); | ||
| 154 | int n, i; | 182 | int n, i; |
| 155 | if (posi < 1) posi = 1; | ||
| 156 | if (pose > (lua_Integer)l) pose = l; | ||
| 157 | if (posi > pose) return 0; /* empty interval; return no values */ | 183 | if (posi > pose) return 0; /* empty interval; return no values */ |
| 158 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ | 184 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ |
| 159 | return luaL_error(L, "string slice too long"); | 185 | return luaL_error(L, "string slice too long"); |
| @@ -171,8 +197,8 @@ static int str_char (lua_State *L) { | |||
| 171 | luaL_Buffer b; | 197 | luaL_Buffer b; |
| 172 | char *p = luaL_buffinitsize(L, &b, n); | 198 | char *p = luaL_buffinitsize(L, &b, n); |
| 173 | for (i=1; i<=n; i++) { | 199 | for (i=1; i<=n; i++) { |
| 174 | lua_Integer c = luaL_checkinteger(L, i); | 200 | lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); |
| 175 | luaL_argcheck(L, uchar(c) == c, i, "value out of range"); | 201 | luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range"); |
| 176 | p[i - 1] = uchar(c); | 202 | p[i - 1] = uchar(c); |
| 177 | } | 203 | } |
| 178 | luaL_pushresultsize(&b, n); | 204 | luaL_pushresultsize(&b, n); |
| @@ -695,16 +721,15 @@ static int str_find_aux (lua_State *L, int find) { | |||
| 695 | size_t ls, lp; | 721 | size_t ls, lp; |
| 696 | const char *s = luaL_checklstring(L, 1, &ls); | 722 | const char *s = luaL_checklstring(L, 1, &ls); |
| 697 | const char *p = luaL_checklstring(L, 2, &lp); | 723 | const char *p = luaL_checklstring(L, 2, &lp); |
| 698 | lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); | 724 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; |
| 699 | if (init < 1) init = 1; | 725 | if (init > ls) { /* start after string's end? */ |
| 700 | else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ | ||
| 701 | lua_pushnil(L); /* cannot find anything */ | 726 | lua_pushnil(L); /* cannot find anything */ |
| 702 | return 1; | 727 | return 1; |
| 703 | } | 728 | } |
| 704 | /* explicit request or no special characters? */ | 729 | /* explicit request or no special characters? */ |
| 705 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { | 730 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { |
| 706 | /* do a plain search */ | 731 | /* do a plain search */ |
| 707 | const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); | 732 | const char *s2 = lmemfind(s + init, ls - init, p, lp); |
| 708 | if (s2) { | 733 | if (s2) { |
| 709 | lua_pushinteger(L, (s2 - s) + 1); | 734 | lua_pushinteger(L, (s2 - s) + 1); |
| 710 | lua_pushinteger(L, (s2 - s) + lp); | 735 | lua_pushinteger(L, (s2 - s) + lp); |
| @@ -713,7 +738,7 @@ static int str_find_aux (lua_State *L, int find) { | |||
| 713 | } | 738 | } |
| 714 | else { | 739 | else { |
| 715 | MatchState ms; | 740 | MatchState ms; |
| 716 | const char *s1 = s + init - 1; | 741 | const char *s1 = s + init; |
| 717 | int anchor = (*p == '^'); | 742 | int anchor = (*p == '^'); |
| 718 | if (anchor) { | 743 | if (anchor) { |
| 719 | p++; lp--; /* skip anchor character */ | 744 | p++; lp--; /* skip anchor character */ |
| @@ -777,11 +802,14 @@ static int gmatch (lua_State *L) { | |||
| 777 | size_t ls, lp; | 802 | size_t ls, lp; |
| 778 | const char *s = luaL_checklstring(L, 1, &ls); | 803 | const char *s = luaL_checklstring(L, 1, &ls); |
| 779 | const char *p = luaL_checklstring(L, 2, &lp); | 804 | const char *p = luaL_checklstring(L, 2, &lp); |
| 805 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; | ||
| 780 | GMatchState *gm; | 806 | GMatchState *gm; |
| 781 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | 807 | lua_settop(L, 2); /* keep strings on closure to avoid being collected */ |
| 782 | gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); | 808 | gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); |
| 809 | if (init > ls) /* start after string's end? */ | ||
| 810 | init = ls + 1; /* avoid overflows in 's + init' */ | ||
| 783 | prepstate(&gm->ms, L, s, ls, p, lp); | 811 | prepstate(&gm->ms, L, s, ls, p, lp); |
| 784 | gm->src = s; gm->p = p; gm->lastmatch = NULL; | 812 | gm->src = s + init; gm->p = p; gm->lastmatch = NULL; |
| 785 | lua_pushcclosure(L, gmatch_aux, 3); | 813 | lua_pushcclosure(L, gmatch_aux, 3); |
| 786 | return 1; | 814 | return 1; |
| 787 | } | 815 | } |
| @@ -1572,7 +1600,7 @@ static int str_unpack (lua_State *L) { | |||
| 1572 | const char *fmt = luaL_checkstring(L, 1); | 1600 | const char *fmt = luaL_checkstring(L, 1); |
| 1573 | size_t ld; | 1601 | size_t ld; |
| 1574 | const char *data = luaL_checklstring(L, 2, &ld); | 1602 | const char *data = luaL_checklstring(L, 2, &ld); |
| 1575 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | 1603 | size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; |
| 1576 | int n = 0; /* number of results */ | 1604 | int n = 0; /* number of results */ |
| 1577 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | 1605 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); |
| 1578 | initheader(L, &h); | 1606 | initheader(L, &h); |
