commit 5a04f1851e0d42b4bcbb0af103490bc964e985aa
parent 8c064fdc23bd745bbd3456a58cc9e2521f8e4263
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Mon, 20 Mar 2023 16:12:50 -0300
New function 'luaL_makeseed'
This function unifies code from 'lua_newstate', 'math.randomseed',
and 'table.sort' that tries to create a value with a minimum level
of randomness.
Diffstat:
9 files changed, 87 insertions(+), 86 deletions(-)
diff --git 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 <time.h>
+
+
+/*
+** 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
@@ -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
@@ -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
@@ -52,37 +52,6 @@ typedef struct LG {
/*
-** 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 <time.h>
-
-/*
-** 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
@@ -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 <time.h>
-
-/* 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
@@ -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
@@ -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
@@ -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
@@ -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.