fix(color): prevent crash, show error if Lua script uses a deleted LVGL object (#6229)

This commit is contained in:
philmoz
2025-05-12 09:10:37 +10:00
committed by GitHub
parent 04a7e340d7
commit d22628d1d6
5 changed files with 92 additions and 66 deletions
+9 -9
View File
@@ -47,7 +47,7 @@ static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> cre
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
@@ -86,7 +86,7 @@ static int luaDestroyLvglWidget(lua_State *L)
static int luaLvglSet(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->update(L);
}
@@ -97,7 +97,7 @@ static int luaLvglClear(lua_State *L)
{
if (luaScriptManager) {
if (lua_gettop(L) == 1) {
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->clear();
}
@@ -111,7 +111,7 @@ static int luaLvglClear(lua_State *L)
static int luaLvglShow(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->show();
}
@@ -120,7 +120,7 @@ static int luaLvglShow(lua_State *L)
static int luaLvglHide(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->hide();
}
@@ -129,7 +129,7 @@ static int luaLvglHide(lua_State *L)
static int luaLvglEnable(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->enable();
}
@@ -138,7 +138,7 @@ static int luaLvglEnable(lua_State *L)
static int luaLvglDisable(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->disable();
}
@@ -147,7 +147,7 @@ static int luaLvglDisable(lua_State *L)
static int luaLvglClose(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
p->close();
}
@@ -269,7 +269,7 @@ static int luaLvglBuild(lua_State *L)
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
+68 -49
View File
@@ -112,15 +112,19 @@ static bool pcallFuncWithString(lua_State *L, int funcRef, int nretval, const ch
//-----------------------------------------------------------------------------
LvglWidgetObjectBase *LvglWidgetObjectBase::checkLvgl(lua_State *L, int index)
LvglWidgetObjectBase *LvglWidgetObjectBase::checkLvgl(lua_State *L, int index, bool required)
{
LvglWidgetObjectBase **p;
p = (LvglWidgetObjectBase **)luaL_testudata(L, index, LVGL_METATABLE);
if (p) return *p;
if (p && *p) return *p;
p = (LvglWidgetObjectBase **)luaL_testudata(L, index, LVGL_SIMPLEMETATABLE);
if (p) return *p;
if (p && *p) return *p;
if (required) {
luaL_error(L, "Invalid lvgl object (it has been probably been cleared).");
}
return nullptr;
}
@@ -170,16 +174,18 @@ void LvglWidgetObjectBase::getParams(lua_State *L, int index)
void LvglWidgetObjectBase::pcallSimpleFunc(lua_State *L, int funcRef)
{
if (funcRef != LUA_REFNIL) {
auto save = luaScriptManager;
luaScriptManager = lvglManager;
PROTECT_LUA()
{
auto save = luaScriptManager;
luaScriptManager = lvglManager;
if (!pcallFunc(L, funcRef, 0)) {
lvglManager->luaShowError();
}
luaScriptManager = save;
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
luaScriptManager = save;
}
}
@@ -191,18 +197,24 @@ bool LvglWidgetObjectBase::pcallUpdateBool(lua_State *L, int getFuncRef,
auto save = luaScriptManager;
luaScriptManager = lvglManager;
int t = lua_gettop(L);
if (pcallFunc(L, getFuncRef, 1)) {
bool val = false;
if (lua_isboolean(L, -1))
val = lua_toboolean(L, -1);
else
val = luaL_optinteger(L, -1, 0) != 0;
update(val);
lua_settop(L, t);
PROTECT_LUA()
{
if (pcallFunc(L, getFuncRef, 1)) {
bool val = false;
if (lua_isboolean(L, -1))
val = lua_toboolean(L, -1);
else
val = luaL_optinteger(L, -1, 0) != 0;
update(val);
} else {
res = false;
}
} else {
res = false;
lvglManager->luaShowError();
}
lvglManager = save;
UNPROTECT_LUA();
lua_settop(L, t);
luaScriptManager = save;
}
return res;
}
@@ -215,14 +227,20 @@ bool LvglWidgetObjectBase::pcallUpdate1Int(lua_State *L, int getFuncRef,
auto save = luaScriptManager;
luaScriptManager = lvglManager;
int t = lua_gettop(L);
if (pcallFunc(L, getFuncRef, 1)) {
int val = luaL_checkunsigned(L, -1);
update(val);
lua_settop(L, t);
PROTECT_LUA()
{
if (pcallFunc(L, getFuncRef, 1)) {
int val = luaL_checkunsigned(L, -1);
update(val);
} else {
res = false;
}
} else {
res = false;
lvglManager->luaShowError();
}
lvglManager = save;
UNPROTECT_LUA();
lua_settop(L, t);
luaScriptManager = save;
}
return res;
}
@@ -235,15 +253,21 @@ bool LvglWidgetObjectBase::pcallUpdate2Int(lua_State *L, int getFuncRef,
auto save = luaScriptManager;
luaScriptManager = lvglManager;
int t = lua_gettop(L);
if (pcallFunc(L, getFuncRef, 2)) {
int v1 = luaL_checkunsigned(L, -2);
int v2 = luaL_checkunsigned(L, -1);
update(v1, v2);
lua_settop(L, t);
PROTECT_LUA()
{
if (pcallFunc(L, getFuncRef, 2)) {
int v1 = luaL_checkunsigned(L, -2);
int v2 = luaL_checkunsigned(L, -1);
update(v1, v2);
} else {
res = false;
}
} else {
res = false;
lvglManager->luaShowError();
}
lvglManager = save;
UNPROTECT_LUA();
lua_settop(L, t);
luaScriptManager = save;
}
return res;
}
@@ -265,14 +289,12 @@ int LvglWidgetObjectBase::pcallGetIntVal(lua_State *L, int getFuncRef)
} else {
lvglManager->luaShowError();
}
}
else
{
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
lua_settop(L, t);
lvglManager = save;
luaScriptManager = save;
}
return val;
}
@@ -294,14 +316,12 @@ int LvglWidgetObjectBase::pcallGetOptIntVal(lua_State *L, int getFuncRef, int de
} else {
lvglManager->luaShowError();
}
}
else
{
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
lua_settop(L, t);
lvglManager = save;
luaScriptManager = save;
}
return val;
}
@@ -317,14 +337,12 @@ void LvglWidgetObjectBase::pcallSetIntVal(lua_State *L, int setFuncRef, int val)
if (!pcallFuncWithInt(L, setFuncRef, 0, val)) {
lvglManager->luaShowError();
}
}
else
{
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
lua_settop(L, t);
lvglManager = save;
luaScriptManager = save;
}
}
@@ -342,14 +360,12 @@ const char* LvglWidgetObjectBase::pcallGetStringVal(lua_State *L, int getFuncRef
} else {
lvglManager->luaShowError();
}
}
else
{
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
lua_settop(L, t);
lvglManager = save;
luaScriptManager = save;
}
return val;
}
@@ -365,14 +381,12 @@ void LvglWidgetObjectBase::pcallSetStringVal(lua_State *L, int setFuncRef, const
if (!pcallFuncWithString(L, setFuncRef, 0, val)) {
lvglManager->luaShowError();
}
}
else
{
} else {
lvglManager->luaShowError();
}
UNPROTECT_LUA();
lua_settop(L, t);
lvglManager = save;
luaScriptManager = save;
}
}
@@ -471,6 +485,11 @@ void LvglWidgetObjectBase::clearChildRefs(lua_State *L)
void LvglWidgetObjectBase::clearRefs(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, luaRef);
auto p = (LvglWidgetObjectBase **)luaL_testudata(L, -1, metatable);
if (p) *p = nullptr;
lua_pop(L, 1);
clearRef(L, luaRef);
clearRef(L, color.function);
clearRef(L, opacity.function);
+1 -1
View File
@@ -86,7 +86,7 @@ class LvglWidgetObjectBase
virtual Window *getWindow() const = 0;
static LvglWidgetObjectBase *checkLvgl(lua_State *L, int index);
static LvglWidgetObjectBase *checkLvgl(lua_State *L, int index, bool required = false);
void clear();
+13 -6
View File
@@ -319,12 +319,12 @@ void LuaWidget::checkEvents()
refresh(nullptr);
if (!errorMessage) {
if (!callRefs(lsWidgets)) {
setErrorMessage("callRefs()");
setErrorMessage("function");
}
}
refreshInstructionsPercent = instructionsPercent;
} else {
// TODO: error handling
setErrorMessage("function");
}
luaScriptManager = save;
UNPROTECT_LUA();
@@ -375,6 +375,7 @@ void LuaWidget::update()
lua_setfield(lsWidgets, -2, option->name);
}
auto save = luaScriptManager;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 2, 0, 0) != 0)
@@ -388,17 +389,17 @@ void LuaWidget::update()
if (a.x2 >= 0 && a.x1 < LCD_W) {
PROTECT_LUA() {
if (!callRefs(lsWidgets)) {
setErrorMessage("callRefs()");
setErrorMessage("function");
}
} else {
// TODO: error handling
setErrorMessage("function");
}
UNPROTECT_LUA();
}
}
}
luaScriptManager = nullptr;
luaScriptManager = save;
}
// Update table on top of Lua stack - set entry with name 'idx' to value 'val'
@@ -459,12 +460,13 @@ void LuaWidget::onFullscreen(bool enable)
void LuaWidget::setErrorMessage(const char* funcName)
{
constexpr int err_len = 255;
const char* lua_err = lua_tostring(lsWidgets, -1);
TRACE("Error in widget %s %s function: %s", factory->getName(), funcName,
lua_err);
TRACE("Widget disabled");
size_t err_len = snprintf(NULL, 0, "ERROR in %s: %s", funcName, lua_err);
errorMessage = (char*)malloc(err_len + 1);
if (errorMessage) {
@@ -473,6 +475,11 @@ void LuaWidget::setErrorMessage(const char* funcName)
}
}
void LuaWidget::luaShowError()
{
setErrorMessage("widget");
}
const char* LuaWidget::getErrorMessage() const { return errorMessage; }
void LuaWidget::refresh(BitmapBuffer* dc)
+1 -1
View File
@@ -138,7 +138,7 @@ class LuaWidget : public Widget, public LuaScriptManager
// Should rotary encoder events be enabled when full screen
bool enableFullScreenRE() const override { return !useLvglLayout(); }
void luaShowError() override {}
void luaShowError() override;
void pushOptionsTable();