Memory leak on peridical json_loads call

898 views
Skip to first unread message

lotan

unread,
Nov 29, 2012, 6:57:26 AM11/29/12
to jansso...@googlegroups.com
Hi,

I've search through the group an found similar issues to mine but wasn't able to find a solution.

I've reduced my code until I've ended up with this snippet:

int parse_json(const char *text) {

   json_t            *root;
   json_error_t       error;

   if (!json_is_object((root = json_loads(text, 0, &error)))) return 1;
   json_decref(root);

   return 0;
}

parse_json is called periodically and valgrind reports this:

==7271== 95,066 (144 direct, 94,922 indirect) bytes in 2 blocks are definitely l
ost in loss record 102 of 102
==7271==    at 0x4A090ED: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd6
4-linux.so)
==7271==    by 0x4C4CD11: json_object (in /usr/lib64/libjansson.so.4.3.1)
==7271==    by 0x4C4A684: ??? (in /usr/lib64/libjansson.so.4.3.1)
==7271==    by 0x4C4AA76: ??? (in /usr/lib64/libjansson.so.4.3.1)
==7271==    by 0x4C4ABF5: json_loads (in /usr/lib64/libjansson.so.4.3.1)
==7271==    by 0x4016F7: parse_json

For every iteration it seems to lose 72 direct and 47461 indirect bytes.

If I comment out the call to parse_json(), I don't lose any bytes.

There's not much to my example.
Will I have to free some additional json context if I call json_loads() periodically?

Petri Lehtinen

unread,
Nov 29, 2012, 9:03:30 AM11/29/12
to jansso...@googlegroups.com
No you don't. Why this happens becomes clear if you look at the
definition of the json_is_object macro:

#define json_typeof(json) ((json)->type)
#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)

When the macros are expanded, the if statement in parse_json()
becomes:

if ((root = json_loads(text, 0, &error)) && ((root = json_loads(text, 0, &error))->type) == JSON_OBJECT) return 1;

So json_loads() is called two times and the first result is thrown
away. Consequently, json_decref() only frees half of the memory that
is allocated.

You can confirm this by changing your code to:

int parse_json(const char *text) {

json_t *root;
json_error_t error;

root = json_loads(text, 0, &error);
if (!json_is_object(root)) return 1;
json_decref(root);

return 0;
}

This way, no memory is leaked.

Petri

Jeff

unread,
Nov 29, 2012, 9:13:20 AM11/29/12
to jansso...@googlegroups.com
json_loads() could also return an array, right?  In that case json_is_object() would be false and you'd miss your json_decref().  Seems like you'd always want to call json_decref().  It will do the right thing even if passed NULL.  Maybe:

root = json_loads(...);
answer = json_is_object(root);
json_decref(root);
return answer;

lotan

unread,
Nov 29, 2012, 10:27:46 AM11/29/12
to jansso...@googlegroups.com
Thank you very much.
It would indeed have helped to look at the code (the include would have even been enough).
Wrong assumption on my side. Sorry for the hassle.
Reply all
Reply to author
Forward
0 new messages