diff --git a/src/hash.c b/src/hash.c index bd3892e..67f0018 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,6 +16,7 @@ this program. If not, see . */ #include "makeint.h" #include "hash.h" +#include #define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n))) #define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n))) @@ -410,10 +411,13 @@ unsigned jhash(unsigned const char *k, int length) #ifdef WORDS_BIGENDIAN /* The ifs are ordered from the first byte in memory to the last. */ -#define sum_up_to_nul(r, p, flag) \ +#define sum_up_to_nul(r, p, plen, flag) \ do { \ - unsigned int val; \ - memcpy(&val, (p), 4); \ + unsigned int val = 0; \ + size_t vsz = sizeof (val); \ + size_t pn = (plen); \ + size_t n = pn < vsz ? pn : vsz; \ + memcpy(&val, (p), n); \ if ((val & 0xFF000000) == 0) \ flag = 1; \ else if ((val & 0xFF0000) == 0) \ @@ -427,11 +431,14 @@ unsigned jhash(unsigned const char *k, int length) /* First detect the presence of zeroes. If there is none, we can sum the 4 bytes directly. Otherwise, the ifs are ordered as in the big endian case, from the first byte in memory to the last. */ -#define sum_up_to_nul(r, p, flag) \ +#define sum_up_to_nul(r, p, plen, flag) \ do { \ - unsigned int val; \ + unsigned int val = 0; \ + size_t vsz = sizeof (val); \ + size_t pn = (plen); \ + size_t n = pn < vsz ? pn : vsz; \ unsigned int zeroes; \ - memcpy(&val, (p), 4); \ + memcpy(&val, (p), n); \ zeroes = ((val - 0x01010101) & ~val); \ if (!(zeroes & 0x80808080)) \ r += val; \ @@ -454,24 +461,31 @@ unsigned jhash_string(unsigned const char *k) unsigned int a, b, c; unsigned int have_nul = 0; unsigned const char *start = k; + size_t klen = strlen(k); /* Set up the internal state */ a = b = c = JHASH_INITVAL; /* All but the last block: affect some 32 bits of (a,b,c) */ for (;;) { - sum_up_to_nul(a, k, have_nul); + sum_up_to_nul(a, k, klen, have_nul); if (have_nul) break; k += 4; - sum_up_to_nul(b, k, have_nul); + assert (klen >= 4); + klen -= 4; + sum_up_to_nul(b, k, klen, have_nul); if (have_nul) break; k += 4; - sum_up_to_nul(c, k, have_nul); + assert (klen >= 4); + klen -= 4; + sum_up_to_nul(c, k, klen, have_nul); if (have_nul) break; k += 4; + assert (klen >= 4); + klen -= 4; jhash_mix(a, b, c); }