From 49698169c7528c71a45acac38edda8f066133a9b Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sat, 2 Aug 2014 02:21:07 -0400 Subject: [PATCH 1/5] Clean-up some unnecessary CHECKVAL templates. --- LuaEngine.cpp | 115 ++++++++------------------------------------------ LuaEngine.h | 12 +++++- 2 files changed, 29 insertions(+), 98 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index 746b521..dc1bd5c 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -22,13 +22,6 @@ #include #endif -extern "C" -{ -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -}; - Eluna::ScriptList Eluna::lua_scripts; Eluna::ScriptList Eluna::lua_extensions; std::string Eluna::lua_folderpath; @@ -462,150 +455,78 @@ void Eluna::Push(lua_State* L, Object const* obj) ElunaTemplate::push(L, obj); } } + template<> bool Eluna::CHECKVAL(lua_State* L, int narg) { - return lua_isnumber(L, narg) != 0 ? luaL_optnumber(L, narg, 1) ? true : false : lua_toboolean(L, narg) != 0; -} -template<> bool Eluna::CHECKVAL(lua_State* L, int narg, bool def) -{ - return lua_isnone(L, narg) != 0 ? def : lua_isnumber(L, narg) != 0 ? luaL_optnumber(L, narg, 1) != 0 ? true : false : lua_toboolean(L, narg) != 0; + return lua_toboolean(L, narg); } template<> float Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checknumber(L, narg); } -template<> float Eluna::CHECKVAL(lua_State* L, int narg, float def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optnumber(L, narg, def); -} template<> double Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checknumber(L, narg); } -template<> double Eluna::CHECKVAL(lua_State* L, int narg, double def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optnumber(L, narg, def); -} template<> int8 Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkint(L, narg); } -template<> int8 Eluna::CHECKVAL(lua_State* L, int narg, int8 def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optint(L, narg, def); -} template<> uint8 Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkunsigned(L, narg); } -template<> uint8 Eluna::CHECKVAL(lua_State* L, int narg, uint8 def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optunsigned(L, narg, def); -} template<> int16 Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkint(L, narg); } -template<> int16 Eluna::CHECKVAL(lua_State* L, int narg, int16 def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optint(L, narg, def); -} template<> uint16 Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkunsigned(L, narg); } -template<> uint16 Eluna::CHECKVAL(lua_State* L, int narg, uint16 def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optunsigned(L, narg, def); -} -template<> uint32 Eluna::CHECKVAL(lua_State* L, int narg) -{ - return luaL_checkunsigned(L, narg); -} -template<> uint32 Eluna::CHECKVAL(lua_State* L, int narg, uint32 def) -{ - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optunsigned(L, narg, def); -} template<> int32 Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checklong(L, narg); } -template<> int32 Eluna::CHECKVAL(lua_State* L, int narg, int32 def) +template<> uint32 Eluna::CHECKVAL(lua_State* L, int narg) { - if (lua_isnoneornil(L, narg) || !lua_isnumber(L, narg)) - return def; - return luaL_optlong(L, narg, def); + return luaL_checkunsigned(L, narg); } template<> const char* Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkstring(L, narg); } -template<> const char* Eluna::CHECKVAL(lua_State* L, int narg, const char* def) -{ - if (lua_isnoneornil(L, narg) || !lua_isstring(L, narg)) - return def; - return luaL_optstring(L, narg, def); -} template<> std::string Eluna::CHECKVAL(lua_State* L, int narg) { return luaL_checkstring(L, narg); } -template<> std::string Eluna::CHECKVAL(lua_State* L, int narg, std::string def) -{ - if (lua_isnoneornil(L, narg) || !lua_isstring(L, narg)) - return def; - return luaL_optstring(L, narg, def.c_str()); -} -template<> uint64 Eluna::CHECKVAL(lua_State* L, int narg) -{ - const char* c_str = CHECKVAL(L, narg, NULL); - if (!c_str) - return luaL_argerror(L, narg, "uint64 (as string) expected"); - uint64 l = 0; - sscanf(c_str, UI64FMTD, &l); - return l; -} -template<> uint64 Eluna::CHECKVAL(lua_State* L, int narg, uint64 def) -{ - const char* c_str = CHECKVAL(L, narg, NULL); - if (!c_str) - return def; - uint64 l = 0; - sscanf(c_str, UI64FMTD, &l); - return l; -} template<> int64 Eluna::CHECKVAL(lua_State* L, int narg) { const char* c_str = CHECKVAL(L, narg, NULL); if (!c_str) return luaL_argerror(L, narg, "int64 (as string) expected"); + int64 l = 0; - sscanf(c_str, SI64FMTD, &l); + int parsed_count = sscanf(c_str, SI64FMTD, &l); + if (parsed_count != 1) + return luaL_argerror(L, narg, "int64 (as string) could not be converted"); + return l; } -template<> int64 Eluna::CHECKVAL(lua_State* L, int narg, int64 def) +template<> uint64 Eluna::CHECKVAL(lua_State* L, int narg) { const char* c_str = CHECKVAL(L, narg, NULL); if (!c_str) - return def; - int64 l = 0; - sscanf(c_str, SI64FMTD, &l); + return luaL_argerror(L, narg, "uint64 (as string) expected"); + + uint64 l = 0; + int parsed_count = sscanf(c_str, UI64FMTD, &l); + if (parsed_count != 1) + return luaL_argerror(L, narg, "uint64 (as string) could not be converted"); + return l; } + #define TEST_OBJ(T, O, E, F)\ {\ if (!O || !O->F())\ diff --git a/LuaEngine.h b/LuaEngine.h index 73f08e7..6649e49 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -20,6 +20,13 @@ #include "World.h" #include "HookMgr.h" +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +}; + #ifdef TRINITY struct ItemTemplate; #else @@ -163,7 +170,10 @@ public: // Checks template static T CHECKVAL(lua_State* L, int narg); - template static T CHECKVAL(lua_State* L, int narg, T def); + template static T CHECKVAL(lua_State* L, int narg, T def) + { + return lua_isnoneornil(L, narg) ? def : CHECKVAL(L, narg); + } template static T* CHECKOBJ(lua_State* L, int narg, bool error = true) { return ElunaTemplate::check(L, narg, error); From 64c26969b7fe322c2f2f0b9131ca1387d20d0d9d Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sat, 2 Aug 2014 02:31:19 -0400 Subject: [PATCH 2/5] Move some unused includes. --- LuaEngine.cpp | 6 ++++++ LuaEngine.h | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index dc1bd5c..59ed1e8 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -22,6 +22,12 @@ #include #endif +extern "C" +{ +#include "lualib.h" +#include "lauxlib.h" +}; + Eluna::ScriptList Eluna::lua_scripts; Eluna::ScriptList Eluna::lua_extensions; std::string Eluna::lua_folderpath; diff --git a/LuaEngine.h b/LuaEngine.h index 6649e49..82a2efb 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -23,8 +23,6 @@ extern "C" { #include "lua.h" -#include "lualib.h" -#include "lauxlib.h" }; #ifdef TRINITY From b2bebc006eaec06fe398cfb2815db79aa52a829b Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sat, 2 Aug 2014 03:31:11 -0400 Subject: [PATCH 3/5] Add overflow checking for CHECKVAL. --- LuaEngine.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index 59ed1e8..bfd88b1 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -462,6 +462,47 @@ void Eluna::Push(lua_State* L, Object const* obj) } } +static int32 CheckIntegerRange(lua_State *L, int narg, int32 max, int32 min) +{ + int32 value = luaL_checklong(L, narg); + char error_buffer[64]; + + if (value > max) + { + snprintf(error_buffer, 64, "value must be less than %u", max); + return luaL_argerror(L, narg, error_buffer); + } + + if (value < min) + { + snprintf(error_buffer, 64, "value must be greater than %d", min); + return luaL_argerror(L, narg, error_buffer); + } + + return value; +} + +// This function does not work properly for anything larger than uint16. +static uint32 CheckUnsignedRange(lua_State *L, int narg, uint32 max) +{ + int32 value = luaL_checklong(L, narg); + char error_buffer[64]; + + if (value < 0) + return luaL_argerror(L, narg, "value must be greater than 0"); + + // Prevent signed-unsigned mismatch. + // This cast is safe because the value is not negative. + uint32 u_value = value; + if (u_value > max) + { + snprintf(error_buffer, 64, "value must be less than %u", max); + return luaL_argerror(L, narg, error_buffer); + } + + return u_value; +} + template<> bool Eluna::CHECKVAL(lua_State* L, int narg) { return lua_toboolean(L, narg); @@ -476,19 +517,19 @@ template<> double Eluna::CHECKVAL(lua_State* L, int narg) } template<> int8 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checkint(L, narg); + return CheckIntegerRange(L, narg, SCHAR_MAX, SCHAR_MIN); } template<> uint8 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checkunsigned(L, narg); + return CheckUnsignedRange(L, narg, UCHAR_MAX); } template<> int16 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checkint(L, narg); + return CheckIntegerRange(L, narg, SHRT_MIN, SHRT_MAX); } template<> uint16 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checkunsigned(L, narg); + return CheckUnsignedRange(L, narg, USHRT_MAX); } template<> int32 Eluna::CHECKVAL(lua_State* L, int narg) { @@ -496,7 +537,9 @@ template<> int32 Eluna::CHECKVAL(lua_State* L, int narg) } template<> uint32 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checkunsigned(L, narg); + // If a negative value is passed instead, it will become a large positive value. + // There is no way to catch this. + return luaL_checklong(L, narg); } template<> const char* Eluna::CHECKVAL(lua_State* L, int narg) { From ac754aeffaa06abdc63d5a9495265505b87958a2 Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sat, 2 Aug 2014 21:18:31 -0400 Subject: [PATCH 4/5] Fix issues with negative values and uint32. --- LuaEngine.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index bfd88b1..0a3a8dd 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -462,14 +462,14 @@ void Eluna::Push(lua_State* L, Object const* obj) } } -static int32 CheckIntegerRange(lua_State *L, int narg, int32 max, int32 min) +static int32 CheckIntegerRange(lua_State *L, int narg, int32 min, int32 max) { - int32 value = luaL_checklong(L, narg); + int64 value = luaL_checklong(L, narg); char error_buffer[64]; if (value > max) { - snprintf(error_buffer, 64, "value must be less than %u", max); + snprintf(error_buffer, 64, "value must be less than %d", max); return luaL_argerror(L, narg, error_buffer); } @@ -482,25 +482,21 @@ static int32 CheckIntegerRange(lua_State *L, int narg, int32 max, int32 min) return value; } -// This function does not work properly for anything larger than uint16. static uint32 CheckUnsignedRange(lua_State *L, int narg, uint32 max) { - int32 value = luaL_checklong(L, narg); + int64 value = luaL_checklong(L, narg); char error_buffer[64]; if (value < 0) return luaL_argerror(L, narg, "value must be greater than 0"); - // Prevent signed-unsigned mismatch. - // This cast is safe because the value is not negative. - uint32 u_value = value; - if (u_value > max) + if (value > max) { snprintf(error_buffer, 64, "value must be less than %u", max); return luaL_argerror(L, narg, error_buffer); } - return u_value; + return value; } template<> bool Eluna::CHECKVAL(lua_State* L, int narg) @@ -517,7 +513,7 @@ template<> double Eluna::CHECKVAL(lua_State* L, int narg) } template<> int8 Eluna::CHECKVAL(lua_State* L, int narg) { - return CheckIntegerRange(L, narg, SCHAR_MAX, SCHAR_MIN); + return CheckIntegerRange(L, narg, SCHAR_MIN, SCHAR_MAX); } template<> uint8 Eluna::CHECKVAL(lua_State* L, int narg) { @@ -533,13 +529,11 @@ template<> uint16 Eluna::CHECKVAL(lua_State* L, int narg) } template<> int32 Eluna::CHECKVAL(lua_State* L, int narg) { - return luaL_checklong(L, narg); + return CheckIntegerRange(L, narg, INT_MIN, INT_MAX); } template<> uint32 Eluna::CHECKVAL(lua_State* L, int narg) { - // If a negative value is passed instead, it will become a large positive value. - // There is no way to catch this. - return luaL_checklong(L, narg); + return CheckUnsignedRange(L, narg, UINT_MAX); } template<> const char* Eluna::CHECKVAL(lua_State* L, int narg) { From 2e1ed8c1e92f3af12165112b333e63ace34bfe2a Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sun, 3 Aug 2014 23:42:42 -0400 Subject: [PATCH 5/5] Fix possible size issues. --- LuaEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index 0a3a8dd..9882d8f 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -464,7 +464,7 @@ void Eluna::Push(lua_State* L, Object const* obj) static int32 CheckIntegerRange(lua_State *L, int narg, int32 min, int32 max) { - int64 value = luaL_checklong(L, narg); + int64 value = luaL_checknumber(L, narg); char error_buffer[64]; if (value > max) @@ -484,7 +484,7 @@ static int32 CheckIntegerRange(lua_State *L, int narg, int32 min, int32 max) static uint32 CheckUnsignedRange(lua_State *L, int narg, uint32 max) { - int64 value = luaL_checklong(L, narg); + int64 value = luaL_checknumber(L, narg); char error_buffer[64]; if (value < 0)