Files
json-c/tests/test_set_serializer.c
Tobias Stoeckmann 5385a566db Prevent truncation on custom double formatters.
A custom double formatter can lead to truncation of the rest of the
JSON document.

If a custom formatter completely fills the buffer used by snprintf
with a trailing dot or comma and the formatting option
JSON_C_TO_STRING_NOZERO has been specified, then an iterator moves
past the ending '\0' (off-by-one buffer overflow) to set an
additional '\0' and adds the first '\0' into the printbuf.

Since '\0' will eventually be considered the terminating character
of the complete printbuf result, all trailing characters are lost.

This leads to an incomplete JSON string as can be seen with the
test case.

The off-by-one can be noticed if compiled with address sanitizer.

Since this is a very special case and a malformed formatter could
do way more harm and is the responsibility of the user of this
library, this is just a protective measure to keep json-c code as
robust as possible.
2020-05-16 15:26:16 +02:00

84 lines
2.6 KiB
C

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "json.h"
#include "printbuf.h"
struct myinfo
{
int value;
};
static int freeit_was_called = 0;
static void freeit(json_object *jso, void *userdata)
{
struct myinfo *info = userdata;
printf("freeit, value=%d\n", info->value);
// Don't actually free anything here, the userdata is stack allocated.
freeit_was_called = 1;
}
static int custom_serializer(struct json_object *o, struct printbuf *pb, int level, int flags)
{
sprintbuf(pb, "Custom Output");
return 0;
}
int main(int argc, char **argv)
{
json_object *my_object, *my_sub_object;
MC_SET_DEBUG(1);
printf("Test setting, then resetting a custom serializer:\n");
my_object = json_object_new_object();
json_object_object_add(my_object, "abc", json_object_new_int(12));
json_object_object_add(my_object, "foo", json_object_new_string("bar"));
printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
struct myinfo userdata = {.value = 123};
json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
printf("my_object.to_string(custom serializer)=%s\n",
json_object_to_json_string(my_object));
printf("Next line of output should be from the custom freeit function:\n");
freeit_was_called = 0;
json_object_set_serializer(my_object, NULL, NULL, NULL);
assert(freeit_was_called);
printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
json_object_put(my_object);
// ============================================
my_object = json_object_new_object();
printf("Check that the custom serializer isn't free'd until the last json_object_put:\n");
json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
json_object_get(my_object);
json_object_put(my_object);
printf("my_object.to_string(custom serializer)=%s\n",
json_object_to_json_string(my_object));
printf("Next line of output should be from the custom freeit function:\n");
freeit_was_called = 0;
json_object_put(my_object);
assert(freeit_was_called);
// ============================================
my_object = json_object_new_object();
my_sub_object = json_object_new_double(1.0);
json_object_object_add(my_object, "double", my_sub_object);
printf("Check that the custom serializer does not include nul byte:\n");
json_object_set_serializer(my_sub_object, json_object_double_to_json_string, "%125.0f,", NULL);
printf("my_object.to_string(custom serializer)=%s\n",
json_object_to_json_string_ext(my_object, JSON_C_TO_STRING_NOZERO));
json_object_put(my_object);
return 0;
}