From 38a7e4faf1d9e78a02e4129e84ca3443b699dea7 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 28 Jan 2019 11:50:33 -0500 Subject: [PATCH] Disallow NaN as table/struct key. Fix bugs and add tests for denormalized tables and structs. --- Makefile | 2 +- src/core/struct.c | 16 ++++------------ src/core/table.c | 1 + test/suite0.janet | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index f13aeee1..6143a664 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ dist: build/janet-dist.tar.gz build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \ janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) \ - build/doc.html README.md + build/doc.html README.md build/janet.c tar -czvf $@ $^ ######################### diff --git a/src/core/struct.c b/src/core/struct.c index 7481fab9..731e35da 100644 --- a/src/core/struct.c +++ b/src/core/struct.c @@ -73,6 +73,7 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) { int32_t i, j, dist; int32_t bounds[4] = {index, cap, 0, index}; if (janet_checktype(key, JANET_NIL) || janet_checktype(value, JANET_NIL)) return; + if (janet_checktype(key, JANET_NUMBER) && isnan(janet_unwrap_number(key))) return; /* Avoid extra items */ if (janet_struct_hash(st) == janet_struct_length(st)) return; for (dist = 0, j = 0; j < 4; j += 2) @@ -120,9 +121,7 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) { dist = otherdist; hash = otherhash; } else if (status == 0) { - /* This should not happen - it means - * than a key was added to the struct more than once */ - janet_exit("struct double put fail"); + /* A key was added to the struct more than once */ return; } } @@ -134,15 +133,8 @@ const JanetKV *janet_struct_end(JanetKV *st) { /* Error building struct, probably duplicate values. We need to rebuild * the struct using only the values that went in. The second creation should always * succeed. */ - int32_t i, realCount; - JanetKV *newst; - realCount = 0; - for (i = 0; i < janet_struct_capacity(st); i++) { - JanetKV *kv = st + i; - realCount += janet_checktype(kv->key, JANET_NIL) ? 1 : 0; - } - newst = janet_struct_begin(realCount); - for (i = 0; i < janet_struct_capacity(st); i++) { + JanetKV *newst = janet_struct_begin(janet_struct_hash(st)); + for (int32_t i = 0; i < janet_struct_capacity(st); i++) { JanetKV *kv = st + i; if (!janet_checktype(kv->key, JANET_NIL)) { janet_struct_put(newst, kv->key, kv->value); diff --git a/src/core/table.c b/src/core/table.c index 3e435c33..a63f2430 100644 --- a/src/core/table.c +++ b/src/core/table.c @@ -131,6 +131,7 @@ Janet janet_table_remove(JanetTable *t, Janet key) { /* Put a value into the object */ void janet_table_put(JanetTable *t, Janet key, Janet value) { if (janet_checktype(key, JANET_NIL)) return; + if (janet_checktype(key, JANET_NUMBER) && isnan(janet_unwrap_number(key))) return; if (janet_checktype(value, JANET_NIL)) { janet_table_remove(t, key); } else { diff --git a/test/suite0.janet b/test/suite0.janet index f9cb47fe..32bc58b6 100644 --- a/test/suite0.janet +++ b/test/suite0.janet @@ -283,5 +283,22 @@ (++ i)) (assert (= i 6) "when macro")) +# Denormal tables and structs + +(assert (= (length {1 2 nil 3}) 1) "nil key struct literal") +(assert (= (length @{1 2 nil 3}) 1) "nil key table literal") +(assert (= (length (struct 1 2 nil 3)) 1) "nil key struct ctor") +(assert (= (length (table 1 2 nil 3)) 1) "nil key table ctor") + +(assert (= (length (struct (/ 0 0) 2 1 3)) 1) "nan key struct ctor") +(assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor") +(assert (= (length {1 2 nil 3}) 1) "nan key struct literal") +(assert (= (length @{1 2 nil 3}) 1) "nan key table literal") + +(assert (= (length (struct 2 1 3 nil)) 1) "nil value struct ctor") +(assert (= (length (table 2 1 3 nil)) 1) "nil value table ctor") +(assert (= (length {1 2 3 nil}) 1) "nil value struct literal") +(assert (= (length @{1 2 3 nil}) 1) "nil value table literal") + (end-suite)