Commit Graph
12 Commits
Author SHA1 Message Date
Javid Khan 46f0355925 pass the add flag to the array callback for json_patch copy 2026-11-08 23:47:51 -05:00
EminY cdd8db0530 json_patch: treat an empty "from" as a parent of any "path"
Since the token-boundary check for the parent/child test (1b504e2), an
empty "from" (the root) only counts as a prefix of "path" when "path"
starts with '/'. With an invalid "path" like "a", a move from "" went
on to remove the root: __json_patch_apply_remove() dropped a reference
to the document, the following set failed on the bad path, and the
error path dropped the last reference, so *base was freed while the
caller still owned it (use-after-free / double free in
json_object_put()).

The root is a parent of every other location, so an empty "from" now
always takes the parent/child branch: a no-op for "path": "" and
EINVAL otherwise. This also restores the invariant the comment below
relies on, that json_pointer can't find the root here.

Added move and copy cases to json_patch_tests.json and regenerated
test_json_patch.expected.
2026-11-08 21:27:08 -05:00
Treston Cuzzort ea3756e561 json_patch: compare integer and double test values numerically
RFC 6902 section 4.6 compares JSON numbers by value. The test operation
used json_object_equal(), which treats json_type_int and json_type_double
as different types, so a test of 1.0 against 1 failed.

Use a private comparison for JSON Patch, including numbers nested inside
objects and arrays. Check floating-point range before converting, and
require both integer equality and an exact round trip to reject fractional
values and large integers that would round to the same double.

Add regression cases for both argument orders, nested values, signed and
unsigned limits, fractional values, precision loss and non-number types.

https://www.rfc-editor.org/rfc/rfc6902.txt section 4.6
2026-11-08 21:22:38 -05:00
Wleeaf d9b375ff1b json_pointer: find null array elements
json_pointer_get_single_path() returned ENOENT when the array element
at an in-range index was NULL, which is how json-c stores a JSON null.
A null object member was already found, but on [0, null, 2] "/1" failed
with "not found", although RFC 6901 says it references the null value.

The array index is bounds-checked just before, so a NULL element now
resolves like a null member: json_pointer_get() returns 0 and sets
*res to NULL. This also fixes json_patch_apply(), which failed every
"test", "replace" and "remove" on a null array element, and every
"move" and "copy" from one, with "Did not find element referenced by
path field".

Added a json_pointer_get() test, and json_patch_tests.json cases that
mirror the existing null object member ones.
2026-10-26 00:39:03 -04:00
fhgffy 86fe287188 json_patch: remove members whose names contain '/' or '~'
json_pointer_get_internal() decodes the last reference token in a
private copy of the path, then pointed key_in_parent at the same offset
in the caller's path, where the token is still escaped. For a path like
"/a~1b" that gave "a~1b" instead of "a/b", so json_patch's remove,
and the remove step of move, called json_object_object_del() with a key
that doesn't exist. Nothing was removed and the patch still reported
success; a move left the source member in place.

Point key_in_parent at the key as it is stored in the parent object
instead, which is always the decoded name.

Added remove and move cases with escaped member names to
json_patch_tests.json and refreshed test_json_patch.expected.
2026-10-25 18:19:07 -04:00
Afonso Januário 1b504e26ab json_patch: fix move/copy false rejection between sibling keys sharing a prefix
json_patch_apply_move_copy() checks that "from" is not a proper prefix
of "path" per RFC 6902 section 4.4 (a location cannot be moved into one
of its own children), but it did so with a plain strncmp() over the raw
pointer strings, without checking that the shared run of characters
actually ends on a JSON Pointer reference-token boundary in "path".

As a result, moving or copying between two sibling object keys where
one name is a textual prefix of the other, e.g. "/aa" to "/aab", was
rejected with "Invalid attempt to move parent under a child" even
though "/aa" is not an ancestor pointer of "/aab" at all, just an
unrelated key that happens to share a few leading characters.

The fix requires that the character in "path" right after the shared
"from" prefix be either the end of the string (equal paths, a no-op)
or a '/' (a genuine nested reference token), before treating it as an
attempt to move a location under its own descendant.

Added two cases to json_patch_tests.json covering the move and copy
operations between such sibling keys, and refreshed the corresponding
golden test_json_patch.expected output.
2026-09-25 23:52:49 +01:00
Javid Khan e248056aa1 require string type for patch op/path/from fields 2026-07-18 21:08:17 +05:30
Javid Khan eed664e06a reject null op/path/from fields in json_patch_apply 2026-07-16 12:55:41 +05:30
dxbjavid 5647679c0c deep copy values in json_patch copy op to avoid aliasing and cycles 2026-06-24 21:56:36 +05:30
Eric Hawicz ce3184243a Fix json_patch_apply handling of removing the whole document (i.e. "path":"").
Enable all disabled tests, add a few more including some with null documents.
2023-07-31 22:18:04 -04:00
Eric Hawicz 9dbf2880cc Adjust the behavior of the args passed to json_patch_apply to make it easier to do in place modifications, and add a struct json_patch_error to report more details on failures. 2023-07-31 22:18:04 -04:00
Alexandru Ardelean 3b8363fcdc tests: test_json_patch: add test suite for JSON patch
Essentially, this change adds the test cases from this repo:
   https://github.com/json-patch/json-patch-tests

Specifically:
   https://github.com/json-patch/json-patch-tests/blob/master/spec_tests.json
   https://github.com/json-patch/json-patch-tests/blob/master/tests.json

The files were taken at the date of this commit, at git hash
  ea3af85790cb72893d0676597814b7532019c24e

Some tests may not have an 'expected' or 'error' field. Those are ignored.
One test was disabled manually via "disabled_in_json_c", because it tries
an impossible test, i.e. to add 2 "op" fields in the same patch entry,
something which is impossible in a JSON object.

For the 'error' cases, right now we only test that an error happens.
Later, we can extend this to check the error codes.

Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
2023-07-31 22:18:03 -04:00