Search code examples
cluamicrocontrollerrtos

Protecting application from erroneous Lua script


I am using Lua in a microcontroller project. My software uses an RTOS, and appart from its other tasks, it also calls a Lua script that the user provides.

The script must have two functions: an init function and a run function. My application calls the init function during initalization, and then calls the run function periodically.

The way I load the script is something very similar to dofile().

The run function is needed to return. This way the underlying thread yields the processor for the other lower priority threads.

So the question is, how can I protect the system from a user providing a "dangerous" script, i.e. a script that never finishes its initial execution, before I have the chance to call the functions I need. See the following:

function init
    --Do some stuff.
end

function run
    --Do some other stuff.
end

while (true) do
    --Do nasty stuff, without ever returning.
end

On the above example the code blocks during the initial loading of the script, and never returns. I never get the chance to call the init and run functions. How can I detect such cases, and how to get protected?

Edit Forgot to mention. I am using Lua 5.2.2.


Solution

  • The solution is to defer execution of user script until you have WD ready.


    Let's assume this is user script:
    user_script.lua

    function init()
       --Do some stuff.
    end
    
    function run()
       --Do some other stuff.
    end
    
    while (true) do
       --Do nasty stuff, without ever returning.
    end
    

    What you are doing now in your host application (as if it was written on Lua)

    dofile("user_script.lua")
    
    init_watchdog()
    
    init()
    
    run()
    run()
    

    What you should do in your host application

    local user_script_as_text = read_content_of_file("user_script.lua")
    assert(loadstring(
    [[
       function init()  -- this is your wrapper around user script
          init = nil
          do
             ]]..user_script_as_text..
    [[  
          end
          init()  -- invoking "init" defined by user
       end
    ]]
    ))()
    
    init_watchdog()
    
    init()  -- invoking your wrapper
    
    run()
    run()
    

    If you need to read values of some configuration variables before turning WD on, then those config variables must be provided as an easy-to-parse string like the following var1=42,var2=on,var3="Hi". These config variables can't be in Lua script because Lua script could loop forever.
    In other words, you need two files from user: user_config_vars.json and user_script.lua