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