diff options
author | Li Jin <dragon-fly@qq.com> | 2023-01-31 18:17:31 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2023-01-31 18:17:31 +0800 |
commit | e3e45fb330e29cc9b203a70b649e61f62697f88d (patch) | |
tree | 114c8e38a133e875e3a2467a69922e7771f513a1 /src | |
parent | 5fa51d49705e25d284c4adb16edb625d85e0c601 (diff) | |
download | yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.tar.gz yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.tar.bz2 yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.zip |
fix stack overflow issue in yue.to_ast().
Diffstat (limited to 'src')
-rw-r--r-- | src/yue.cpp | 18 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 4 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 5 | ||||
-rw-r--r-- | src/yuescript/yuescript.cpp | 156 |
4 files changed, 124 insertions, 59 deletions
diff --git a/src/yue.cpp b/src/yue.cpp index 5679e58..7adde70 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
@@ -270,15 +270,6 @@ int main(int narg, const char** args) { | |||
270 | ; | 270 | ; |
271 | #ifndef YUE_COMPILER_ONLY | 271 | #ifndef YUE_COMPILER_ONLY |
272 | if (narg == 1) { | 272 | if (narg == 1) { |
273 | lua_State* L = luaL_newstate(); | ||
274 | openlibs(L); | ||
275 | DEFER(lua_close(L)); | ||
276 | pushYue(L, "insert_loader"sv); | ||
277 | if (lua_pcall(L, 0, 0, 0) != 0) { | ||
278 | std::cout << lua_tostring(L, -1) << '\n'; | ||
279 | return 1; | ||
280 | } | ||
281 | int count = 0; | ||
282 | linenoise::SetMultiLine(false); | 273 | linenoise::SetMultiLine(false); |
283 | linenoise::SetCompletionCallback([](const char* editBuffer, std::vector<std::string>& completions) { | 274 | linenoise::SetCompletionCallback([](const char* editBuffer, std::vector<std::string>& completions) { |
284 | std::string buf = editBuffer; | 275 | std::string buf = editBuffer; |
@@ -326,6 +317,15 @@ int main(int narg, const char** args) { | |||
326 | break; | 317 | break; |
327 | } | 318 | } |
328 | }); | 319 | }); |
320 | lua_State* L = luaL_newstate(); | ||
321 | openlibs(L); | ||
322 | DEFER(lua_close(L)); | ||
323 | pushYue(L, "insert_loader"sv); | ||
324 | if (lua_pcall(L, 0, 0, 0) != 0) { | ||
325 | std::cout << lua_tostring(L, -1) << '\n'; | ||
326 | return 1; | ||
327 | } | ||
328 | int count = 0; | ||
329 | std::cout << "Yuescript "sv << yue::version << '\n'; | 329 | std::cout << "Yuescript "sv << yue::version << '\n'; |
330 | while (true) { | 330 | while (true) { |
331 | count++; | 331 | count++; |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 83933d1..0cf643f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -32,7 +32,9 @@ extern "C" { | |||
32 | 32 | ||
33 | #if LUA_VERSION_NUM > 501 | 33 | #if LUA_VERSION_NUM > 501 |
34 | #ifndef LUA_COMPAT_5_1 | 34 | #ifndef LUA_COMPAT_5_1 |
35 | #ifndef lua_objlen | ||
35 | #define lua_objlen lua_rawlen | 36 | #define lua_objlen lua_rawlen |
37 | #endif // lua_objlen | ||
36 | #endif // LUA_COMPAT_5_1 | 38 | #endif // LUA_COMPAT_5_1 |
37 | #endif // LUA_VERSION_NUM | 39 | #endif // LUA_VERSION_NUM |
38 | 40 | ||
@@ -71,7 +73,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
71 | "close"s // Lua 5.4 | 73 | "close"s // Lua 5.4 |
72 | }; | 74 | }; |
73 | 75 | ||
74 | const std::string_view version = "0.15.25"sv; | 76 | const std::string_view version = "0.15.26"sv; |
75 | const std::string_view extension = "yue"sv; | 77 | const std::string_view extension = "yue"sv; |
76 | 78 | ||
77 | class YueCompilerImpl { | 79 | class YueCompilerImpl { |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 5bb4817..e70c4a0 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -869,9 +869,10 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
869 | codes = codes.substr(3); | 869 | codes = codes.substr(3); |
870 | } | 870 | } |
871 | try { | 871 | try { |
872 | res.codes = std::make_unique<input>(); | ||
873 | if (!codes.empty()) { | 872 | if (!codes.empty()) { |
874 | *(res.codes) = _converter.from_bytes(&codes.front(), &codes.back() + 1); | 873 | res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); |
874 | } else { | ||
875 | res.codes = std::make_unique<input>(); | ||
875 | } | 876 | } |
876 | } catch (const std::range_error&) { | 877 | } catch (const std::range_error&) { |
877 | res.error = "invalid text encoding"sv; | 878 | res.error = "invalid text encoding"sv; |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index b01c3eb..20fa258 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
@@ -22,6 +22,14 @@ extern "C" { | |||
22 | #include "lauxlib.h" | 22 | #include "lauxlib.h" |
23 | #include "lua.h" | 23 | #include "lua.h" |
24 | 24 | ||
25 | #if LUA_VERSION_NUM > 501 | ||
26 | #ifndef LUA_COMPAT_5_1 | ||
27 | #ifndef lua_objlen | ||
28 | #define lua_objlen lua_rawlen | ||
29 | #endif // lua_objlen | ||
30 | #endif // LUA_COMPAT_5_1 | ||
31 | #endif // LUA_VERSION_NUM | ||
32 | |||
25 | static const char yuescriptCodes[] = | 33 | static const char yuescriptCodes[] = |
26 | #include "yuescript/yuescript.h" | 34 | #include "yuescript/yuescript.h" |
27 | ; | 35 | ; |
@@ -142,6 +150,14 @@ static int yuetolua(lua_State* L) { | |||
142 | return 3; | 150 | return 3; |
143 | } | 151 | } |
144 | 152 | ||
153 | struct yue_stack { | ||
154 | int continuation; | ||
155 | yue::ast_node* node; | ||
156 | int i; | ||
157 | std::unique_ptr<std::vector<yue::ast_node*>> children; | ||
158 | bool hasSep; | ||
159 | }; | ||
160 | |||
145 | static int yuetoast(lua_State* L) { | 161 | static int yuetoast(lua_State* L) { |
146 | size_t size = 0; | 162 | size_t size = 0; |
147 | const char* input = luaL_checklstring(L, 1, &size); | 163 | const char* input = luaL_checklstring(L, 1, &size); |
@@ -154,6 +170,8 @@ static int yuetoast(lua_State* L) { | |||
154 | auto info = parser.parse<yue::File_t>({input, size}); | 170 | auto info = parser.parse<yue::File_t>({input, size}); |
155 | if (info.node) { | 171 | if (info.node) { |
156 | lua_createtable(L, 0, 0); | 172 | lua_createtable(L, 0, 0); |
173 | int tableIndex = lua_gettop(L); | ||
174 | lua_createtable(L, 0, 0); | ||
157 | int cacheIndex = lua_gettop(L); | 175 | int cacheIndex = lua_gettop(L); |
158 | auto getName = [&](yue::ast_node* node) { | 176 | auto getName = [&](yue::ast_node* node) { |
159 | int id = node->getId(); | 177 | int id = node->getId(); |
@@ -166,64 +184,108 @@ static int yuetoast(lua_State* L) { | |||
166 | lua_rawseti(L, cacheIndex, id); | 184 | lua_rawseti(L, cacheIndex, id); |
167 | } | 185 | } |
168 | }; | 186 | }; |
169 | std::function<void(yue::ast_node*)> visit; | 187 | std::stack<yue_stack> stack; |
170 | visit = [&](yue::ast_node* node) { | 188 | auto do_call = [&](yue::ast_node* node) { |
171 | int count = 0; | 189 | stack.push({0, node, 0, nullptr, false}); |
172 | bool hasSep = false; | 190 | }; |
173 | node->visitChild([&](yue::ast_node* child) { | 191 | auto do_return = [&]() { |
174 | if (yue::ast_is<yue::Seperator_t>(child)) { | 192 | stack.pop(); |
175 | hasSep = true; | 193 | }; |
176 | return false; | 194 | do_call(info.node); |
177 | } | 195 | while (!stack.empty()) { |
178 | count++; | 196 | auto& current = stack.top(); |
179 | visit(child); | 197 | int continuation = current.continuation; |
180 | return false; | 198 | auto node = current.node; |
181 | }); | 199 | switch (continuation) { |
182 | switch (count) { | ||
183 | case 0: { | 200 | case 0: { |
184 | lua_createtable(L, 4, 0); | 201 | if (!current.children) { |
185 | getName(node); | 202 | node->visitChild([&](yue::ast_node* child) { |
186 | lua_rawseti(L, -2, 1); | 203 | if (yue::ast_is<yue::Seperator_t>(child)) { |
187 | lua_pushinteger(L, node->m_begin.m_line); | 204 | current.hasSep = true; |
188 | lua_rawseti(L, -2, 2); | 205 | return false; |
189 | lua_pushinteger(L, node->m_begin.m_col); | 206 | } |
190 | lua_rawseti(L, -2, 3); | 207 | if (!current.children) { |
191 | auto str = parser.toString(node); | 208 | current.children = std::make_unique<std::vector<yue::ast_node*>>(); |
192 | yue::Utils::trim(str); | 209 | } |
193 | lua_pushlstring(L, str.c_str(), str.length()); | 210 | current.children->push_back(child); |
194 | lua_rawseti(L, -2, 4); | 211 | return false; |
212 | }); | ||
213 | } | ||
214 | current.i = 0; | ||
215 | current.continuation = 1; | ||
195 | break; | 216 | break; |
196 | } | 217 | } |
197 | case 1: { | 218 | case 1: { |
198 | if (flattenLevel > 1 || (flattenLevel == 1 && !hasSep)) { | 219 | if (current.children && current.i < static_cast<int>(current.children->size())) { |
199 | getName(node); | 220 | do_call(current.children->at(current.i)); |
200 | lua_rawseti(L, -2, 1); | 221 | current.continuation = 2; |
201 | lua_pushinteger(L, node->m_begin.m_line); | ||
202 | lua_rawseti(L, -2, 2); | ||
203 | lua_pushinteger(L, node->m_begin.m_col); | ||
204 | lua_rawseti(L, -2, 3); | ||
205 | break; | 222 | break; |
206 | } | 223 | } |
224 | current.continuation = 3; | ||
225 | break; | ||
226 | } | ||
227 | case 2: { | ||
228 | current.i++; | ||
229 | current.continuation = 1; | ||
230 | break; | ||
207 | } | 231 | } |
208 | default: { | 232 | case 3: { |
209 | lua_createtable(L, count + 3, 0); | 233 | int count = current.children ? static_cast<int>(current.children->size()) : 0; |
210 | getName(node); | 234 | switch (count) { |
211 | lua_rawseti(L, -2, 1); | 235 | case 0: { |
212 | lua_pushinteger(L, node->m_begin.m_line); | 236 | lua_createtable(L, 4, 0); |
213 | lua_rawseti(L, -2, 2); | 237 | getName(node); |
214 | lua_pushinteger(L, node->m_begin.m_col); | 238 | lua_rawseti(L, -2, 1); |
215 | lua_rawseti(L, -2, 3); | 239 | lua_pushinteger(L, node->m_begin.m_line); |
216 | for (int i = count, j = 4; i >= 1; i--, j++) { | 240 | lua_rawseti(L, -2, 2); |
217 | lua_pushvalue(L, -1 - i); | 241 | lua_pushinteger(L, node->m_begin.m_col); |
218 | lua_rawseti(L, -2, j); | 242 | lua_rawseti(L, -2, 3); |
243 | auto str = parser.toString(node); | ||
244 | yue::Utils::trim(str); | ||
245 | lua_pushlstring(L, str.c_str(), str.length()); | ||
246 | lua_rawseti(L, -2, 4); | ||
247 | lua_rawseti(L, tableIndex, lua_objlen(L, tableIndex) + 1); | ||
248 | break; | ||
249 | } | ||
250 | case 1: { | ||
251 | if (flattenLevel > 1 || (flattenLevel == 1 && !current.hasSep)) { | ||
252 | lua_rawgeti(L, tableIndex, 1); | ||
253 | getName(node); | ||
254 | lua_rawseti(L, -2, 1); | ||
255 | lua_pushinteger(L, node->m_begin.m_line); | ||
256 | lua_rawseti(L, -2, 2); | ||
257 | lua_pushinteger(L, node->m_begin.m_col); | ||
258 | lua_rawseti(L, -2, 3); | ||
259 | lua_pop(L, 1); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | default: { | ||
264 | auto len = lua_objlen(L, tableIndex); | ||
265 | lua_createtable(L, count + 3, 0); | ||
266 | getName(node); | ||
267 | lua_rawseti(L, -2, 1); | ||
268 | lua_pushinteger(L, node->m_begin.m_line); | ||
269 | lua_rawseti(L, -2, 2); | ||
270 | lua_pushinteger(L, node->m_begin.m_col); | ||
271 | lua_rawseti(L, -2, 3); | ||
272 | for (int i = count, j = 4; i >= 1; i--, j++) { | ||
273 | lua_rawgeti(L, tableIndex, len); | ||
274 | lua_rawseti(L, -2, j); | ||
275 | lua_pushnil(L); | ||
276 | lua_rawseti(L, tableIndex, len); | ||
277 | len--; | ||
278 | } | ||
279 | lua_rawseti(L, tableIndex, lua_objlen(L, tableIndex) + 1); | ||
280 | break; | ||
281 | } | ||
219 | } | 282 | } |
220 | lua_insert(L, -1 - count); | 283 | do_return(); |
221 | lua_pop(L, count); | ||
222 | break; | 284 | break; |
223 | } | 285 | } |
224 | } | 286 | } |
225 | }; | 287 | } |
226 | visit(info.node); | 288 | lua_rawgeti(L, tableIndex, 1); |
227 | return 1; | 289 | return 1; |
228 | } else { | 290 | } else { |
229 | lua_pushnil(L); | 291 | lua_pushnil(L); |