from_table: Fix crash for missing inventory or field
authorSmallJoker <mk939@ymail.com>
Mon, 2 Jan 2017 14:17:28 +0000 (15:17 +0100)
committersapier <sapier at gmx dot net>
Sat, 28 Jan 2017 15:38:46 +0000 (16:38 +0100)
doc/lua_api.txt
src/script/lua_api/l_nodemeta.cpp

index ff745c1c2173b420622760a1b27b74b771b0569f..9a1cb6bace39f92e73e11c333bcda0d469c40683 100644 (file)
@@ -2781,8 +2781,9 @@ Can be gotten via `minetest.get_meta(pos)`.
 * `get_inventory()`: returns `InvRef`
 * `to_table()`: returns `nil` or `{fields = {...}, inventory = {list1 = {}, ...}}`
 * `from_table(nil or {})`
-    * to clear metadata, use from_table(nil)
+    * Any non-table value will clear the metadata
     * See "Node Metadata"
+    * returns `true` on success
 
 ### `NodeTimerRef`
 Node Timers: a high resolution persistent per-node timer.
index 3d03c0c41f6ddd9f72448d0cdb19d533b14134a2..631aa68ce746b68dc4c6af4d09167e297fc7b274 100644 (file)
@@ -250,7 +250,7 @@ int NodeMetaRef::l_from_table(lua_State *L)
        // clear old metadata first
        ref->m_env->getMap().removeNodeMetadata(ref->m_p);
 
-       if(lua_isnil(L, base)){
+       if (!lua_istable(L, base)) {
                // No metadata
                lua_pushboolean(L, true);
                return 1;
@@ -258,34 +258,42 @@ int NodeMetaRef::l_from_table(lua_State *L)
 
        // Create new metadata
        NodeMetadata *meta = getmeta(ref, true);
-       if(meta == NULL){
+       if (meta == NULL) {
                lua_pushboolean(L, false);
                return 1;
        }
+
        // Set fields
        lua_getfield(L, base, "fields");
-       int fieldstable = lua_gettop(L);
-       lua_pushnil(L);
-       while(lua_next(L, fieldstable) != 0){
-               // key at index -2 and value at index -1
-               std::string name = lua_tostring(L, -2);
-               size_t cl;
-               const char *cs = lua_tolstring(L, -1, &cl);
-               std::string value(cs, cl);
-               meta->setString(name, value);
-               lua_pop(L, 1); // removes value, keeps key for next iteration
+       if (lua_istable(L, -1)) {
+               int fieldstable = lua_gettop(L);
+               lua_pushnil(L);
+               while (lua_next(L, fieldstable) != 0) {
+                       // key at index -2 and value at index -1
+                       std::string name = lua_tostring(L, -2);
+                       size_t cl;
+                       const char *cs = lua_tolstring(L, -1, &cl);
+                       meta->setString(name, std::string(cs, cl));
+                       lua_pop(L, 1); // Remove value, keep key for next iteration
+               }
+               lua_pop(L, 1);
        }
+
        // Set inventory
        Inventory *inv = meta->getInventory();
        lua_getfield(L, base, "inventory");
-       int inventorytable = lua_gettop(L);
-       lua_pushnil(L);
-       while(lua_next(L, inventorytable) != 0){
-               // key at index -2 and value at index -1
-               std::string name = lua_tostring(L, -2);
-               read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
-               lua_pop(L, 1); // removes value, keeps key for next iteration
+       if (lua_istable(L, -1)) {
+               int inventorytable = lua_gettop(L);
+               lua_pushnil(L);
+               while (lua_next(L, inventorytable) != 0) {
+                       // key at index -2 and value at index -1
+                       std::string name = lua_tostring(L, -2);
+                       read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
+                       lua_pop(L, 1); // Remove value, keep key for next iteration
+               }
+               lua_pop(L, 1);
        }
+
        reportMetadataChange(ref);
        lua_pushboolean(L, true);
        return 1;