akheron / jansson

C library for encoding, decoding and manipulating JSON data
http://www.digip.org/jansson/
Other
3.05k stars 808 forks source link

json_dumpb issue #604

Closed liningjie418 closed 2 years ago

liningjie418 commented 2 years ago

Hello team,

The json library is used in our product, and the program crashed while testing.

I think it is caused by the wrong return value of the function json_dumpb in the jansson library.

Here are the demo and patch file for reference.

Now let me describe the problem:

In my opinion, json_dumpb's function is to convert json to string and put it in buf,the length is its size.

When the length of the json serialization is greater than the length of the buf passed in, the return value is wrong. From the explanation of the api, in fact, it should return the number of bytes serialized to buf, but it's not.

  1. patch `size_t json_dumpb(const json_t json, char buffer, size_t size, size_t flags) { struct buffer buf = {size, 0, buffer};

    if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) return 0;

    return buf.used <= buf.size ? buf.used : buf.size; }`

  2. Demo ` json_t *js = json_object(); json_object_set_new(js, "test1", json_string("hello")); json_object_set_new(js, "test2", json_string("hello")); json_object_set_new(js, "test3", json_string("hello")); json_object_set_new(js, "test4", json_string("hello")); json_object_set_new(js, "test5", json_string("hello")); json_object_set_new(js, "test6", json_string("hello"));

    int n = json_dumpb(js, buf, sizeof(buf), 0); json_decref(js);

    buf[n] = '\0';

    printf("n : %s, %d\n", buf, n); return 0; `

ploxiln commented 2 years ago

The documentation says:

Returns the number of bytes that would be written or 0 on error.

This function never writes more than size bytes. If the return value is greater than size, the contents of the buffer are undefined. This behavior enables you to specify a NULL buffer to determine the length of the encoding.

This is inspired by snprintf(), which also returns the length of the string that would have been written if there was enough space. Then you can compare that to the amount of space you provided/specified to know both 1) if it successfully fit everything, and 2) how much space it would need to fit everything.

ploxiln commented 2 years ago

minor side note / tip: you can use triple-backticks on their own line for multi-line code-quote, or you can use 4-space indent of a empty-line separated block, but single-backtick does not work for multiple lines. demo:

json_t *js = json_object();
json_object_set_new(js, "test1", json_string("hello"));
json_object_set_new(js, "test2", json_string("hello"));
json_object_set_new(js, "test3", json_string("hello"));
json_object_set_new(js, "test4", json_string("hello"));
json_object_set_new(js, "test5", json_string("hello"));
json_object_set_new(js, "test6", json_string("hello"));

int n = json_dumpb(js, buf, sizeof(buf), 0);
json_decref(js);

buf[n] = '\0';

printf("n : %s, %d\n", buf, n);
return 0;

is produced by:

```c
json_t *js = json_object();
json_object_set_new(js, "test1", json_string("hello"));
json_object_set_new(js, "test2", json_string("hello"));
json_object_set_new(js, "test3", json_string("hello"));
json_object_set_new(js, "test4", json_string("hello"));
json_object_set_new(js, "test5", json_string("hello"));
json_object_set_new(js, "test6", json_string("hello"));

int n = json_dumpb(js, buf, sizeof(buf), 0);
json_decref(js);

buf[n] = '\0';

printf("n : %s, %d\n", buf, n);
return 0;
```
liningjie418 commented 2 years ago

minor side note / tip: you can use triple-backticks on their own line for multi-line code-quote, or you can use 4-space indent of a empty-line separated block, but single-backtick does not work for multiple lines. demo:

json_t *js = json_object();
json_object_set_new(js, "test1", json_string("hello"));
json_object_set_new(js, "test2", json_string("hello"));
json_object_set_new(js, "test3", json_string("hello"));
json_object_set_new(js, "test4", json_string("hello"));
json_object_set_new(js, "test5", json_string("hello"));
json_object_set_new(js, "test6", json_string("hello"));

int n = json_dumpb(js, buf, sizeof(buf), 0);
json_decref(js);

buf[n] = '\0';

printf("n : %s, %d\n", buf, n);
return 0;

is produced by:

```c
json_t *js = json_object();
json_object_set_new(js, "test1", json_string("hello"));
json_object_set_new(js, "test2", json_string("hello"));
json_object_set_new(js, "test3", json_string("hello"));
json_object_set_new(js, "test4", json_string("hello"));
json_object_set_new(js, "test5", json_string("hello"));
json_object_set_new(js, "test6", json_string("hello"));

int n = json_dumpb(js, buf, sizeof(buf), 0);
json_decref(js);

buf[n] = '\0';

printf("n : %s, %d\n", buf, n);
return 0;

I am not good at using Github. Thank you very much for your suggestion.

liningjie418 commented 2 years ago

The documentation says:

Returns the number of bytes that would be written or 0 on error.

This function never writes more than size bytes. If the return value is greater than size, the contents of the buffer are undefined. This behavior enables you to specify a NULL buffer to determine the length of the encoding.

This is inspired by snprintf(), which also returns the length of the string that would have been written if there was enough space. Then you can compare that to the amount of space you provided/specified to know both 1) if it successfully fit everything, and 2) how much space it would need to fit everything.

OK. I've got it. From my point of view, return the actual number of bytes be written is easier to understand.