]> git.lizzy.rs Git - dragonblocks_alpha.git/blobdiff - src/map.c
Fix UB/leaks in server
[dragonblocks_alpha.git] / src / map.c
index 82af06420cc34a96f334f3fda261334fa70daf33..a9a83befb97c8502fc90ccdaecbcaf7d390edc70 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -2,7 +2,6 @@
 #include <stdbool.h>
 #include <unistd.h>
 #include <math.h>
-#include <endian.h>
 #include <string.h>
 #include "map.h"
 #include "util.h"
@@ -12,25 +11,25 @@ Map *map_create(MapCallbacks callbacks)
        Map *map = malloc(sizeof(Map));
        pthread_rwlock_init(&map->rwlck, NULL);
        pthread_rwlock_init(&map->cached_rwlck, NULL);
-       map->sectors = bintree_create(sizeof(v2s32));
+       map->sectors = bintree_create(sizeof(v2s32), NULL);
        map->cached = NULL;
        map->callbacks = callbacks;
        return map;
 }
 
-static void free_block(void *value, void *arg)
+static void free_block(BintreeNode *node, void *arg)
 {
        Map *map = arg;
 
        if (map->callbacks.delete_block)
-               map->callbacks.delete_block(value);
+               map->callbacks.delete_block(node->value);
 
-       map_free_block(value);
+       map_free_block(node->value);
 }
 
-static void free_sector(void *value, void *arg)
+static void free_sector(BintreeNode *node, void *arg)
 {
-       MapSector *sector = value;
+       MapSector *sector = node->value;
 
        bintree_clear(&sector->blocks, &free_block, arg);
        pthread_rwlock_destroy(&sector->rwlck);
@@ -62,7 +61,7 @@ MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
                sector = malloc(sizeof(MapSector));
                pthread_rwlock_init(&sector->rwlck, NULL);
                sector->pos = pos;
-               sector->blocks = bintree_create(sizeof(s32));
+               sector->blocks = bintree_create(sizeof(s32), NULL);
 
                bintree_add_node(&map->sectors, nodeptr, &pos, sector);
        }
@@ -130,76 +129,62 @@ MapBlock *map_allocate_block(v3s32 pos)
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        pthread_mutex_init(&block->mtx, &attr);
-       return block;
-}
 
-void map_clear_meta(MapBlock *block)
-{
-       pthread_mutex_lock(&block->mtx);
-       ITERATE_MAPBLOCK list_clear(&block->metadata[x][y][z]);
-       pthread_mutex_unlock(&block->mtx);
+       ITERATE_MAPBLOCK block->data[x][y][z] = map_node_create(NODE_UNKNOWN, (Blob) {0, NULL});
+
+       return block;
 }
 
 void map_free_block(MapBlock *block)
 {
-       map_clear_meta(block);
+       ITERATE_MAPBLOCK map_node_delete(block->data[x][y][z]);
+
        pthread_mutex_destroy(&block->mtx);
        free(block);
 }
 
-bool map_deserialize_node(int fd, MapNode *node)
+Blob map_serialize_block(MapBlock *block)
 {
-       Node type;
-
-       if (! read_u32(fd, &type))
-               return false;
-
-       if (type >= NODE_UNLOADED)
-               type = NODE_INVALID;
+       SerializedMapBlock block_data;
 
-       *node = map_node_create(type);
-
-       return true;
-}
-
-void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr)
-{
-       MapBlockData uncompressed;
        ITERATE_MAPBLOCK {
-               MapNode node = block->data[x][y][z];
+               MapNode *node = &block->data[x][y][z];
+               SerializedMapNode *node_data = &block_data.raw.nodes[x][y][z];
 
-               if (node_definitions[node.type].serialize)
-                       node_definitions[node.type].serialize(&node);
+               *node_data = (SerializedMapNode) {
+                       .type = node->type,
+                       .data = {
+                               .siz = 0,
+                               .data = NULL,
+                       },
+               };
 
-               node.type = htobe32(node.type);
-               uncompressed[x][y][z] = node;
+               NodeDefinition *def = &node_definitions[node->type];
+
+               if (def->serialize)
+                       def->serialize(&node_data->data, node->data);
        }
 
-       my_compress(&uncompressed, sizeof(MapBlockData), dataptr, sizeptr);
+       Blob buffer = {0, NULL};
+       SerializedMapBlock_write(&buffer, &block_data);
+       SerializedMapBlock_free(&block_data);
+
+       return buffer;
 }
 
-bool map_deserialize_block(MapBlock *block, const char *data, size_t size)
+bool map_deserialize_block(MapBlock *block, Blob buffer)
 {
-       MapBlockData decompressed;
+       // it's important to copy Blobs that have been malloc'd before reading from them
+       // because reading from a Blob modifies its data and size pointer,
+       // but does not free anything
+       SerializedMapBlock block_data = {0};
+       bool success = SerializedMapBlock_read(&buffer, &block_data);
 
-       if (! my_decompress(data, size, &decompressed, sizeof(MapBlockData)))
-               return false;
-
-       ITERATE_MAPBLOCK {
-               MapNode node = decompressed[x][y][z];
-               node.type = be32toh(node.type);
+       if (success) ITERATE_MAPBLOCK
+               block->data[x][y][z] = map_node_create(block_data.raw.nodes[x][y][z].type, block_data.raw.nodes[x][y][z].data);
 
-               if (node.type >= NODE_UNLOADED)
-                       node.type = NODE_INVALID;
-
-               if (node_definitions[node.type].deserialize)
-                       node_definitions[node.type].deserialize(&node);
-
-               block->data[x][y][z] = node;
-               block->metadata[x][y][z] = list_create(&list_compare_string);
-       }
-
-       return true;
+       SerializedMapBlock_free(&block_data);
+       return success;
 }
 
 v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset)
@@ -215,7 +200,7 @@ MapNode map_get_node(Map *map, v3s32 pos)
        v3s32 blockpos = map_node_to_block_pos(pos, &offset);
        MapBlock *block = map_get_block(map, blockpos, false);
        if (! block)
-               return map_node_create(NODE_UNLOADED);
+               return map_node_create(NODE_UNLOADED, (Blob) {0, NULL});
        return block->data[offset.x][offset.y][offset.z];
 }
 
@@ -226,23 +211,43 @@ void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg)
        if (block) {
                pthread_mutex_lock(&block->mtx);
                if (! map->callbacks.set_node || map->callbacks.set_node(block, offset, &node, arg)) {
+                       block->data[offset.x][offset.y][offset.z] = node;
                        if (map->callbacks.after_set_node)
                                map->callbacks.after_set_node(block, offset, arg);
-                       list_clear(&block->metadata[offset.x][offset.y][offset.z]);
-                       block->data[offset.x][offset.y][offset.z] = node;
+               } else {
+                       map_node_delete(node);
                }
                pthread_mutex_unlock(&block->mtx);
        }
 }
 
-MapNode map_node_create(Node type)
+MapNode map_node_create(Node type, Blob buffer)
 {
+       if (type >= NODE_UNLOADED)
+               type = NODE_UNKNOWN;
+
+       NodeDefinition *def = &node_definitions[type];
+
        MapNode node;
        node.type = type;
-       memset(&node.state, 0, sizeof(NodeState));
+       node.data = def->data_size ? malloc(def->data_size) : NULL;
 
-       if (node.type != NODE_UNLOADED && node_definitions[node.type].create)
-               node_definitions[node.type].create(&node);
+       if (def->create)
+               def->create(&node);
+
+       if (def->deserialize)
+               def->deserialize(&buffer, node.data);
 
        return node;
 }
+
+void map_node_delete(MapNode node)
+{
+       NodeDefinition *def = &node_definitions[node.type];
+
+       if (def->delete)
+               def->delete(&node);
+
+       if (node.data)
+               free(node.data);
+}