diff --git a/src/dump.c b/src/dump.c index 1baa248..7e14db4 100644 --- a/src/dump.c +++ b/src/dump.c @@ -263,7 +263,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par if (!embed && dump("[", 1, data)) return -1; if (n == 0) { - hashtable_del(parents, key); + hashtable_del(parents, key, strlen(key)); return embed ? 0 : dump("]", 1, data); } if (dump_indent(flags, depth + 1, 0, dump, data)) @@ -284,7 +284,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par } } - hashtable_del(parents, key); + hashtable_del(parents, key, strlen(key)); return embed ? 0 : dump("]", 1, data); } @@ -311,7 +311,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par if (!embed && dump("{", 1, data)) return -1; if (!iter) { - hashtable_del(parents, loop_key); + hashtable_del(parents, loop_key, strlen(loop_key)); return embed ? 0 : dump("}", 1, data); } if (dump_indent(flags, depth + 1, 0, dump, data)) @@ -392,7 +392,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par } } - hashtable_del(parents, loop_key); + hashtable_del(parents, loop_key, strlen(loop_key)); return embed ? 0 : dump("}", 1, data); } diff --git a/src/hashtable.c b/src/hashtable.c index fd1e706..743e233 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -35,7 +35,7 @@ extern volatile uint32_t hashtable_seed; #define list_to_pair(list_) container_of(list_, pair_t, list) #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) -#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed)) +#define hash_str(key, len) ((size_t)hashlittle((key), len, hashtable_seed)) static JSON_INLINE void list_init(list_t *list) { list->next = list; @@ -69,7 +69,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *l } static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, - const char *key, size_t hash) { + const char *key, size_t key_len, size_t hash) { list_t *list; pair_t *pair; @@ -79,7 +79,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, list = bucket->first; while (1) { pair = list_to_pair(list); - if (pair->hash == hash && strcmp(pair->key, key) == 0) + if (pair->hash == hash && pair->key_len == key_len && + memcmp(pair->key, key, key_len) == 0) return pair; if (list == bucket->last) @@ -92,7 +93,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, } /* returns 0 on success, -1 if key was not found */ -static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) { +static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len, + size_t hash) { pair_t *pair; bucket_t *bucket; size_t index; @@ -100,7 +102,7 @@ static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash index = hash & hashmask(hashtable->order); bucket = &hashtable->buckets[index]; - pair = hashtable_find_pair(hashtable, bucket, key, hash); + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); if (!pair) return -1; @@ -193,7 +195,37 @@ void hashtable_close(hashtable_t *hashtable) { jsonp_free(hashtable->buckets); } -int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { +static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) { + pair_t *pair; + + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + + if (key_len >= (size_t)-1 - offsetof(pair_t, key)) { + /* Avoid an overflow if the key is very long */ + return NULL; + } + + pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1); + + if (!pair) + return NULL; + + pair->hash = hash; + memcpy(pair->key, key, key_len); + pair->key[key_len] = '\0'; + pair->key_len = key_len; + pair->value = value; + + list_init(&pair->list); + list_init(&pair->ordered_list); + + return pair; +} + +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, + json_t *value) { pair_t *pair; bucket_t *bucket; size_t hash, index; @@ -203,35 +235,20 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { if (hashtable_do_rehash(hashtable)) return -1; - hash = hash_str(key); + hash = hash_str(key, key_len); index = hash & hashmask(hashtable->order); bucket = &hashtable->buckets[index]; - pair = hashtable_find_pair(hashtable, bucket, key, hash); + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); if (pair) { json_decref(pair->value); pair->value = value; } else { - /* offsetof(...) returns the size of pair_t without the last, - flexible member. This way, the correct amount is - allocated. */ + pair = init_pair(value, key, key_len, hash); - size_t len = strlen(key); - if (len >= (size_t)-1 - offsetof(pair_t, key)) { - /* Avoid an overflow if the key is very long */ - return -1; - } - - pair = jsonp_malloc(offsetof(pair_t, key) + len + 1); if (!pair) return -1; - pair->hash = hash; - strncpy(pair->key, key, len + 1); - pair->value = value; - list_init(&pair->list); - list_init(&pair->ordered_list); - insert_to_bucket(hashtable, bucket, &pair->list); list_insert(&hashtable->ordered_list, &pair->ordered_list); @@ -240,24 +257,24 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { return 0; } -void *hashtable_get(hashtable_t *hashtable, const char *key) { +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) { pair_t *pair; size_t hash; bucket_t *bucket; - hash = hash_str(key); + hash = hash_str(key, key_len); bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; - pair = hashtable_find_pair(hashtable, bucket, key, hash); + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); if (!pair) return NULL; return pair->value; } -int hashtable_del(hashtable_t *hashtable, const char *key) { - size_t hash = hash_str(key); - return hashtable_do_del(hashtable, key, hash); +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) { + size_t hash = hash_str(key, key_len); + return hashtable_do_del(hashtable, key, key_len, hash); } void hashtable_clear(hashtable_t *hashtable) { @@ -278,15 +295,15 @@ void *hashtable_iter(hashtable_t *hashtable) { return hashtable_iter_next(hashtable, &hashtable->ordered_list); } -void *hashtable_iter_at(hashtable_t *hashtable, const char *key) { +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) { pair_t *pair; size_t hash; bucket_t *bucket; - hash = hash_str(key); + hash = hash_str(key, key_len); bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; - pair = hashtable_find_pair(hashtable, bucket, key, hash); + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); if (!pair) return NULL; diff --git a/src/hashtable.h b/src/hashtable.h index 6c4845d..6defa00 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -24,6 +24,7 @@ struct hashtable_pair { struct hashtable_list ordered_list; size_t hash; json_t *value; + size_t key_len; char key[1]; }; @@ -69,6 +70,7 @@ void hashtable_close(hashtable_t *hashtable); * * @hashtable: The hashtable object * @key: The key + * @key: The length of key * @serial: For addition order of keys * @value: The value * @@ -79,27 +81,29 @@ void hashtable_close(hashtable_t *hashtable); * * Returns 0 on success, -1 on failure (out of memory). */ -int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value); +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value); /** * hashtable_get - Get a value associated with a key * * @hashtable: The hashtable object * @key: The key + * @key: The length of key * * Returns value if it is found, or NULL otherwise. */ -void *hashtable_get(hashtable_t *hashtable, const char *key); +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len); /** * hashtable_del - Remove a value from the hashtable * * @hashtable: The hashtable object * @key: The key + * @key: The length of key * * Returns 0 on success, or -1 if the key was not found. */ -int hashtable_del(hashtable_t *hashtable, const char *key); +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len); /** * hashtable_clear - Clear hashtable @@ -132,11 +136,12 @@ void *hashtable_iter(hashtable_t *hashtable); * * @hashtable: The hashtable object * @key: The key that the iterator should point to + * @key: The length of key * * Like hashtable_iter() but returns an iterator pointing to a * specific key. */ -void *hashtable_iter_at(hashtable_t *hashtable, const char *key); +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len); /** * hashtable_iter_next - Advance an iterator diff --git a/src/pack_unpack.c b/src/pack_unpack.c index a89be58..04c116e 100644 --- a/src/pack_unpack.c +++ b/src/pack_unpack.c @@ -544,7 +544,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { if (unpack(s, value, ap)) goto out; - hashtable_set(&key_set, key, json_null()); + hashtable_set(&key_set, key, strlen(key), json_null()); next_token(s); } @@ -554,6 +554,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { if (root && strict == 1) { /* We need to check that all non optional items have been parsed */ const char *key; + size_t key_len; /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ int keys_res = 1; strbuffer_t unrecognized_keys; @@ -562,7 +563,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { if (gotopt || json_object_size(root) != key_set.size) { json_object_foreach(root, key, value) { - if (!hashtable_get(&key_set, key)) { + key_len = strlen(key); + if (!hashtable_get(&key_set, key, key_len)) { unpacked++; /* Save unrecognized keys for the error message */ @@ -574,7 +576,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { if (!keys_res) keys_res = - strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); + strbuffer_append_bytes(&unrecognized_keys, key, key_len); } } } diff --git a/src/value.c b/src/value.c index c85a0b4..e46d14f 100644 --- a/src/value.c +++ b/src/value.c @@ -46,11 +46,12 @@ static JSON_INLINE void json_init(json_t *json, json_type type) { int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size) { - snprintf(key, key_size, "%p", json); - if (hashtable_get(parents, key)) + size_t key_len = snprintf(key, key_size, "%p", json); + + if (hashtable_get(parents, key, key_len)) return -1; - return hashtable_set(parents, key, json_null()); + return hashtable_set(parents, key, key_len, json_null()); } /*** object ***/ @@ -99,7 +100,7 @@ json_t *json_object_get(const json_t *json, const char *key) { return NULL; object = json_to_object(json); - return hashtable_get(&object->hashtable, key); + return hashtable_get(&object->hashtable, key, strlen(key)); } int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { @@ -114,7 +115,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { } object = json_to_object(json); - if (hashtable_set(&object->hashtable, key, value)) { + if (hashtable_set(&object->hashtable, key, strlen(key), value)) { json_decref(value); return -1; } @@ -138,7 +139,7 @@ int json_object_del(json_t *json, const char *key) { return -1; object = json_to_object(json); - return hashtable_del(&object->hashtable, key); + return hashtable_del(&object->hashtable, key, strlen(key)); } int json_object_clear(json_t *json) { @@ -226,7 +227,7 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren } } - hashtable_del(parents, loop_key); + hashtable_del(parents, loop_key, strlen(loop_key)); return res; } @@ -260,7 +261,7 @@ void *json_object_iter_at(json_t *json, const char *key) { return NULL; object = json_to_object(json); - return hashtable_iter_at(&object->hashtable, key); + return hashtable_iter_at(&object->hashtable, key, strlen(key)); } void *json_object_iter_next(json_t *json, void *iter) { @@ -366,7 +367,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents) } out: - hashtable_del(parents, loop_key); + hashtable_del(parents, loop_key, strlen(loop_key)); return result; } @@ -651,7 +652,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) { } out: - hashtable_del(parents, loop_key); + hashtable_del(parents, loop_key, strlen(loop_key)); return result; }