Skip to content

Commit

Permalink
AP_Scripting: stash and restore FPU register context in LUAI_TRY
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bugobliterator authored and tridge committed Jul 5, 2023
1 parent 0ee778c commit e48f2a6
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 2 deletions.
10 changes: 10 additions & 0 deletions libraries/AP_Scripting/AP_Scripting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,15 @@ void AP_Scripting::repl_stop(void) {
// can't do any more cleanup here, closing the open FD's is the REPL's responsibility
}

/*
avoid optimisation of the thread function. This avoids nasty traps
where setjmp/longjmp does not properly handle save/restore of
floating point registers on exceptions. This is an extra protection
over the top of the fix in luaD_rawrunprotected() for the same issue
*/
#pragma GCC push_options
#pragma GCC optimize ("O0")

void AP_Scripting::thread(void) {
while (true) {
// reset flags
Expand Down Expand Up @@ -289,6 +298,7 @@ void AP_Scripting::thread(void) {
}
}
}
#pragma GCC pop_options

void AP_Scripting::handle_mission_command(const AP_Mission::Mission_Command& cmd_in)
{
Expand Down
12 changes: 10 additions & 2 deletions libraries/AP_Scripting/lua/src/ldo.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,29 @@ l_noret luaD_throw (lua_State *L, int errcode) {
}
}


// remove optimization
#pragma GCC push_options
#pragma GCC optimize ("O0")
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
unsigned short oldnCcalls = L->nCcalls;
struct lua_longjmp lj;
lj.status = LUA_OK;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
#ifdef ARM_MATH_CM7
__asm__("vpush {s16-s31}");
#endif
(*f)(L, ud);
);
#ifdef ARM_MATH_CM7
__asm__("vpop {s16-s31}");
#endif
L->errorJmp = lj.previous; /* restore old error handler */
L->nCcalls = oldnCcalls;
return lj.status;
}

#pragma GCC pop_options
/* }====================================================== */


Expand Down

0 comments on commit e48f2a6

Please sign in to comment.