From ce5927379d57fecf74129fa3f8f93c56a7e2e3f4 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 3 Jul 2011 18:02:53 +0200 Subject: [PATCH] Use a lua_type switch/case in thread.send, to prevent casts (bug #252) Push non-love userdata as lightuserdata, will probably break it, but shouldn't crash love (bug #243) --- src/modules/thread/Thread.cpp | 13 ++- src/modules/thread/wrap_Thread.cpp | 176 +++++++++++------------------ 2 files changed, 73 insertions(+), 116 deletions(-) diff --git a/src/modules/thread/Thread.cpp b/src/modules/thread/Thread.cpp index 2b437ebbf..a159e8132 100644 --- a/src/modules/thread/Thread.cpp +++ b/src/modules/thread/Thread.cpp @@ -101,10 +101,15 @@ namespace thread { type = FUSERDATA; this->udatatype = udatatype; - Proxy *p = (Proxy *) userdata; - flags = p->flags; - data.userdata = p->data; - ((love::Object *) data.userdata)->retain(); + if (udatatype != INVALID_ID) + { + Proxy *p = (Proxy *) userdata; + flags = p->flags; + data.userdata = p->data; + ((love::Object *) data.userdata)->retain(); + } + else + data.userdata = userdata; } ThreadVariant::~ThreadVariant() diff --git a/src/modules/thread/wrap_Thread.cpp b/src/modules/thread/wrap_Thread.cpp index 5e149cd0c..631ec1a8a 100644 --- a/src/modules/thread/wrap_Thread.cpp +++ b/src/modules/thread/wrap_Thread.cpp @@ -70,18 +70,12 @@ namespace thread return 1; } - int w_Thread_get(lua_State *L) + bool __pushThreadVariant(lua_State *L, ThreadVariant *v) { - Thread *t = luax_checkthread(L, 1); - std::string name = luax_checklstring(L, 2); - t->lock(); - ThreadVariant *v = t->get(name); - t->clear(name); - t->unlock(); if (!v) { lua_pushnil(L); - return 1; + return false; } switch(v->type) { @@ -98,17 +92,36 @@ namespace thread lua_pushlightuserdata(L, v->data.userdata); break; case FUSERDATA: - { - const char *name = NULL; - love::types.find(v->udatatype, name); - ((love::Object *) v->data.userdata)->retain(); - luax_newtype(L, name, v->flags, v->data.userdata); + if (v->udatatype != INVALID_ID) + { + const char *name = NULL; + love::types.find(v->udatatype, name); + ((love::Object *) v->data.userdata)->retain(); + luax_newtype(L, name, v->flags, v->data.userdata); + } + else + lua_pushlightuserdata(L, v->data.userdata); + // I know this is not the same + // sadly, however, it's the most + // I can do (at the moment). break; - } default: lua_pushnil(L); break; } + return true; + } + + int w_Thread_get(lua_State *L) + { + Thread *t = luax_checkthread(L, 1); + std::string name = luax_checklstring(L, 2); + t->lock(); + ThreadVariant *v = t->get(name); + t->clear(name); + t->unlock(); + if (!__pushThreadVariant(L, v)) + return 1; t->lock(); v->release(); t->unlock(); @@ -123,37 +136,8 @@ namespace thread ThreadVariant *v = t->demand(name); t->clear(name); t->unlock(); - if (!v) - { - lua_pushnil(L); + if (!__pushThreadVariant(L, v)) return 1; - } - switch(v->type) - { - case BOOLEAN: - lua_pushboolean(L, v->data.boolean); - break; - case NUMBER: - lua_pushnumber(L, v->data.number); - break; - case STRING: - lua_pushlstring(L, v->data.string.str, v->data.string.len); - break; - case LUSERDATA: - lua_pushlightuserdata(L, v->data.userdata); - break; - case FUSERDATA: - { - const char *name = NULL; - types.find(v->udatatype, name); - ((love::Object *) v->data.userdata)->retain(); - luax_newtype(L, name, v->flags, v->data.userdata); - break; - } - default: - lua_pushnil(L); - break; - } t->lock(); v->release(); t->unlock(); @@ -167,37 +151,8 @@ namespace thread t->lock(); ThreadVariant *v = t->get(name); t->unlock(); - if (!v) - { - lua_pushnil(L); + if (!__pushThreadVariant(L, v)) return 1; - } - switch(v->type) - { - case BOOLEAN: - lua_pushboolean(L, v->data.boolean); - break; - case NUMBER: - lua_pushnumber(L, v->data.number); - break; - case STRING: - lua_pushlstring(L, v->data.string.str, v->data.string.len); - break; - case LUSERDATA: - lua_pushlightuserdata(L, v->data.userdata); - break; - case FUSERDATA: - { - const char *name = NULL; - types.find(v->udatatype, name); - ((love::Object *) v->data.userdata)->retain(); - luax_newtype(L, name, v->flags, v->data.userdata); - break; - } - default: - lua_pushnil(L); - break; - } t->lock(); v->release(); t->unlock(); @@ -205,51 +160,48 @@ namespace thread } Type extractudatatype(lua_State * L, int idx) - { - Type t = INVALID_ID; - if (!lua_isuserdata(L, idx)) - return t; - if (luaL_getmetafield (L, idx, "__tostring") == 0) - return t; - lua_pushvalue(L, idx); - int result = lua_pcall(L, 1, 1, 0); - if (result == 0) - types.find(lua_tostring(L, -1), t); - if (result == 0 || result == LUA_ERRRUN) - lua_pop(L, 1); - return t; - } + { + Type t = INVALID_ID; + if (!lua_isuserdata(L, idx)) + return t; + if (luaL_getmetafield (L, idx, "__tostring") == 0) + return t; + lua_pushvalue(L, idx); + int result = lua_pcall(L, 1, 1, 0); + if (result == 0) + types.find(lua_tostring(L, -1), t); + if (result == 0 || result == LUA_ERRRUN) + lua_pop(L, 1); + return t; + } int w_Thread_set(lua_State *L) { Thread *t = luax_checkthread(L, 1); std::string name = luax_checklstring(L, 2); ThreadVariant *v; - if (lua_isboolean(L, 3)) + size_t len; + const char *str; + switch(lua_type(L, 3)) { - v = new ThreadVariant(luax_toboolean(L, 3)); - } - else if (lua_isnumber(L, 3)) - { - v = new ThreadVariant(lua_tonumber(L, 3)); - } - else if (lua_isstring(L, 3)) - { - size_t len; - const char *str = lua_tolstring(L, 3, &len); - v = new ThreadVariant(str, len); - } - else if (lua_islightuserdata(L, 3)) - { - v = new ThreadVariant(lua_touserdata(L, 3)); - } - else if (lua_isuserdata(L, 3)) - { - v = new ThreadVariant(extractudatatype(L, 3), lua_touserdata(L, 3)); - } - else - { - return luaL_error(L, "Expected boolean, number, string or userdata"); + case LUA_TBOOLEAN: + v = new ThreadVariant(luax_toboolean(L, 3)); + break; + case LUA_TNUMBER: + v = new ThreadVariant(lua_tonumber(L, 3)); + break; + case LUA_TSTRING: + str = lua_tolstring(L, 3, &len); + v = new ThreadVariant(str, len); + break; + case LUA_TLIGHTUSERDATA: + v = new ThreadVariant(lua_touserdata(L, 3)); + break; + case LUA_TUSERDATA: + v = new ThreadVariant(extractudatatype(L, 3), lua_touserdata(L, 3)); + break; + default: + return luaL_error(L, "Expected boolean, number, string or userdata"); } t->set(name, v); v->release();