From: Petri Lehtinen Date: Wed, 30 Mar 2011 09:57:24 +0000 (+0300) Subject: Fix invalid object key hashing in json_unpack() strict checking mode X-Git-Tag: v2.0.1~2 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=jansson.git;a=commitdiff_plain;h=0944ac8d91ad6a02c44d6166f46c6c0183147976 Fix invalid object key hashing in json_unpack() strict checking mode The keys which are stored temporarily to a hashtable to make sure that all object keys are unpacked, were hashed with the object key hashing function. It is meant to compute hashes for object_key_t values, and it works incorrectly for plain strings. Fixed by introducing suitable functions for hashing and comparing strings for string-keyed hashtables. --- diff --git a/src/jansson_private.h b/src/jansson_private.h index 9224b31..452a4f0 100644 --- a/src/jansson_private.h +++ b/src/jansson_private.h @@ -66,8 +66,8 @@ typedef struct { #define json_to_real(json_) container_of(json_, json_real_t, json) #define json_to_integer(json_) container_of(json_, json_integer_t, json) -size_t jsonp_hash_key(const void *ptr); -int jsonp_key_equal(const void *ptr1, const void *ptr2); +size_t jsonp_hash_str(const void *ptr); +int jsonp_str_equal(const void *ptr1, const void *ptr2); typedef struct { size_t serial; diff --git a/src/pack_unpack.c b/src/pack_unpack.c index 5001764..20d540b 100644 --- a/src/pack_unpack.c +++ b/src/pack_unpack.c @@ -233,7 +233,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) */ hashtable_t key_set; - if(hashtable_init(&key_set, jsonp_hash_key, jsonp_key_equal, NULL, NULL)) { + if(hashtable_init(&key_set, jsonp_hash_str, jsonp_str_equal, NULL, NULL)) { set_error(s, "", "Out of memory"); return -1; } diff --git a/src/value.c b/src/value.c index 937aa95..5d8ae22 100644 --- a/src/value.c +++ b/src/value.c @@ -26,15 +26,10 @@ static JSON_INLINE void json_init(json_t *json, json_type type) /*** object ***/ -/* This macro just returns a pointer that's a few bytes backwards from - string. This makes it possible to pass a pointer to object_key_t - when only the string inside it is used, without actually creating - an object_key_t instance. */ -#define string_to_key(string) container_of(string, object_key_t, key) - -size_t jsonp_hash_key(const void *ptr) +/* From http://www.cse.yorku.ca/~oz/hash.html */ +size_t jsonp_hash_str(const void *ptr) { - const char *str = ((const object_key_t *)ptr)->key; + const char *str = (const char *)ptr; size_t hash = 5381; size_t c; @@ -48,10 +43,26 @@ size_t jsonp_hash_key(const void *ptr) return hash; } -int jsonp_key_equal(const void *ptr1, const void *ptr2) +int jsonp_str_equal(const void *ptr1, const void *ptr2) +{ + return strcmp((const char *)ptr1, (const char *)ptr2) == 0; +} + +/* This macro just returns a pointer that's a few bytes backwards from + string. This makes it possible to pass a pointer to object_key_t + when only the string inside it is used, without actually creating + an object_key_t instance. */ +#define string_to_key(string) container_of(string, object_key_t, key) + +static size_t hash_key(const void *ptr) +{ + return jsonp_hash_str(((const object_key_t *)ptr)->key); +} + +static int key_equal(const void *ptr1, const void *ptr2) { - return strcmp(((const object_key_t *)ptr1)->key, - ((const object_key_t *)ptr2)->key) == 0; + return jsonp_str_equal(((const object_key_t *)ptr1)->key, + ((const object_key_t *)ptr2)->key); } static void value_decref(void *value) @@ -67,7 +78,7 @@ json_t *json_object(void) json_init(&object->json, JSON_OBJECT); if(hashtable_init(&object->hashtable, - jsonp_hash_key, jsonp_key_equal, + hash_key, key_equal, jsonp_free, value_decref)) { jsonp_free(object); diff --git a/test/suites/api/test_unpack.c b/test/suites/api/test_unpack.c index cfc68ea..9426104 100644 --- a/test/suites/api/test_unpack.c +++ b/test/suites/api/test_unpack.c @@ -122,6 +122,13 @@ int main() fail("json_unpack simple array failed"); json_decref(j); + /* object with many items & strict checking */ + j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3); + rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3); + if(rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack object with many items failed"); + json_decref(j); + /* * Invalid cases */ @@ -285,7 +292,7 @@ int main() /* Unpack the same item twice */ j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) - fail("json_unpack object with strict validation failed"); + fail("json_unpack object with strict validation failed"); check_error("1 object item(s) left unpacked", "", 1, 10, 10); json_decref(j);