Hash always use all characters in a long string

Hashes for long strings are computed only when they are used as keys
in a table, not a too common case. And, in that case, it is to easy to
force collisions changing only the characters which are not part of the
hash.
This commit is contained in:
Roberto Ierusalimschy 2020-10-12 10:02:37 -03:00
parent c23cc86c54
commit 9a89fb1c9d
4 changed files with 6 additions and 20 deletions

View File

@ -76,7 +76,7 @@ static unsigned int luai_makeseed (lua_State *L) {
addbuff(buff, p, &h); /* local variable */ addbuff(buff, p, &h); /* local variable */
addbuff(buff, p, &lua_newstate); /* public function */ addbuff(buff, p, &lua_newstate); /* public function */
lua_assert(p == sizeof(buff)); lua_assert(p == sizeof(buff));
return luaS_hash(buff, p, h, 1); return luaS_hash(buff, p, h);
} }
#endif #endif

View File

@ -22,16 +22,6 @@
#include "lstring.h" #include "lstring.h"
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a long string to
** compute its hash
*/
#if !defined(LUAI_HASHLIMIT)
#define LUAI_HASHLIMIT 5
#endif
/* /*
** Maximum size for string table. ** Maximum size for string table.
*/ */
@ -50,10 +40,9 @@ int luaS_eqlngstr (TString *a, TString *b) {
} }
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed, unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
size_t step) {
unsigned int h = seed ^ cast_uint(l); unsigned int h = seed ^ cast_uint(l);
for (; l >= step; l -= step) for (; l > 0; l--)
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h; return h;
} }
@ -63,8 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_VLNGSTR); lua_assert(ts->tt == LUA_VLNGSTR);
if (ts->extra == 0) { /* no hash? */ if (ts->extra == 0) { /* no hash? */
size_t len = ts->u.lnglen; size_t len = ts->u.lnglen;
size_t step = (len >> LUAI_HASHLIMIT) + 1; ts->hash = luaS_hash(getstr(ts), len, ts->hash);
ts->hash = luaS_hash(getstr(ts), len, ts->hash, step);
ts->extra = 1; /* now it has its hash */ ts->extra = 1; /* now it has its hash */
} }
return ts->hash; return ts->hash;
@ -201,7 +189,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts; TString *ts;
global_State *g = G(L); global_State *g = G(L);
stringtable *tb = &g->strt; stringtable *tb = &g->strt;
unsigned int h = luaS_hash(str, l, g->seed, 1); unsigned int h = luaS_hash(str, l, g->seed);
TString **list = &tb->hash[lmod(h, tb->size)]; TString **list = &tb->hash[lmod(h, tb->size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) { for (ts = *list; ts != NULL; ts = ts->u.hnext) {

View File

@ -41,8 +41,7 @@
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) #define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
unsigned int seed, size_t step);
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC void luaS_resize (lua_State *L, int newsize);

View File

@ -523,7 +523,6 @@ static lu_mem checkgraylist (global_State *g, GCObject *o) {
((void)g); /* better to keep it available if we need to print an object */ ((void)g); /* better to keep it available if we need to print an object */
while (o) { while (o) {
lua_assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); lua_assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
//lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!testbit(o->marked, TESTBIT)); lua_assert(!testbit(o->marked, TESTBIT));
if (keepinvariant(g)) if (keepinvariant(g))
l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */ l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */