mirror of
https://github.com/lua/lua
synced 2024-12-27 12:49:43 +03:00
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.
This commit is contained in:
parent
8c064fdc23
commit
5a04f1851e
50
lauxlib.c
50
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 */
|
||||
|
@ -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,
|
||||
|
24
lmathlib.c
24
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);
|
||||
}
|
||||
|
35
lstate.c
35
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 <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;
|
||||
|
29
ltablib.c
29
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) */
|
||||
}
|
||||
|
||||
|
4
ltests.c
4
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;
|
||||
|
3
ltests.h
3
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); \
|
||||
|
3
lua.h
3
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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user