ソースを参照

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.
Roberto Ierusalimschy 2 年 前
コミット
5a04f1851e
9 ファイル変更87 行追加86 行削除
  1. 49 1
      lauxlib.c
  2. 2 0
      lauxlib.h
  3. 7 17
      lmathlib.c
  4. 2 33
      lstate.c
  5. 3 26
      ltablib.c
  6. 2 2
      ltests.c
  7. 2 1
      ltests.h
  8. 2 1
      lua.h
  9. 18 5
      manual/manual.of

+ 49 - 1
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) {
 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)) {
   if (l_likely(L)) {
     lua_atpanic(L, &panic);
     lua_atpanic(L, &panic);
     lua_setwarnf(L, warnfoff, L);  /* default is warnings off */
     lua_setwarnf(L, warnfoff, L);  /* default is warnings off */

+ 2 - 0
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 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 lua_Integer (luaL_len) (lua_State *L, int idx);
 
 
 LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
 LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,

+ 7 - 17
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) {
 static int math_randomseed (lua_State *L) {
   RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
   RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
+  lua_Unsigned n1, n2;
   if (lua_isnone(L, 1)) {
   if (lua_isnone(L, 1)) {
-    randseed(L, state);
+    n1 = luaL_makeseed(L);
+    n2 = I2UInt(state->s[0]);
   }
   }
   else {
   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 */
   return 2;  /* return seeds */
 }
 }
 
 
@@ -641,7 +631,7 @@ static const luaL_Reg randfuncs[] = {
 */
 */
 static void setrandfunc (lua_State *L) {
 static void setrandfunc (lua_State *L) {
   RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
   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 */
   lua_pop(L, 2);  /* remove pushed seeds */
   luaL_setfuncs(L, randfuncs, 1);
   luaL_setfuncs(L, randfuncs, 1);
 }
 }

+ 2 - 33
lstate.c

@@ -51,37 +51,6 @@ typedef struct LG {
 #define fromstate(L)	(cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
 #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)
 ** set GCdebt to a new value keeping the value (totalobjs + GCdebt)
 ** invariant (and avoiding underflows in 'totalobjs')
 ** 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;
   int i;
   lua_State *L;
   lua_State *L;
   global_State *g;
   global_State *g;
@@ -370,7 +339,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->warnf = NULL;
   g->warnf = NULL;
   g->ud_warn = NULL;
   g->ud_warn = NULL;
   g->mainthread = L;
   g->mainthread = L;
-  g->seed = luai_makeseed(L);
+  g->seed = seed;
   g->gcstp = GCSTPGC;  /* no GC while building state */
   g->gcstp = GCSTPGC;  /* no GC while building state */
   g->strt.size = g->strt.nuse = 0;
   g->strt.size = g->strt.nuse = 0;
   g->strt.hash = NULL;
   g->strt.hash = NULL;

+ 3 - 26
ltablib.c

@@ -230,31 +230,8 @@ typedef unsigned int IdxT;
 ** of a partition. (If you don't want/need this "randomness", ~0 is a
 ** of a partition. (If you don't want/need this "randomness", ~0 is a
 ** good choice.)
 ** 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					/* } */
 #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) */
       up = p - 1;  /* tail call for [lo .. p - 1]  (lower interval) */
     }
     }
     if ((up - lo) / 128 > n) /* partition too imbalanced? */
     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) */
   }  /* tail call auxsort(L, lo, up, rnd) */
 }
 }
 
 

+ 2 - 2
ltests.c

@@ -1159,7 +1159,7 @@ static int num2int (lua_State *L) {
 static int newstate (lua_State *L) {
 static int newstate (lua_State *L) {
   void *ud;
   void *ud;
   lua_Alloc f = lua_getallocf(L, &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) {
   if (L1) {
     lua_atpanic(L1, tpanic);
     lua_atpanic(L1, tpanic);
     lua_pushlightuserdata(L, L1);
     lua_pushlightuserdata(L, L1);
@@ -1252,7 +1252,7 @@ static int checkpanic (lua_State *L) {
   lua_Alloc f = lua_getallocf(L, &ud);
   lua_Alloc f = lua_getallocf(L, &ud);
   b.paniccode = luaL_optstring(L, 2, "");
   b.paniccode = luaL_optstring(L, 2, "");
   b.L = L;
   b.L = L;
-  L1 = lua_newstate(f, ud);  /* create new state */
+  L1 = lua_newstate(f, ud, 0);  /* create new state */
   if (L1 == NULL) {  /* error? */
   if (L1 == NULL) {  /* error? */
     lua_pushnil(L);
     lua_pushnil(L);
     return 1;
     return 1;

+ 2 - 1
ltests.h

@@ -102,7 +102,8 @@ LUA_API void *debug_realloc (void *ud, void *block,
                              size_t osize, size_t nsize);
                              size_t osize, size_t nsize);
 
 
 #if defined(lua_c)
 #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)  \
 #define luai_openlibs(L)  \
   {  luaL_openlibs(L); \
   {  luaL_openlibs(L); \
      luaL_requiref(L, "T", luaB_opentests, 1); \
      luaL_requiref(L, "T", luaB_opentests, 1); \

+ 2 - 1
lua.h

@@ -160,7 +160,8 @@ extern const char lua_ident[];
 /*
 /*
 ** state manipulation
 ** 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 void       (lua_close) (lua_State *L);
 LUA_API lua_State *(lua_newthread) (lua_State *L);
 LUA_API lua_State *(lua_newthread) (lua_State *L);
 LUA_API int        (lua_resetthread) (lua_State *L, lua_State *from);
 LUA_API int        (lua_resetthread) (lua_State *L, lua_State *from);

+ 18 - 5
manual/manual.of

@@ -20,7 +20,7 @@ making it ideal for configuration, scripting,
 and rapid prototyping.
 and rapid prototyping.
 
 
 Lua is implemented as a library, written in @emphx{clean C},
 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},
 The Lua distribution includes a host program called @id{lua},
 which uses the Lua library to offer a complete,
 which uses the Lua library to offer a complete,
 standalone Lua interpreter,
 standalone Lua interpreter,
@@ -2957,7 +2957,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize,
     return realloc(ptr, nsize);
     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
 that @T{free(NULL)} has no effect and that
 @T{realloc(NULL,size)} is equivalent to @T{malloc(size)}.
 @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,-}
 @apii{0,0,-}
 
 
 Creates a new independent state and returns its main thread.
 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}.
 through this function @seeF{lua_Alloc}.
 The second argument, @id{ud}, is an opaque pointer that Lua
 The second argument, @id{ud}, is an opaque pointer that Lua
 passes to the allocator in every call.
 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[]);|
 @APIEntry{void luaL_newlib (lua_State *L, const luaL_Reg l[]);|
 @apii{0,1,m}
 @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}
 @id{funcname} must be the exact name exported by the @N{C library}
 (which may depend on the @N{C compiler} and linker used).
 (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
 As such, it is only available on some platforms
 (Windows, Linux, Mac OS X, Solaris, BSD,
 (Windows, Linux, Mac OS X, Solaris, BSD,
 plus other Unix systems that support the @id{dlfcn} standard).
 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,
 When called with at least one argument,
 the integer parameters @id{x} and @id{y} are
 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;
 is used to reinitialize the pseudo-random generator;
 equal seeds produce equal sequences of numbers.
 equal seeds produce equal sequences of numbers.
 The default for @id{y} is zero.
 The default for @id{y} is zero.