Skip to content

Commit c07ea89

Browse files
authored
Fix issue with lua_loadfile and require. (#2317)
Fixes an regression introduced in afcbbb2. `require` actually follows a different code path in Lua with a different stack layout expectation than the other code paths. Fix the code to deal with this case, and also clean up some other tidbits around cleaning up stack values. The new approach is simpler to understand and should fix a potential issue that could happen in the error case. Fixes #2314.
1 parent 9ca6f92 commit c07ea89

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

src/host/lua_auxlib.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include "premake.h"
8+
#include <assert.h>
89

910

1011
static int chunk_wrapper(lua_State* L);
@@ -29,11 +30,15 @@ LUALIB_API int luaL_loadfilex (lua_State* L, const char* filename, const char* m
2930
const char* script_dir;
3031
const char* test_name;
3132

32-
/* this function can be called with from 1 to 3 arguments on the stack,
33+
/* this function is usually called with from 1 to 3 arguments on the stack,
3334
* the filename, the mode and an environment table */
3435

35-
int env = (!lua_isnone(L, 3) ? 1 : 0); /* 1 if there is an env or 0 if no 'env' */
36+
/* however, in the case of require, we end up being called from searcher_Lua,
37+
which sets up extra values on the stack */
3638
int bottom = lua_gettop(L);
39+
int is_require = bottom >= 4;
40+
41+
int env = (!is_require && !lua_isnone(L, 3)) ? 1 : 0; /* 1 if there is an env or 0 if no 'env' */
3742
int z = !OKAY;
3843

3944
/* If filename starts with "$/" then we want to load the version that
@@ -50,6 +55,7 @@ LUALIB_API int luaL_loadfilex (lua_State* L, const char* filename, const char* m
5055
if (z != OKAY) {
5156
lua_getglobal(L, "_SCRIPT_DIR");
5257
script_dir = lua_tostring(L, -1);
58+
int script_dir_index = lua_gettop(L);
5359

5460
if (script_dir && script_dir[0] == '$') {
5561
/* Call `path.getabsolute(filename, _SCRIPT_DIR)` to resolve any
@@ -59,16 +65,17 @@ LUALIB_API int luaL_loadfilex (lua_State* L, const char* filename, const char* m
5965
lua_pushvalue(L, -3);
6066
lua_call(L, 2, 1);
6167
test_name = lua_tostring(L, -1);
68+
int test_name_index = lua_gettop(L);
6269

6370
/* if successful, filename and chunk will be on top of stack */
6471
z = premake_load_embedded_script(L, test_name + 2); /* Skip over leading "$/" */
6572

6673
/* remove test_name */
67-
lua_remove(L, -3);
74+
lua_remove(L, test_name_index);
6875
}
6976

7077
/* remove _SCRIPT_DIR */
71-
lua_remove(L, bottom + env);
78+
lua_remove(L, script_dir_index);
7279
}
7380

7481
/* Try to locate the script on the filesystem */
@@ -103,6 +110,9 @@ LUALIB_API int luaL_loadfilex (lua_State* L, const char* filename, const char* m
103110
/* Either way I should have ended up with the file name followed by the
104111
* script chunk on the stack. Turn these into a closure that will call my
105112
* wrapper below when the loaded script needs to be executed. */
113+
114+
assert(lua_gettop(L) == bottom + 2);
115+
106116
if (z == OKAY) {
107117
/* if we are called with an env, then our caller, luaB_loadfile, will
108118
* call load_aux, which sets up our env as the first up value via

tests/folder/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-- empty file used by loadfile_with_require test

tests/test_lua.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ end
3535
test.isequal(10, value)
3636
end
3737

38+
39+
--
40+
-- loadfile via require with init.lua
41+
--
42+
43+
function suite.loadfile_with_require()
44+
os.chdir(_SCRIPT_DIR)
45+
assert(require("folder"))
46+
end
47+

0 commit comments

Comments
 (0)