]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
Issue #927: update the documentation for json_object_iterator to clarify that any... master
authorEric Hawicz <erh+git@nimenees.com>
Sat, 23 May 2026 18:27:32 +0000 (14:27 -0400)
committerEric Hawicz <erh+git@nimenees.com>
Sat, 23 May 2026 18:31:45 +0000 (14:31 -0400)
Update the test to show what kind of changes _are_ allowed.

json_object_iterator.h
tests/test_object_iterator.c

index 86d37343fcba30e5b680cb5c418cf954c13b5ef4..d05f572a299c31aff2d34fea2cfa0a65c0d80d78 100644 (file)
@@ -3,6 +3,7 @@
 * @file json_object_iterator.h
 *
 * Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
+* Copyright (c) 2026 Eric Hawicz
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See COPYING for details.
@@ -37,6 +38,12 @@ extern "C" {
 struct json_object_iterator
 {
        const void *opaque_;
+       // These could be used to make an interator that fails "faster" 
+       // in the face of certain changes to the underlying object, but
+       // would still be vulnerable to skipping entries.
+       // Changing this structure size is an ABI change
+       // const lh_table *table;
+       // size_t begin_size;
 };
 
 /**
@@ -68,10 +75,20 @@ struct json_object;
  */
 JSON_EXPORT struct json_object_iterator json_object_iter_init_default(void);
 
-/** Retrieves an iterator to the first pair of the JSON Object.
- *
- * @warning    Any modification of the underlying pair invalidates all
- *             iterators to that pair.
+/** Retrieves an iterator to the first key/value pair of the JSON Object.
+ *
+ * @warning    Any modification of the fields present on the object
+ *              invalidates all iterators on that object, regardless of
+ *              what key/value pair they are pointing to, other than the
+ *              end iterator.
+ *              Modifications include adding or removing any pair, even if
+ *              set of keys appears unchanged after the modification.
+ *              Modifying *values* is allowed, including replacing a value
+ *              by calling json_object_add(), provided the key already exists.
+ *              Attempting to use an invalidated iterator in any way, other
+ *              than comparing it to the end iterator, is *undefined behavior*.
+ *              Passing such an iterator to any of the the json_object_iterator
+ *              functions is not even guaranteed to fail in any consistent way.
  *
  * @param obj  JSON Object instance (MUST be of type json_object)
  *
@@ -133,8 +150,9 @@ JSON_EXPORT struct json_object_iterator json_object_iter_end(const struct json_o
 
 /** Returns an iterator to the next pair, if any
  *
- * @warning    Any modification of the underlying pair
- *             invalidates all iterators to that pair.
+ * @warning    Any modification of the fields of the object invalidates
+ *             the iterator, see the warning on json_object_iter_begin()
+ *              for details.
  *
  * @param iter [IN/OUT] Pointer to iterator that references a
  *         name/value pair; MUST be a valid, non-end iterator.
@@ -154,8 +172,9 @@ JSON_EXPORT void json_object_iter_next(struct json_object_iterator *iter);
  * @param iter pointer to iterator that references a name/value
  *             pair; MUST be a valid, non-end iterator.
  *
- * @warning    bad things will happen if an invalid or
- *                     "end" iterator is passed.
+ * @warning    bad things will happen if an invalid or "end" iterator
+ *                     is passed.  See the warning on json_object_iter_begin()
+ *              for details.
  *
  * @return const char* Pointer to the name of the referenced
  *         name/value pair.  The name memory belongs to the
@@ -172,8 +191,9 @@ JSON_EXPORT const char *json_object_iter_peek_name(const struct json_object_iter
  * @param iter         pointer to iterator that references a name/value
  *                     pair; MUST be a valid, non-end iterator.
  *
- * @warning    bad things will happen if invalid or
- *             "end" iterator is passed.
+ * @warning    bad things will happen if an invalid or "end" iterator
+ *                     is passed.  See the warning on json_object_iter_begin()
+ *              for details.
  *
  * @return struct json_object* Pointer to the json-c value
  *         instance of the referenced name/value pair;  the
index 4928088e09b3638a0728ccb4424eba4aa99adeb2..2202ed5d7f03a89a129fc133cec58a6c827406fe 100644 (file)
@@ -2,6 +2,7 @@
 #undef NDEBUG
 #endif
 #include "config.h"
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -20,6 +21,7 @@ int main(int atgc, char **argv)
                \"boolean_false\": false,\n\
                \"big_number\": 2147483649,\n\
                \"a_null\": null,\n\
+                \"an_object\": { \"foo\": \"bar\" },\n\
                }";
 
        struct json_object *new_obj;
@@ -31,10 +33,41 @@ int main(int atgc, char **argv)
        it = json_object_iter_begin(new_obj);
        itEnd = json_object_iter_end(new_obj);
 
+       // If this changes size on any platform, it'd break the ABI
+       printf("sizeof(struct json_object_iterator)/sizeof(void *)=%zu\n", sizeof(struct json_object_iterator) / sizeof(void *));
+
        while (!json_object_iter_equal(&it, &itEnd))
        {
-               printf("%s\n", json_object_iter_peek_name(&it));
-               printf("%s\n", json_object_to_json_string(json_object_iter_peek_value(&it)));
+               const char *key = json_object_iter_peek_name(&it);
+               json_object *value = json_object_iter_peek_value(&it);
+               printf("key: %s\n", key);
+               printf("pre change:  %s\n", json_object_to_json_string(value));
+               if (json_object_get_type(value) == json_type_object)
+               {
+                       // Changing sub-objects is ok
+                       assert(json_object_object_add(value, "foo", json_object_new_string("change foo")) == 0);
+                       assert(json_object_object_add(value, "newkey", json_object_new_string("new value")) == 0);
+               }
+               else
+               {
+                       // Changing the value of pairs is ok
+                       assert(json_object_object_add(new_obj, key, json_object_new_string("switched")) == 0);
+               }
+
+               if (0) // DO NOT DO THIS
+               {
+                       // Adding new keys is NOT ok, and invalidates the iterator
+                       json_object_object_add(value, "somenewkey", json_object_new_string("foo"));
+
+                       // Deleting any keys ALSO invalidates the iterator, even if
+                       // the key is immediately re-added.
+                       json_object_object_del(value, key);
+                       json_object_object_add(value, key, json_object_new_string("switched"));
+               }
+
+               value = json_object_iter_peek_value(&it);
+               printf("post change: %s\n", json_object_to_json_string(value));
+
                json_object_iter_next(&it);
        }