Browse Source

Added some checks for invalid numbers to love.math.setRandomState

--HG--
branch : RandomGenerator-2
Alex Szpakowski 12 years ago
parent
commit
674ad9247a

+ 9 - 0
src/modules/math/RandomGenerator.cpp

@@ -45,6 +45,15 @@ RandomGenerator::RandomGenerator()
 #endif
 }
 
+void RandomGenerator::setState(RandomGenerator::State state)
+{
+	// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
+	if (state.b64 == 0)
+		throw love::Exception("Invalid random state.");
+
+	rng_state = state;
+}
+
 uint64 RandomGenerator::rand()
 {
 	rng_state.b64 ^= (rng_state.b64 << 13);

+ 10 - 8
src/modules/math/RandomGenerator.h

@@ -23,6 +23,7 @@
 
 // LOVE
 #include "common/config.h"
+#include "common/Exception.h"
 #include "common/math.h"
 #include "common/int.h"
 #include "common/Object.h"
@@ -56,23 +57,24 @@ public:
 	 * Set pseudo-random state.
 	 * It's up to the implementation how to use this.
 	 **/
-	inline void setState(State state)
-	{
-		rng_state = state;
-	}
+	void setState(State state);
 
 	/**
 	 * Separately set the low and high parts of the pseudo-random state.
 	 **/
 	inline void setState(uint32 low, uint32 high)
 	{
+		State newstate;
+
 #ifdef LOVE_BIG_ENDIAN
-		rng_state.b32.a = high;
-		rng_state.b32.b = low;
+		newstate.b32.a = high;
+		newstate.b32.b = low;
 #else
-		rng_state.b32.b = high;
-		rng_state.b32.a = low;
+		newstate.b32.b = high;
+		newstate.b32.a = low;
 #endif
+
+		setState(newstate);
 	}
 
 	inline State getState() const

+ 8 - 1
src/modules/math/wrap_Math.cpp

@@ -34,7 +34,14 @@ namespace math
 
 int w_setRandomState(lua_State *L)
 {
-	Math::instance.setRandomState(luax_checkrandomstate(L, 1));
+	try
+	{
+		Math::instance.setRandomState(luax_checkrandomstate(L, 1));
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
 	return 0;
 }
 

+ 25 - 4
src/modules/math/wrap_RandomGenerator.cpp

@@ -21,20 +21,34 @@
 #include "wrap_RandomGenerator.h"
 
 #include <cmath>
+#include <algorithm>
 
 namespace love
 {
 namespace math
 {
 
+template <typename T>
+static T checkrandomstate_part(lua_State *L, int idx)
+{
+	double num = luaL_checknumber(L, idx);
+	double inf = std::numeric_limits<double>::infinity();
+
+	// Disallow conversions from infinity and NaN.
+	if (num == inf || num == -inf || num != num)
+		luaL_argerror(L, idx, "invalid random state");
+
+	return (T) num;
+}
+
 RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx)
 {
 	RandomGenerator::State s;
 
 	if (!lua_isnoneornil(L, idx + 1))
 	{
-		uint32 low = (uint32) luaL_checknumber(L, idx);
-		uint32 high = (uint32) luaL_checknumber(L, idx + 1);
+		uint32 low = checkrandomstate_part<uint32>(L, idx);
+		uint32 high = checkrandomstate_part<uint32>(L, idx + 1);
 
 #ifdef LOVE_BIG_ENDIAN
 		s.b32.a = high;
@@ -45,7 +59,7 @@ RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx)
 #endif
 	}
 	else
-		s.b64 = (uint64) luaL_checknumber(L, idx);
+		s.b64 = checkrandomstate_part<uint64>(L, idx);
 
 	return s;
 }
@@ -84,7 +98,14 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
 int w_RandomGenerator_setState(lua_State *L)
 {
 	RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
-	rng->setState(luax_checkrandomstate(L, 2));
+	try
+	{
+		rng->setState(luax_checkrandomstate(L, 2));
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
 	return 0;
 }