From 9eff6f390d37e4ea1d532c2021a00a3be4a379f3 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 27 Oct 2016 23:47:36 +0200 Subject: LuaJson: Report serialization errors instead of crashing. --- src/Bindings/LuaJson.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) (limited to 'src/Bindings') diff --git a/src/Bindings/LuaJson.cpp b/src/Bindings/LuaJson.cpp index 7a0ddb961..5b562eab5 100644 --- a/src/Bindings/LuaJson.cpp +++ b/src/Bindings/LuaJson.cpp @@ -22,6 +22,53 @@ static Json::Value JsonSerializeValue(cLuaState & a_LuaState); +/** Exception thrown when the input cannot be serialized. +Keeps track of the error message and the problematic value's path in the table. +*/ +class CannotSerializeException: + public std::runtime_error +{ + typedef std::runtime_error Super; +public: + /** Constructs a new instance of the exception based on the provided values directly. */ + explicit CannotSerializeException(const AString & a_ValueName, const char * a_ErrorMsg): + Super(a_ErrorMsg), + m_ValueName(a_ValueName) + { + } + + /** Constructs a new instance of the exception based on the provided values directly. */ + explicit CannotSerializeException(int a_ValueIndex, const char * a_ErrorMsg): + Super(a_ErrorMsg), + m_ValueName(Printf("%d", a_ValueIndex)) + { + } + + /** Constructs a new instance of the exception that takes the error message and value name from the parent, and prefix the value name with the specified prefix. + Used for prefixing the value name's path along the call stack that lead to the main exception. */ + explicit CannotSerializeException(const CannotSerializeException & a_Parent, const AString & a_ValueNamePrefix): + Super(a_Parent.what()), + m_ValueName(a_ValueNamePrefix + "." + a_Parent.m_ValueName) + { + } + + /** Constructs a new instance of the exception that takes the error message and value name from the parent, and prefix the value name with the specified prefix. + Used for prefixing the value name's path along the call stack that lead to the main exception. */ + explicit CannotSerializeException(const CannotSerializeException & a_Parent, int a_ValueNamePrefixIndex): + Super(a_Parent.what()), + m_ValueName(Printf("%d", a_ValueNamePrefixIndex) + "." + a_Parent.m_ValueName) + { + } + + const AString & GetValueName() const { return m_ValueName; } + +protected: + AString m_ValueName; +}; + + + + /** Pushes the specified Json array as a table on top of the specified Lua state. Assumes that a_Value is an array. */ @@ -136,14 +183,36 @@ static Json::Value JsonSerializeTable(cLuaState & a_LuaState) { int idx; a_LuaState.GetStackValue(-2, idx); - res[idx - 1] = JsonSerializeValue(a_LuaState); + try + { + res[idx - 1] = JsonSerializeValue(a_LuaState); + } + catch (const CannotSerializeException & exc) + { + throw CannotSerializeException(exc, idx); + } + catch (const std::exception & exc) // Cannot catch Json::Exception, because it's not properly defined + { + throw CannotSerializeException(idx, exc.what()); + } } else { AString name; if (a_LuaState.GetStackValue(-2, name)) { - res[name] = JsonSerializeValue(a_LuaState); + try + { + res[name] = JsonSerializeValue(a_LuaState); + } + catch (const CannotSerializeException & exc) + { + throw CannotSerializeException(exc, name); + } + catch (const std::exception & exc) // Cannot catch Json::Exception, because it's not properly defined + { + throw CannotSerializeException(name, exc.what()); + } } } lua_pop(a_LuaState, 1); @@ -259,7 +328,17 @@ static int tolua_cJson_Serialize(lua_State * a_LuaState) // Push the table to the top of the Lua stack, and call the serializing function: lua_pushvalue(L, 2); - Json::Value root = JsonSerializeValue(L); + Json::Value root; + try + { + root = JsonSerializeValue(L); + } + catch (const CannotSerializeException & exc) + { + lua_pushnil(L); + L.Push(Printf("Cannot serialize into Json, value \"%s\" caused an error \"%s\"", exc.GetValueName().c_str(), exc.what())); + return 2; + } lua_pop(L, 1); // Create the writer, with all properties (optional param 3) applied to it: -- cgit v1.2.3