diff --git a/lauxlib.c b/lauxlib.c index 4ca6c654..64b325d3 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -1091,8 +1091,56 @@ static void warnfon (void *ud, const char *message, int tocont) { } + +/* +** A function to compute an unsigned int with some level of +** randomness. Rely on Address Space Layout Randomization (if present), +** current time, and clock. +*/ +#if !defined(luai_makeseed) + +#include + + +/* +** Size of 'e' measured in number of 'unsigned int's. (In the weird +** case that the division truncates, we just lose some part of the +** value, no big deal.) +*/ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + + +#define addbuff(b,v) \ + (memcpy(b, &(v), sof(v) * sizeof(unsigned int)), b += sof(v)) + + +static unsigned int luai_makeseed (void) { + unsigned int buff[sof(void*) + sof(clock_t) + sof(time_t)]; + unsigned int res; + unsigned int *b = buff; + clock_t c = clock(); + time_t t = time(NULL); + void *h = buff; + addbuff(b, h); /* local variable's address */ + addbuff(b, c); /* clock */ + addbuff(b, t); /* time */ + res = buff[0]; + for (b = buff + 1; b < buff + sof(buff); b++) + res += *b; + return res; +} + +#endif + + +LUALIB_API unsigned int luaL_makeseed (lua_State *L) { + (void)L; /* unused */ + return luai_makeseed(); +} + + LUALIB_API lua_State *luaL_newstate (void) { - lua_State *L = lua_newstate(l_alloc, NULL); + lua_State *L = lua_newstate(l_alloc, NULL, luai_makeseed()); if (l_likely(L)) { lua_atpanic(L, &panic); lua_setwarnf(L, warnfoff, L); /* default is warnings off */ diff --git a/lauxlib.h b/lauxlib.h index 5b977e2a..0ee9a572 100644 --- a/lauxlib.h +++ b/lauxlib.h @@ -100,6 +100,8 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API unsigned int luaL_makeseed (lua_State *L); + LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, diff --git a/lmathlib.c b/lmathlib.c index d0b1e1e5..f13cae4a 100644 --- a/lmathlib.c +++ b/lmathlib.c @@ -603,28 +603,18 @@ static void setseed (lua_State *L, Rand64 *state, } -/* -** Set a "random" seed. To get some randomness, use the current time -** and the address of 'L' (in case the machine does address space layout -** randomization). -*/ -static void randseed (lua_State *L, RanState *state) { - lua_Unsigned seed1 = (lua_Unsigned)time(NULL); - lua_Unsigned seed2 = (lua_Unsigned)(size_t)L; - setseed(L, state->s, seed1, seed2); -} - - static int math_randomseed (lua_State *L) { RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); + lua_Unsigned n1, n2; if (lua_isnone(L, 1)) { - randseed(L, state); + n1 = luaL_makeseed(L); + n2 = I2UInt(state->s[0]); } else { - lua_Integer n1 = luaL_checkinteger(L, 1); - lua_Integer n2 = luaL_optinteger(L, 2, 0); - setseed(L, state->s, n1, n2); + n1 = luaL_checkinteger(L, 1); + n2 = luaL_optinteger(L, 2, 0); } + setseed(L, state->s, n1, n2); return 2; /* return seeds */ } @@ -641,7 +631,7 @@ static const luaL_Reg randfuncs[] = { */ static void setrandfunc (lua_State *L) { RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); - randseed(L, state); /* initialize with a "random" seed */ + setseed(L, state->s, luaL_makeseed(L), 0); /* initialize with random seed */ lua_pop(L, 2); /* remove pushed seeds */ luaL_setfuncs(L, randfuncs, 1); } diff --git a/lstate.c b/lstate.c index bee3bf66..1ce6b9a1 100644 --- a/lstate.c +++ b/lstate.c @@ -51,37 +51,6 @@ typedef struct LG { #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) -/* -** A macro to create a "random" seed when a state is created; -** the seed is used to randomize string hashes. -*/ -#if !defined(luai_makeseed) - -#include - -/* -** Compute an initial seed with some level of randomness. -** Rely on Address Space Layout Randomization (if present) and -** current time. -*/ -#define addbuff(b,p,e) \ - { size_t t = cast_sizet(e); \ - memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } - -static unsigned int luai_makeseed (lua_State *L) { - char buff[3 * sizeof(size_t)]; - unsigned int h = cast_uint(time(NULL)); - int p = 0; - addbuff(buff, p, L); /* heap variable */ - addbuff(buff, p, &h); /* local variable */ - addbuff(buff, p, &lua_newstate); /* public function */ - lua_assert(p == sizeof(buff)); - return luaS_hash(buff, p, h); -} - -#endif - - /* ** set GCdebt to a new value keeping the value (totalobjs + GCdebt) ** invariant (and avoiding underflows in 'totalobjs') @@ -350,7 +319,7 @@ LUA_API int lua_resetthread (lua_State *L, lua_State *from) { } -LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned int seed) { int i; lua_State *L; global_State *g; @@ -370,7 +339,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->warnf = NULL; g->ud_warn = NULL; g->mainthread = L; - g->seed = luai_makeseed(L); + g->seed = seed; g->gcstp = GCSTPGC; /* no GC while building state */ g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; diff --git a/ltablib.c b/ltablib.c index e6bc4d04..82584459 100644 --- a/ltablib.c +++ b/ltablib.c @@ -230,31 +230,8 @@ typedef unsigned int IdxT; ** of a partition. (If you don't want/need this "randomness", ~0 is a ** good choice.) */ -#if !defined(l_randomizePivot) /* { */ - -#include - -/* size of 'e' measured in number of 'unsigned int's */ -#define sof(e) (sizeof(e) / sizeof(unsigned int)) - -/* -** Use 'time' and 'clock' as sources of "randomness". Because we don't -** know the types 'clock_t' and 'time_t', we cannot cast them to -** anything without risking overflows. A safe way to use their values -** is to copy them to an array of a known type and use the array values. -*/ -static unsigned int l_randomizePivot (void) { - clock_t c = clock(); - time_t t = time(NULL); - unsigned int buff[sof(c) + sof(t)]; - unsigned int i, rnd = 0; - memcpy(buff, &c, sof(c) * sizeof(unsigned int)); - memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); - for (i = 0; i < sof(buff); i++) - rnd += buff[i]; - return rnd; -} - +#if !defined(l_randomizePivot) +#define l_randomizePivot(L) luaL_makeseed(L) #endif /* } */ @@ -391,7 +368,7 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up, up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ } if ((up - lo) / 128 > n) /* partition too imbalanced? */ - rnd = l_randomizePivot(); /* try a new randomization */ + rnd = l_randomizePivot(L); /* try a new randomization */ } /* tail call auxsort(L, lo, up, rnd) */ } diff --git a/ltests.c b/ltests.c index e2e0d983..456e83e1 100644 --- a/ltests.c +++ b/ltests.c @@ -1159,7 +1159,7 @@ static int num2int (lua_State *L) { static int newstate (lua_State *L) { void *ud; lua_Alloc f = lua_getallocf(L, &ud); - lua_State *L1 = lua_newstate(f, ud); + lua_State *L1 = lua_newstate(f, ud, 0); if (L1) { lua_atpanic(L1, tpanic); lua_pushlightuserdata(L, L1); @@ -1252,7 +1252,7 @@ static int checkpanic (lua_State *L) { lua_Alloc f = lua_getallocf(L, &ud); b.paniccode = luaL_optstring(L, 2, ""); b.L = L; - L1 = lua_newstate(f, ud); /* create new state */ + L1 = lua_newstate(f, ud, 0); /* create new state */ if (L1 == NULL) { /* error? */ lua_pushnil(L); return 1; diff --git a/ltests.h b/ltests.h index 45d5beba..da773d6e 100644 --- a/ltests.h +++ b/ltests.h @@ -102,7 +102,8 @@ LUA_API void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); #if defined(lua_c) -#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) +#define luaL_newstate() \ + lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL)) #define luai_openlibs(L) \ { luaL_openlibs(L); \ luaL_requiref(L, "T", luaB_opentests, 1); \ diff --git a/lua.h b/lua.h index cb32ec22..e950dfb4 100644 --- a/lua.h +++ b/lua.h @@ -160,7 +160,8 @@ extern const char lua_ident[]; /* ** state manipulation */ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud, + unsigned int seed); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API int (lua_resetthread) (lua_State *L, lua_State *from); diff --git a/manual/manual.of b/manual/manual.of index 73d25951..fdae76f2 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -20,7 +20,7 @@ making it ideal for configuration, scripting, and rapid prototyping. Lua is implemented as a library, written in @emphx{clean C}, -the common subset of @N{Standard C} and C++. +the common subset of C and C++. The Lua distribution includes a host program called @id{lua}, which uses the Lua library to offer a complete, standalone Lua interpreter, @@ -2957,7 +2957,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, return realloc(ptr, nsize); } } -Note that @N{Standard C} ensures +Note that @N{ISO C} ensures that @T{free(NULL)} has no effect and that @T{realloc(NULL,size)} is equivalent to @T{malloc(size)}. @@ -3644,7 +3644,8 @@ Other upvalues are initialized with @nil. } -@APIEntry{lua_State *lua_newstate (lua_Alloc f, void *ud);| +@APIEntry{lua_State *lua_newstate (lua_Alloc f, void *ud, + unsigned int seed);| @apii{0,0,-} Creates a new independent state and returns its main thread. @@ -3655,6 +3656,8 @@ Lua will do all memory allocation for this state through this function @seeF{lua_Alloc}. The second argument, @id{ud}, is an opaque pointer that Lua passes to the allocator in every call. +The third argument, @id{seed}, is a seed for the hashing of +strings when they are used as table keys. } @@ -5721,6 +5724,16 @@ it does not run it. } +@APIEntry{unsigned int luaL_makeseed (lua_State *L);| +@apii{0,0,-} + +Returns a value with a weak attempt for randomness. +(It produces that value based on the current date and time, +the current processor time, and the address of an internal variable, +in case the machine has Address Space Layout Randomization.) + +} + @APIEntry{void luaL_newlib (lua_State *L, const luaL_Reg l[]);| @apii{0,1,m} @@ -6892,7 +6905,7 @@ including if necessary a path and an extension. @id{funcname} must be the exact name exported by the @N{C library} (which may depend on the @N{C compiler} and linker used). -This function is not supported by @N{Standard C}. +This function is not supported by @N{ISO C}. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the @id{dlfcn} standard). @@ -8093,7 +8106,7 @@ different sequences of results each time the program runs. When called with at least one argument, the integer parameters @id{x} and @id{y} are -joined into a 128-bit @emphx{seed} that +joined into a @emphx{seed} that is used to reinitialize the pseudo-random generator; equal seeds produce equal sequences of numbers. The default for @id{y} is zero.