Skip to content

Commit

Permalink
AP_Scripting: demystify require test
Browse files Browse the repository at this point in the history
Explain more thoroughly how the test works using lessons learned from
studying the compiled bytecode and function data.

Tested that it still fails after reverting the patches in PR #27652.
  • Loading branch information
tpwrules authored and peterbarker committed Jan 4, 2025
1 parent 2d98657 commit 01964d8
Showing 1 changed file with 19 additions and 8 deletions.
27 changes: 19 additions & 8 deletions libraries/AP_Scripting/tests/scripting_require_test_2.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
-- main require tests are in scripting_test.lua

-- DO NOT EDIT!!!! it's very easy to make this accidentally pass even when the
-- original problem is still present!! we do some very careful work to check
-- that require works even when the function's first upvalue is not the script
-- environment.
-- CAREFUL WHEN EDITING!!!! we do some very careful work to check that require
-- works even when the update function's first upvalue is not the script
-- environment _ENV. this fact can be verified by looking at its upvalues using
-- e.g. https://www.luac.nl/

local loop_time = 500 -- number of ms between runs

-- need to shadow gcs to make the upvalues right
-- alias global gcs as a local so update uses it as an upvalue
local gcs = gcs -- luacheck: ignore

local passes = 0 -- run both before and after scheduling

-- this time running require, the main function that implicitly wraps the script
-- is the update function and its only upvalue is by definition _ENV; require
-- is expected to work here
local require_global = require("test/nested")

local function update()
-- need to send before requiring to make the upvalues right
-- reference gcs first so it's update's first upvalue
gcs:send_text(6, "testing")
local require_local = require("test/nested") -- should not crash
-- require is a global, so referencing it implicitly adds _ENV as update's
-- second upvalue, thus exercising the problem during the second and third
-- passes when this is in fact the update function
local require_local = require("test/nested") -- should not cause an error

-- validate we got the same object (object contents validated in main test)
-- no matter when require is called and what set of upvalues are used
if require_local == require_global then
passes = passes + 1
else
Expand All @@ -29,7 +36,11 @@ local function update()
gcs:send_text(3, "Require test 2 passed")
end

-- now schedule this function as the update function, not the main function
return update, loop_time
end

return update() -- run immediately before starting to reschedule
-- run immediately before starting to reschedule. the update function doesn't
-- change until the return, so the first time it's run the bug shouldn't trigger
-- as the main function's upvalues are still the ones checked
return update()

0 comments on commit 01964d8

Please sign in to comment.