In Lua, strings are the only type that come with a default metatable.
The metatable must be shared by all string objects, and it is set to be
the `string` library table each time that library is opened. In
Ardupilot's scripting engine, the last script to load then has access to
the string metatable as the library is opened fresh for each script, as
its `string` library will have been set to the metatable.
Therefore, if two scripts are loaded, A first and B second, and script B
executes e.g. `string.byte = "haha"`, then `string.byte()` and
`s:byte()` for script B are broken. Because the metatable is shared,
this also breaks `s:byte()` for script A, which violates the integrity
of the sandbox.
Fix the issue by disabling the metatable setup functionality when the
string libary is opened, then manually opening an additional copy of the
library (which won't be given to any script) and setting it as the
string metatable during intialization.
This will break any script that modifies the string metatable for
constructive purposes, but such a script could have been broken if it
weren't the only script running anyway.
Referencing the original function to run is of questionable value and
the only user uses it to grab the script environent from the upvalues.
Instead, use a reference to the script environment table directly.
the register save must happen before the setjmp() call, which means
outside of the LUAI_TRY() macro. We also should be saving all 32
floating point registers
this fixes an issue where a lua library function triggers an exception
after it does a math operation which changes the floating point
registers on M7 MCUs (such as STM32H7). An example is math.random()
which calls math_random(), which pre-calculates a double value before
checking if the arguments to the call are valid. When it then checks
and finds invalid values the exception longjmp does not restore the
floating point registers.