When a json string object is updated with a bigger string, a new
malloc'ed buffer is used to store the new string and it's size is made
negative to indicate that an external buffer is in use.
When that same json string object get's updated again with an empty
stirng (size = 0), the new external malloc'ed buffer is still used.
But the fact that the new size value is not negative removes the
indicator that the externally malloc'ed buffer is used.
This becomes a problem when the object get's updated again with any
other string, because a new buffer will be malloced and linked to the
object while to old one won't be free'd.
This causes a memory leak when updating a json string with
json_object_set_stirng() which has previously been updated
with an empty string.
Example:
--
obj = json_object_new_string("data");
json_object_set_string(obj, "more data");
json_object_set_string(obj, "");
json_object_set_string(obj, "other data"); /* leaks */
--
This commit fixes the issue by free'ing the external buffer when an
empty string is set and use the internal one again.
Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
Use target_link_libraries, plus fill in Libs.private in json-c.pc so pkg-config --static --libs works appropriately.
Also, only link against libbsd when arc4random is actually found there.
If memory allocation fails in json_c_set_serialization_double_format or
json_object_copy_serializer_data then return with an error value and
preserve previous values without overriding them with NULL.
Most of these sites support HTTPS (some forward to HTTPS when accessing
the HTTP versions). Use HTTPS directly if supported.
Some URLs led to 404 error pages. Adjusted the links to point to
new locations.
I did not adjust the Microsoft HTML Help Workshop link because it seems
that this software is not available anymore. Instead of removing the
link entirely I kept it there in case it helps someone to find the
software on archived websites.
If errors occur in printbuf_memappend, then these errors should be
propagated through sprintbuf to indicate the error to the user.
Proof of Concept:
```
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include "json.h"
int
main(void) {
struct printbuf *pb;
if ((pb = printbuf_new()) == NULL)
err(1, "printbuf_new");
if (printbuf_memset(pb, INT_MAX - 9, 'a', 1) < 0)
errx(1, "printbuf_memset");
printf("length: %d\n", printbuf_length(pb));
printf("sprintbuf: %d\n", sprintbuf(pb, "string too long"));
printf("length: %d\n", printbuf_length(pb));
printbuf_free(pb);
return 0;
}
```
You can see that sprintbuf does not return an error but length is still
the same, i.e. the string "string too long" has not been appended.
I would like to add this as a unit test but it really depends on the
operating system if printbuf_memset() would fail if not enough memory is
available or not.
It is possible to have a printbuf with "gaps", i.e. areas within the
print buffer which have not been initialized by using printbuf_memset.
Always clear memory in such cases.
Example:
```
struct printbuf *pb = printbuf_new();
printbuf_memset(pb, 10, 'a', 2);
```
In this case pb->buf[0] is '\0' but pb->buf[1] up to pb->buf[9] are
not set. The length would be 12 due to successful printbuf_memset.
Systems without vasprintf fall back to implementation in header file
vasprintf_compat.h. This version could run into heap overflow issues
with very long arguments or formats provoking a lot of output.
The vsnprintf function returns a negative value if more than INT_MAX
characters would be written since its int return type could not
handle this (and %n couldn't handle it either).
Before testing for a possible error value the additional char for
\0 is already added. A -1 error code would not be detected.
Increment only after implicitly casting to an unsigned value to avoid
signed integer overflow if INT_MAX has been returned.
Use va_copy to duplicate the original ap argument for multiple uses
on non-WIN32 systems. At least with glibc the test suite would fail
because the arguments are not reset after leaving the vsnprintf call.
Removed support for apparently very old glibc versions which do not
comply with vsnprintf standard descriptions. It breaks support for
modern ones which are not forced to return -1 in case of error. The
standard specifies merely "a negative value".
How to reproduce:
- Use a system without vasprintf
- Alternatively remove -D_GNU_SOURCE from CMakeLists.txt
- Compile and run:
#include "json.h"
int main(void) {
struct printbuf *pb = printbuf_new();
sprintbuf(pb, "prefix %2147483647s", "*");
printbuf_free(pb);
return 0;
}