fix: sel_key_cmp_fn padding-byte mismatch in kvtab lookups

sel_key_cmp_fn compared keys with memcmp on the whole sel_node_key_t
struct, including the 4-byte padding between type and op1.  The stack-
allocated search key in gc_sweep_select_nodes can have different padding
bytes than the heap-allocated copy stored by key_add, causing key_del
to miss the entry and leave a dangling pointer in the CSE intern table.

Replace memcmp with field-by-field comparison on type, op1, op2.

Also fix GC sweep tests that asserted pointer inequality after re-intern:
calloc may lawfully reuse the freed address, so pointer inequality does
not reliably indicate a successful sweep.  Track the swept node's
node_id before freeing and assert the re-interned node gets a fresh id.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-05-12 09:53:59 +00:00
parent 3e652d2d7e
commit 450a4d467c
2 changed files with 25 additions and 11 deletions

View file

@ -98,7 +98,16 @@ static uint32_t sel_key_hash_fn(void* k)
static int sel_key_cmp_fn(void* a, void* b)
{
return memcmp(a, b, sizeof(sel_node_key_t));
/* Field-by-field comparison: memcmp on the whole struct would
* compare padding bytes between type and op1, which can differ
* between the stack-local search key and the heap-allocated copy
* stored in the kvtab, causing false misses in key_del. */
sel_node_key_t* ka = (sel_node_key_t*)a;
sel_node_key_t* kb = (sel_node_key_t*)b;
if (ka->type != kb->type) return 1;
if (ka->op1 != kb->op1) return 1;
if (ka->op2 != kb->op2) return 1;
return 0;
}
static int sel_key_assign_fn(void** dst, void* src)