From da9328e72c06eeb5e6b9191966352b69f3ef9a75 Mon Sep 17 00:00:00 2001 From: Josip Miskovic Date: Wed, 21 Sep 2022 11:53:36 +0200 Subject: [PATCH] Fix sending strings with \0 through channels A null-char is valid part of Lua string. When such a string is sent through the channel, its length should be stored as well to be able to correctly reconstruct it on the other thread. The bug was triggered with this code: s1 = 'a \0 b' print(#s1) -- 5 ch:push(s1) s2 = ch:pop() print(#s2) -- 2 --- src/api/l_event.c | 11 ++++++----- src/modules/event/event.c | 2 +- src/modules/event/event.h | 6 +++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/api/l_event.c b/src/api/l_event.c index 56af7350..80145e68 100644 --- a/src/api/l_event.c +++ b/src/api/l_event.c @@ -46,10 +46,11 @@ void luax_checkvariant(lua_State* L, int index, Variant* variant) { variant->type = TYPE_STRING; size_t length; const char* string = lua_tolstring(L, index, &length); - variant->value.string = malloc(length + 1); - lovrAssert(variant->value.string, "Out of memory"); - memcpy(variant->value.string, string, length); - variant->value.string[length] = '\0'; + variant->value.string.pointer = malloc(length + 1); + lovrAssert(variant->value.string.pointer, "Out of memory"); + memcpy(variant->value.string.pointer, string, length); + variant->value.string.pointer[length] = '\0'; + variant->value.string.length = length; break; case LUA_TUSERDATA: @@ -80,7 +81,7 @@ int luax_pushvariant(lua_State* L, Variant* variant) { case TYPE_NIL: lua_pushnil(L); return 1; case TYPE_BOOLEAN: lua_pushboolean(L, variant->value.boolean); return 1; case TYPE_NUMBER: lua_pushnumber(L, variant->value.number); return 1; - case TYPE_STRING: lua_pushstring(L, variant->value.string); return 1; + case TYPE_STRING: lua_pushlstring(L, variant->value.string.pointer, variant->value.string.length); return 1; case TYPE_OBJECT: _luax_pushtype(L, variant->value.object.type, hash64(variant->value.object.type, strlen(variant->value.object.type)), variant->value.object.pointer); return 1; default: return 0; } diff --git a/src/modules/event/event.c b/src/modules/event/event.c index 0a2a6bf4..9aa37be2 100644 --- a/src/modules/event/event.c +++ b/src/modules/event/event.c @@ -13,7 +13,7 @@ static struct { void lovrVariantDestroy(Variant* variant) { switch (variant->type) { - case TYPE_STRING: free(variant->value.string); return; + case TYPE_STRING: free(variant->value.string.pointer); return; case TYPE_OBJECT: lovrRelease(variant->value.object.pointer, variant->value.object.destructor); return; default: return; } diff --git a/src/modules/event/event.h b/src/modules/event/event.h index b01d390f..0191a55b 100644 --- a/src/modules/event/event.h +++ b/src/modules/event/event.h @@ -1,5 +1,6 @@ #include #include +#include #pragma once @@ -33,7 +34,10 @@ typedef enum { typedef union { bool boolean; double number; - char* string; + struct { + char* pointer; + size_t length; + } string; struct { void* pointer; const char* type;