← Commit list

32c6bd5303

Joshua Rogers
Joshua Rogers
2026-09-15
SUCCESS Duration: 404s

Subject

hash: vary bucket placement across process runs

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/easy.c+5 -0
@@ -177,6 +177,11 @@ static CURLcode global_init(long flags, bool memoryfuncs)
goto fail;
}
+ if(Curl_hash_global_init()) {
+ DEBUGF(curl_mfprintf(stderr, "Error: Curl_hash_global_init failed\n"));
+ goto fail;
+ }
+
if(!Curl_vquic_init()) {
DEBUGF(curl_mfprintf(stderr, "Error: Curl_vquic_init failed\n"));
goto fail;
lib/hash.c+44 -3
@@ -26,6 +26,7 @@
#include <stddef.h> /* for offsetof() */
#include "hash.h"
+#include "rand.h"
/* random patterns for API verification */
#ifdef DEBUGBUILD
@@ -52,14 +53,46 @@ struct hash_functions {
comp_function compare;
};
+/* set at global init, read-only afterwards */
+static size_t hash_seed;
+
+CURLcode Curl_hash_global_init(void)
+{
+ static bool seeded;
+ unsigned char buf[sizeof(size_t)];
+ size_t seed = 0;
+ size_t i;
+ CURLcode result;
+
+ if(seeded)
+ return CURLE_OK;
+
+ result = Curl_rand_bytes(NULL,
+#ifdef DEBUGBUILD
+ FALSE,
+#endif
+ buf, sizeof(buf));
+ if(result)
+ return result;
+
+ for(i = 0; i < sizeof(buf); i++)
+ seed = (seed << 8) | buf[i];
+
+ hash_seed = seed ? seed : 1;
+ seeded = TRUE;
+ return CURLE_OK;
+}
+
/* @unittest 1603
*/
-UNITTEST size_t hash_str(const void *key, size_t key_length, size_t slots_num);
-UNITTEST size_t hash_str(const void *key, size_t key_length, size_t slots_num)
+UNITTEST size_t hash_str_seeded(const void *key, size_t key_length,
+ size_t slots_num, size_t seed);
+UNITTEST size_t hash_str_seeded(const void *key, size_t key_length,
+ size_t slots_num, size_t seed)
{
const char *key_str = (const char *)key;
const char *end = key_str + key_length;
- size_t h = 5381;
+ size_t h = 5381 ^ seed;
while(key_str < end) {
size_t j = (size_t)*key_str++;
@@ -70,6 +103,14 @@ UNITTEST size_t hash_str(const void *key, size_t key_length, size_t slots_num)
return (h % slots_num);
}
+/* @unittest 1603
+ */
+UNITTEST size_t hash_str(const void *key, size_t key_length, size_t slots_num);
+UNITTEST size_t hash_str(const void *key, size_t key_length, size_t slots_num)
+{
+ return hash_str_seeded(key, key_length, slots_num, hash_seed);
+}
+
/* Avoid treating the variable-length key[1] as a one-byte object. */
static char *hash_elem_key(struct Curl_hash_element *he)
{
lib/hash.h+2 -0
@@ -65,6 +65,8 @@ struct Curl_hash_iterator {
#endif
};
+CURLcode Curl_hash_global_init(void);
+
void Curl_hash_init(struct Curl_hash *h,
size_t slots,
Curl_hash_type type,
lib/rand.h+2 -0
@@ -23,6 +23,8 @@
* SPDX-License-Identifier: curl
*
***************************************************************************/
+struct Curl_easy;
+
CURLcode Curl_rand_bytes(struct Curl_easy *data,
#ifdef DEBUGBUILD
bool env_override,
tests/unit/unit1603.c+3 -0
@@ -122,6 +122,9 @@ static CURLcode test_unit1603(const char *arg)
const char *nodep;
int rc;
+ fail_unless(hash_str_seeded("a", 1, 97, 0x1234) == 95,
+ "seeded hash is not computed as expected");
+
/* Ensure the key hashes are as expected in order to test both hash
collisions and a full table. Unfortunately, the hashes can vary
between architectures. */