mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-24 02:10:39 +00:00
Merge branch 'limit_layout_depth' into 'master'
Limit maximum Lua UI layout depth to prevent stack overflow Closes #6733 See merge request OpenMW/openmw!1841
This commit is contained in:
commit
b832ba5c83
1 changed files with 148 additions and 139 deletions
|
@ -7,6 +7,8 @@
|
||||||
#include "widget.hpp"
|
#include "widget.hpp"
|
||||||
|
|
||||||
namespace LuaUi
|
namespace LuaUi
|
||||||
|
{
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
namespace LayoutKeys
|
namespace LayoutKeys
|
||||||
{
|
{
|
||||||
|
@ -22,6 +24,8 @@ namespace LuaUi
|
||||||
|
|
||||||
const std::string defaultWidgetType = "LuaWidget";
|
const std::string defaultWidgetType = "LuaWidget";
|
||||||
|
|
||||||
|
constexpr uint64_t maxDepth = 250;
|
||||||
|
|
||||||
std::string widgetType(const sol::table& layout)
|
std::string widgetType(const sol::table& layout)
|
||||||
{
|
{
|
||||||
sol::object typeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::type);
|
sol::object typeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::type);
|
||||||
|
@ -44,12 +48,13 @@ namespace LuaUi
|
||||||
MyGUI::Gui::getInstancePtr()->destroyWidget(ext->widget());
|
MyGUI::Gui::getInstancePtr()->destroyWidget(ext->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetExtension* createWidget(const sol::table& layout);
|
WidgetExtension* createWidget(const sol::table& layout, uint64_t depth);
|
||||||
void updateWidget(WidgetExtension* ext, const sol::table& layout);
|
void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth);
|
||||||
|
|
||||||
std::vector<WidgetExtension*> updateContent(
|
std::vector<WidgetExtension*> updateContent(
|
||||||
const std::vector<WidgetExtension*>& children, const sol::object& contentObj)
|
const std::vector<WidgetExtension*>& children, const sol::object& contentObj, uint64_t depth)
|
||||||
{
|
{
|
||||||
|
++depth;
|
||||||
std::vector<WidgetExtension*> result;
|
std::vector<WidgetExtension*> result;
|
||||||
if (contentObj == sol::nil)
|
if (contentObj == sol::nil)
|
||||||
{
|
{
|
||||||
|
@ -68,28 +73,29 @@ namespace LuaUi
|
||||||
sol::table newLayout = content.at(i);
|
sol::table newLayout = content.at(i);
|
||||||
if (ext->widget()->getTypeName() == widgetType(newLayout))
|
if (ext->widget()->getTypeName() == widgetType(newLayout))
|
||||||
{
|
{
|
||||||
updateWidget(ext, newLayout);
|
updateWidget(ext, newLayout, depth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroyWidget(ext);
|
destroyWidget(ext);
|
||||||
ext = createWidget(newLayout);
|
ext = createWidget(newLayout, depth);
|
||||||
}
|
}
|
||||||
result[i] = ext;
|
result[i] = ext;
|
||||||
}
|
}
|
||||||
for (size_t i = minSize; i < children.size(); i++)
|
for (size_t i = minSize; i < children.size(); i++)
|
||||||
destroyWidget(children[i]);
|
destroyWidget(children[i]);
|
||||||
for (size_t i = minSize; i < content.size(); i++)
|
for (size_t i = minSize; i < content.size(); i++)
|
||||||
result[i] = createWidget(content.at(i));
|
result[i] = createWidget(content.at(i), depth);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTemplate(WidgetExtension* ext, const sol::object& templateLayout)
|
void setTemplate(WidgetExtension* ext, const sol::object& templateLayout, uint64_t depth)
|
||||||
{
|
{
|
||||||
|
++depth;
|
||||||
sol::object props = LuaUtil::getFieldOrNil(templateLayout, LayoutKeys::props);
|
sol::object props = LuaUtil::getFieldOrNil(templateLayout, LayoutKeys::props);
|
||||||
ext->setTemplateProperties(props);
|
ext->setTemplateProperties(props);
|
||||||
sol::object content = LuaUtil::getFieldOrNil(templateLayout, LayoutKeys::content);
|
sol::object content = LuaUtil::getFieldOrNil(templateLayout, LayoutKeys::content);
|
||||||
ext->setTemplateChildren(updateContent(ext->templateChildren(), content));
|
ext->setTemplateChildren(updateContent(ext->templateChildren(), content, depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEventCallbacks(LuaUi::WidgetExtension* ext, const sol::object& eventsObj)
|
void setEventCallbacks(LuaUi::WidgetExtension* ext, const sol::object& eventsObj)
|
||||||
|
@ -112,7 +118,7 @@ namespace LuaUi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetExtension* createWidget(const sol::table& layout)
|
WidgetExtension* createWidget(const sol::table& layout, uint64_t depth)
|
||||||
{
|
{
|
||||||
static auto widgetTypeMap = widgetTypeToName();
|
static auto widgetTypeMap = widgetTypeToName();
|
||||||
std::string type = widgetType(layout);
|
std::string type = widgetType(layout);
|
||||||
|
@ -130,19 +136,21 @@ namespace LuaUi
|
||||||
throw std::runtime_error("Invalid widget!");
|
throw std::runtime_error("Invalid widget!");
|
||||||
ext->initialize(layout.lua_state(), widget);
|
ext->initialize(layout.lua_state(), widget);
|
||||||
|
|
||||||
updateWidget(ext, layout);
|
updateWidget(ext, layout, depth);
|
||||||
return ext;
|
return ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateWidget(WidgetExtension* ext, const sol::table& layout)
|
void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth)
|
||||||
{
|
{
|
||||||
|
if (depth >= maxDepth)
|
||||||
|
throw std::runtime_error("Maximum layout depth exceeded, probably caused by a circular reference");
|
||||||
ext->reset();
|
ext->reset();
|
||||||
ext->setLayout(layout);
|
ext->setLayout(layout);
|
||||||
ext->setExternal(layout.get<sol::object>(LayoutKeys::external));
|
ext->setExternal(layout.get<sol::object>(LayoutKeys::external));
|
||||||
setTemplate(ext, layout.get<sol::object>(LayoutKeys::templateLayout));
|
setTemplate(ext, layout.get<sol::object>(LayoutKeys::templateLayout), depth);
|
||||||
ext->setProperties(layout.get<sol::object>(LayoutKeys::props));
|
ext->setProperties(layout.get<sol::object>(LayoutKeys::props));
|
||||||
setEventCallbacks(ext, layout.get<sol::object>(LayoutKeys::events));
|
setEventCallbacks(ext, layout.get<sol::object>(LayoutKeys::events));
|
||||||
ext->setChildren(updateContent(ext->children(), layout.get<sol::object>(LayoutKeys::content)));
|
ext->setChildren(updateContent(ext->children(), layout.get<sol::object>(LayoutKeys::content), depth));
|
||||||
ext->updateCoord();
|
ext->updateCoord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +167,7 @@ namespace LuaUi
|
||||||
}
|
}
|
||||||
return newLayer;
|
return newLayer;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::map<Element*, std::shared_ptr<Element>> Element::sAllElements;
|
std::map<Element*, std::shared_ptr<Element>> Element::sAllElements;
|
||||||
|
|
||||||
|
@ -184,7 +193,7 @@ namespace LuaUi
|
||||||
assert(!mRoot);
|
assert(!mRoot);
|
||||||
if (!mRoot)
|
if (!mRoot)
|
||||||
{
|
{
|
||||||
mRoot = createWidget(mLayout);
|
mRoot = createWidget(mLayout, 0);
|
||||||
mLayer = setLayer(mRoot, mLayout);
|
mLayer = setLayer(mRoot, mLayout);
|
||||||
updateAttachment();
|
updateAttachment();
|
||||||
}
|
}
|
||||||
|
@ -197,11 +206,11 @@ namespace LuaUi
|
||||||
if (mRoot->widget()->getTypeName() != widgetType(mLayout))
|
if (mRoot->widget()->getTypeName() != widgetType(mLayout))
|
||||||
{
|
{
|
||||||
destroyWidget(mRoot);
|
destroyWidget(mRoot);
|
||||||
mRoot = createWidget(mLayout);
|
mRoot = createWidget(mLayout, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
updateWidget(mRoot, mLayout);
|
updateWidget(mRoot, mLayout, 0);
|
||||||
}
|
}
|
||||||
mLayer = setLayer(mRoot, mLayout);
|
mLayer = setLayer(mRoot, mLayout);
|
||||||
updateAttachment();
|
updateAttachment();
|
||||||
|
|
Loading…
Reference in a new issue