aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-01-31 18:17:31 +0800
committerLi Jin <dragon-fly@qq.com>2023-01-31 18:17:31 +0800
commite3e45fb330e29cc9b203a70b649e61f62697f88d (patch)
tree114c8e38a133e875e3a2467a69922e7771f513a1 /src
parent5fa51d49705e25d284c4adb16edb625d85e0c601 (diff)
downloadyuescript-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.cpp18
-rw-r--r--src/yuescript/yue_compiler.cpp4
-rw-r--r--src/yuescript/yue_parser.cpp5
-rw-r--r--src/yuescript/yuescript.cpp156
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
74const std::string_view version = "0.15.25"sv; 76const std::string_view version = "0.15.26"sv;
75const std::string_view extension = "yue"sv; 77const std::string_view extension = "yue"sv;
76 78
77class YueCompilerImpl { 79class 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
25static const char yuescriptCodes[] = 33static 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
153struct 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
145static int yuetoast(lua_State* L) { 161static 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);