fix(color): prevent crash, show error if Lua script uses a deleted LVGL object (#6229)
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user