Skip to content

Commit 134c11f

Browse files
committed
Move Map hash seed to runtime
Map and Set objects can be accessed from a context other than the one that created them. With a per-context hash seed, insertion and lookup may select different buckets. Store the seed on JSRuntime so every context sharing these objects uses the same hash seed. Signed-off-by: Yan-Jie Wang <yanjiewtw@gmail.com>
1 parent 02368b6 commit 134c11f

2 files changed

Lines changed: 60 additions & 3 deletions

File tree

‎api-test.c‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,58 @@ static void get_class_name(void)
20582058
JS_FreeRuntime(rt);
20592059
}
20602060

2061+
static void map_set_cross_context(void)
2062+
{
2063+
static const char create_source[] =
2064+
"({"
2065+
" map: new Map(Array.from({length: 1024}, (_, i) => ['key' + i, i])),"
2066+
" set: new Set(Array.from({length: 1024}, (_, i) => 'key' + i))"
2067+
"})";
2068+
static const char check_source[] =
2069+
"(() => {"
2070+
" for (let i = 0; i < 1024; i++) {"
2071+
" const key = 'key' + i;"
2072+
" if (Map.prototype.get.call(foreign.map, key) !== i) return false;"
2073+
" if (!Set.prototype.has.call(foreign.set, key)) return false;"
2074+
" }"
2075+
" return true;"
2076+
"})()";
2077+
JSRuntime *rt = new_runtime();
2078+
JSContext *owner_ctx = JS_NewContext(rt);
2079+
JSValue containers = eval(owner_ctx, create_source);
2080+
int i;
2081+
2082+
assert(!JS_IsException(containers));
2083+
for (i = 0; i < 4; i++) {
2084+
uint64_t deadline = js__gettimeofday_us() + 1000;
2085+
JSContext *caller_ctx;
2086+
JSValue global, result;
2087+
2088+
while (js__gettimeofday_us() < deadline) {
2089+
}
2090+
caller_ctx = JS_NewContext(rt);
2091+
global = JS_GetGlobalObject(caller_ctx);
2092+
assert(JS_SetPropertyStr(caller_ctx, global, "foreign",
2093+
JS_DupValue(caller_ctx, containers)) >= 0);
2094+
JS_FreeValue(caller_ctx, global);
2095+
2096+
result = eval(caller_ctx, check_source);
2097+
assert(!JS_IsException(result));
2098+
assert(JS_IsBool(result));
2099+
assert(JS_VALUE_GET_BOOL(result));
2100+
JS_FreeValue(caller_ctx, result);
2101+
2102+
result = eval(caller_ctx, "globalThis.foreign = undefined");
2103+
assert(!JS_IsException(result));
2104+
JS_FreeValue(caller_ctx, result);
2105+
JS_FreeContext(caller_ctx);
2106+
}
2107+
2108+
JS_FreeValue(owner_ctx, containers);
2109+
JS_FreeContext(owner_ctx);
2110+
JS_FreeRuntime(rt);
2111+
}
2112+
20612113
void object_from(void)
20622114
{
20632115
JSRuntime *rt = new_runtime();
@@ -2153,6 +2205,7 @@ int main(void)
21532205
resize_external_array_buffer();
21542206
transfer_default_managed_array_buffer();
21552207
get_class_name();
2208+
map_set_cross_context();
21562209
object_from();
21572210
add_intrinsic_bigint();
21582211
new_typed_array();

‎quickjs.c‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ struct JSRuntime {
339339
JSMallocState malloc_state;
340340
JSArenaState arena_state;
341341
const char *rt_info;
342+
uint32_t hash_seed;
342343

343344
int atom_hash_size; /* power of two */
344345
int atom_count;
@@ -602,7 +603,6 @@ struct JSContext {
602603
double time_origin;
603604

604605
uint64_t random_state;
605-
uint32_t hash_seed;
606606

607607
/* when the counter reaches zero, JSRutime.interrupt_handler is called */
608608
int interrupt_counter;
@@ -2315,6 +2315,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
23152315
{
23162316
JSRuntime *rt;
23172317
JSMallocState ms;
2318+
uint64_t random_state;
23182319

23192320
memset(&ms, 0, sizeof(ms));
23202321
ms.opaque = opaque;
@@ -2334,6 +2335,10 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
23342335
rt->malloc_state = ms;
23352336
js_arena_init(rt);
23362337
rt->malloc_gc_threshold = 256 * 1024;
2338+
random_state = js__gettimeofday_us();
2339+
if (random_state == 0)
2340+
random_state = 1;
2341+
rt->hash_seed = xorshift64star(&random_state);
23372342

23382343
init_list_head(&rt->context_list);
23392344
init_list_head(&rt->gc_obj_list);
@@ -2885,7 +2890,6 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
28852890
// the state must be non zero
28862891
if (ctx->random_state == 0)
28872892
ctx->random_state = 1;
2888-
ctx->hash_seed = xorshift64star(&ctx->random_state);
28892893

28902894
if (JS_AddIntrinsicBasicObjects(ctx)) {
28912895
JS_FreeContext(ctx);
@@ -53362,7 +53366,7 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
5336253366
h = 0;
5336353367
break;
5336453368
}
53365-
return h ^ ctx->hash_seed ^ hash32(tag);
53369+
return h ^ ctx->rt->hash_seed ^ hash32(tag);
5336653370
}
5336753371

5336853372
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,

0 commit comments

Comments
 (0)