HPChange Reason: Fix push after free, and type being overwritten (#8359)
authorrubenwardy <rw@rubenwardy.com>
Tue, 12 Mar 2019 07:56:56 +0000 (07:56 +0000)
committerrubenwardy <rw@rubenwardy.com>
Tue, 12 Mar 2019 20:25:48 +0000 (20:25 +0000)
* HPChange Reason: Fix push after free, and type being overwritten

Fixes #8227 and #8344

src/content_sao.h
src/script/cpp_api/s_base.cpp
src/script/lua_api/l_object.cpp

index 14f959e30c51f8f9be62f5278ac0311e18177779..f54bc16c2d4a1bc4aba41870710ef4b54ce27591 100644 (file)
@@ -405,6 +405,11 @@ struct PlayerHPChangeReason {
        bool from_mod = false;
        int lua_reference = -1;
 
+       inline bool hasLuaReference() const
+       {
+               return lua_reference >= 0;
+       }
+
        bool setTypeFromString(const std::string &typestr)
        {
                if (typestr == "set_hp")
index bf89f748c6756ed42850589bacbd94e52ae7d383..a8ed902dd1a28d836f74f28676c1ab745131c698 100644 (file)
@@ -384,14 +384,18 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
 
 void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
 {
-       if (reason.lua_reference >= 0) {
+       if (reason.hasLuaReference())
                lua_rawgeti(L, LUA_REGISTRYINDEX, reason.lua_reference);
-               luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference);
-       } else
+       else
                lua_newtable(L);
 
-       lua_pushstring(L, reason.getTypeAsString().c_str());
-       lua_setfield(L, -2, "type");
+       lua_getfield(L, -1, "type");
+       bool has_type = (bool)lua_isstring(L, -1);
+       lua_pop(L, 1);
+       if (!has_type) {
+               lua_pushstring(L, reason.getTypeAsString().c_str());
+               lua_setfield(L, -2, "type");
+       }
 
        lua_pushstring(L, reason.from_mod ? "mod" : "engine");
        lua_setfield(L, -2, "from");
index 9edb2f4f828ab4712fba469e2cdef339b47c68ec..b3ed39c7cb5230e5e6bf055d6f732e7ad7341d18 100644 (file)
@@ -257,6 +257,9 @@ int ObjectRef::l_set_hp(lua_State *L)
        if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
                getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
 
+       if (reason.hasLuaReference())
+               luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference);
+
        // Return
        return 0;
 }