From 4c9db198db68f4b9a49ed7152f72c0149b898323 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 17 Feb 2026 12:26:52 -0600 Subject: [PATCH] fix string hash bug --- package.cm | 21 --------------------- source/runtime.c | 24 ++++++++++++++++++++---- toml.cm | 8 ++++---- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/package.cm b/package.cm index b7c4641b..a73e57eb 100644 --- a/package.cm +++ b/package.cm @@ -63,27 +63,6 @@ package.load_config = function(name) return {} } - // Validate: if content has [compilation] but decode result doesn't, retry - var has_compilation = search(content, '[compilation') != null - var retry = 0 - var cf = null - if (has_compilation && !result.compilation) { - print(`TOML decode missing compilation for ${config_path}, retrying`) - while (retry < 3 && (!result || !result.compilation)) { - result = toml.decode(content) - retry = retry + 1 - } - if (!result) return {} - } - - if (has_compilation && result.compilation) { - cf = result.compilation.CFLAGS - if (cf == null && search(content, 'CFLAGS') != null) { - print(`TOML has CFLAGS text but decode missing it for ${config_path}`) - print(`compilation keys: ${text(array(result.compilation), ',')}`) - } - } - config_cache[cache_key] = result return result } diff --git a/source/runtime.c b/source/runtime.c index c2430c88..cb7fa421 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -526,7 +526,7 @@ JS_BOOL js_key_equal_str (JSValue a, const char *str) { } if (!JS_IsPtr (a)) return FALSE; - JSText *ta = (JSText *)JS_VALUE_GET_PTR (a); + JSText *ta = (JSText *)chase (a); if (objhdr_type (ta->hdr) != OBJ_TEXT) return FALSE; uint64_t txt_len = objhdr_cap56 (ta->hdr); if (txt_len != len) return FALSE; @@ -704,6 +704,16 @@ int rec_set_own (JSContext *ctx, JSValue *pobj, JSValue k, JSValue val) { rec->slots[insert_slot].val = val; rec->len++; +#ifdef VALIDATE_GC + /* Verify the just-inserted key is findable */ + int verify = rec_find_slot (rec, k); + if (verify <= 0) { + fprintf (stderr, "rec_set_own: INSERTED KEY NOT FINDABLE! slot=%d insert_slot=%d len=%u\n", + verify, insert_slot, (uint32_t)rec->len); + abort (); + } +#endif + return 0; } @@ -1873,6 +1883,12 @@ JSText *js_alloc_string (JSContext *ctx, int max_len) { /* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */ str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false); str->length = 0; /* length starts at 0, capacity is in hdr */ + /* Zero packed data so odd-length strings have deterministic padding. + js_malloc is a bump allocator and does not zero memory; without this, + the last word's unused low 32 bits contain garbage, causing + fash64_hash_words and JSText_equal (memcmp) to produce inconsistent + results for different allocations of the same text content. */ + memset (str->packed, 0, data_words * sizeof (uint64_t)); return str; } @@ -3514,9 +3530,9 @@ JSValue JS_GetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key) { return JS_GetProperty (ctx, this_obj, key); } -/* CAUTION: rec_set_own is NOT GC-safe if rec_resize is implemented. - Currently safe because rec_resize always fails. - When resize is implemented, rec pointer may become stale. */ +/* rec_set_own calls rec_resize which can move the record. + JS_SetProperty uses a local copy so the caller's JSValue is NOT updated; + the VM must call mach_resolve_forward after store operations. */ int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key, JSValue val) { if (JS_IsRecord (key)) { if (!JS_IsRecord (this_obj)) { diff --git a/toml.cm b/toml.cm index 1ba4ba3c..6a8e1a7c 100644 --- a/toml.cm +++ b/toml.cm @@ -87,8 +87,8 @@ function parse_toml(toml_text) { if (current_section[key] == null) return null } else if (value == 'true' || value == 'false') { current_section[key] = value == 'true' - } else if (is_number(value)) { - current_section[key] = Number(value) + } else if (number(value) != null) { + current_section[key] = number(value) } else { // Unquoted string current_section[key] = value @@ -187,8 +187,8 @@ function parse_value(str) { } if (str == 'true' || str == 'false') return str == 'true' - // Use your existing numeric test; TOML numeric formats are richer, but this keeps your "module TOML" scope. - if (!isNaN(Number(str))) return Number(str) + var n = number(str) + if (n != null) return n return str }