I made an ingame code executor, similiar to an Online Judge, that runs the player’s code, then check if the answer returned from the code is correct.
Problem is if the player’s code never yields, it halts the code executor, along with other server scripts too.
For example, if the player submits this:
x = 0
while true do
x += 1
end
and I have another server script doing its own thing:
while true do
task.wait(1)
print("look! im running! look at me go")
end
the script will never print when the player’s code is running, until the code is stopped by the script timeout.
My code executor (simplified) looks like this:
local RunService = game:GetService("RunService")
local ENV = {
ipairs = ipairs,
math = math,
string = string,
pairs = pairs,
table = table,
tonumber = tonumber,
tostring = tostring,
}
local CodeExecutor = {}
function CodeExecutor.TestCode(code: string, input: any, answer: any): (string, string)
local fake, err = loadstring(code)
local newENV = table.clone(ENV)
newENV.input = input
local real, err = setfenv(fake, table.clone(newENV))
--/\/\/\/\/\/\/\
local success, judgement, result
local runningUserCodeThing: thread
runningUserCodeThing = task.spawn(function()
success, result = pcall(real)
if not success then
judgement = "RE"
end
end)
local timePassed = 0
while judgement == nil do
timePassed += RunService.Heartbeat:Wait()
if result ~= nil then
--yay it worked
elseif timePassed >= 1 then
task.cancel(runningUserCodeThing)
judgement = "TLE"
end
end
return judgement, if judgement == "RE" or judgement == "PE" then result else nil
end
return CodeExecutor
I have tried to wrap the user code in a task.spawn, then task.cancel it when it has ran for too long, but RunService.Heartbeat:Wait() never fires during running the user code.
How would I fix this?