Hide shell functions from _G using upvalues on the main chunk

Store __command, __interactive, __getenv, __setenv as upvalues
populated by lua_load() from the registry, keeping them invisible
to user code while accessible to the parser's codegen.
This commit is contained in:
Cormac Shannon
2026-03-12 22:46:56 +00:00
parent 34bfabccbd
commit f88b17959f
8 changed files with 134 additions and 77 deletions

View File

@@ -3,13 +3,10 @@
print "testing shell builtins"
-- === __builtins table ===
-- === __builtins is NOT in _G (internal, stored in registry) ===
do
assert(type(__builtins) == "table")
assert(type(__builtins.cd) == "function")
assert(type(__builtins.exec) == "function")
assert(type(__builtins.umask) == "function")
assert(__builtins == nil, "__builtins should not be in _G")
end
@@ -117,9 +114,9 @@ end
-- === exec ===
-- exec with no command returns error
-- exec with no command returns error (tested via backtick)
do
local r = __builtins.exec("exec")
local r = `exec`
assert(r.code == 1)
assert(r.stderr:find("command required"),
"expected 'command required', got: " .. r.stderr)
@@ -127,7 +124,7 @@ end
-- exec nonexistent command returns error
do
local r = __builtins.exec("exec", "nonexistent_cmd_xyz_999")
local r = `exec nonexistent_cmd_xyz_999`
assert(r.code == 1)
assert(r.stderr:find("exec:"),
"expected exec error, got: " .. r.stderr)
@@ -140,21 +137,4 @@ do
end
-- === builtins are overridable ===
do
local old_cd = __builtins.cd
local called = false
__builtins.cd = function(...)
called = true
return old_cd(...)
end
local before = `pwd`.stdout:gsub("\n$", "")
`cd /tmp`
assert(called, "custom cd was not called")
__builtins.cd = old_cd
`cd ${before}`
end
print "OK"