Crash in json-c when first '{' missing in json string

593 views
Skip to first unread message

nags

unread,
Nov 20, 2012, 1:15:00 AM11/20/12
to jso...@googlegroups.com
Hi,

I wrote a function like the following to create json object for the given string,

json_object* createJsonObject (char *string)
{
    struct json_tokener* tok = NULL;
    json_object *jobj = NULL;
    json_tokener_error error = json_tokener_error_parse_null;

    if (NULL == string)
        return NULL;

    tok = json_tokener_new();

    if (tok)
    {
        jobj = json_tokener_parse_ex(tok, string, -1);
        if(json_tokener_success == (json_tokener_error)tok->err && jobj)
        {
            printf ("Object created successfully.\n");
        }
        else
        {
            jobj = NULL;
            printf ("Object creation failed.\n");
        }
        json_tokener_free(tok);
    }
    return jobj;
}

And this createJsonObject function is working well for all positive strings.
Also it is returning NULL for error inputs like '{' or ':' missing strings.
But it is returning junk pointer when the first '{' is missing like,

"Message": { "To": "user-pc", "Msg": "Restart"}}

While debugging I found that the "json_tokener_parse_ex" is returning json_tokener_success on tok->err.
Can you please guide me to fix this issue ASAP?

Thanks in advance,
Nagarajan Palaniyappan.

nags

unread,
Nov 20, 2012, 2:10:47 AM11/20/12
to jso...@googlegroups.com
I have done a workaround to fix this issue using the tok->char_offset as,

.....
        if(strlen (string) == tok->char_offset && json_tokener_success == (json_tokener_error)tok->err && jobj)

        {
            printf ("Object created successfully.\n");
        }
        else
        {
            jobj = NULL;
            printf ("Object creation failed.\n");
        }
.......

Please share your feedback on this.

Eric Haszlakiewicz

unread,
Nov 20, 2012, 1:30:11 PM11/20/12
to jso...@googlegroups.com
On Tue, Nov 20, 2012 at 12:15 AM, nags <cobra...@gmail.com> wrote:
> I wrote a function like the following to create json object for the given
> string,
>
> json_object* createJsonObject (char *string)
> {
> struct json_tokener* tok = NULL;
> json_object *jobj = NULL;
> json_tokener_error error = json_tokener_error_parse_null;

I had to change this to "enum json_tokener_error ..." to get it to compile.

>
> if (NULL == string)
> return NULL;
>
> tok = json_tokener_new();
>
> if (tok)
> {
> jobj = json_tokener_parse_ex(tok, string, -1);
> if(json_tokener_success == (json_tokener_error)tok->err && jobj)

You shouldn't reference tok->err directly. Use json_tokener_get_error(tok).

> {
> printf ("Object created successfully.\n");
> }
> else
> {
> jobj = NULL;
> printf ("Object creation failed.\n");
> }
> json_tokener_free(tok);
> }
> return jobj;
> }
>
> And this createJsonObject function is working well for all positive strings.
> Also it is returning NULL for error inputs like '{' or ':' missing strings.

It's supposed to return NULL for some of that, but
json_tokener_get_error(tok) should return json_tokener_continue to
indicate that a partial string has been parsed.

> But it is returning junk pointer when the first '{' is missing like,
>
> "Message": { "To": "user-pc", "Msg": "Restart"}}
>
> While debugging I found that the "json_tokener_parse_ex" is returning
> json_tokener_success on tok->err.

How do you know it is a junk pointer? json_tokener_parse_ex is
*supposed* to return success with that example message because the
beginning of it is entirely valid.
"Message" is a parsable string, so it should return a json_object of
type json_type_string. To test this, I added this main function:

int main(int argc, char **argv)
{
if (argc <= 1)
{
printf("not enough args\n");
return 1;
}
json_object *obj;
obj = createJsonObject(argv[1]);
if (!obj)
return 1;

printf("got obj: %x type=%s\n", obj,
json_type_to_name(json_object_get_type(obj)));
printf("string val=%s\n", json_object_get_string(obj));
json_object_put(obj);
return 0;
}


Then ran it using your example:
./a.out '"Message": { "To": "user-pc", "Msg": "Restart"}}'

and it worked just fine:
Object created successfully.
got obj: bb90a060 type=string
string val=Message

Do you get something different? What version of json-c are you using?

Eric

nags

unread,
Nov 21, 2012, 1:36:27 AM11/21/12
to jso...@googlegroups.com
Hi Eric,

Thanks for the information in detail.
Actually I am using the "json_object_object_foreach" macro to travel thru the entire object.
Because I need a generic way to travel thru the json object if it is created successfully.
And it is crashing in the same macro when the first '{' is missing because that is a string object.
My requirement is to return NULL from createJsonObject API if the first '{' is missing.
So please suggest me a better way to do that.

Thanks.

Eric Haszlakiewicz

unread,
Nov 21, 2012, 1:49:55 AM11/21/12
to jso...@googlegroups.com


On Nov 21, 2012 12:36 AM, "nags" <cobra...@gmail.com> wrote:
> Thanks for the information in detail.
> Actually I am using the "json_object_object_foreach" macro to travel thru the entire object.
> Because I need a generic way to travel thru the json object if it is created successfully.
> And it is crashing in the same macro when the first '{' is missing because that is a string object.
> My requirement is to return NULL from createJsonObject API if the first '{' is missing.
> So please suggest me a better way to do that.

Well, I'd say use json_object_get_type and check for json_type_object.  If the parse function returns something else, free it with json_object_put and return NULL.

Eric

nags

unread,
Nov 21, 2012, 1:50:39 AM11/21/12
to jso...@googlegroups.com
Please use the below sample to reproduce this issue.

/**************************************************/
#include <stdio.h>
#include <json/json.h>

json_object* createJsonObject (char *string);
void extractJsonValue (json_object * obj, char *key);
void parseJsonArray (json_object * jobj, char *key);
void parseJsonObject (json_object * jobj);


json_object* createJsonObject (char *string)
{
    struct json_tokener* tok = NULL;
    json_object *jobj = NULL;
    enum json_tokener_error error = json_tokener_error_parse_null;


    if (NULL == string)
        return NULL;

    tok = json_tokener_new();

    if (tok)
    {
        jobj = json_tokener_parse_ex(tok, string, -1);
        if(json_tokener_success == (enum json_tokener_error)tok->err && jobj)
        {

            printf ("Object created successfully.\n");
        }
        else
        {
            jobj = NULL;
            printf ("Object creation failed.\n");
        }
        json_tokener_free(tok);
    }
    return jobj;
}

void extractJsonValue (json_object * obj, char *key)
{
    enum json_type type = json_object_get_type (obj);
    switch (type)
    {
        case json_type_boolean:
            printf("key: %s val: %s\n", key, (json_object_get_boolean(obj)?"true":"false"));
        break;
        case json_type_double:
            printf("key: %s val: %f\n", key, json_object_get_double(obj));
        break;
        case json_type_int:
            printf("key: %s val: %d\n", key, json_object_get_int(obj));
        break;
        case json_type_string:
            printf("key: %s val: %s\n", key, json_object_get_string(obj));
        break;
        default:
            printf("key: %s is unknown type\n", key);
        break;
    }
}

void parseJsonArray (json_object * jobj, char *key)
{
    enum json_type type;

    /*Simply get the array */
    json_object *jarray = jobj;

    if (key)
    {
        /*Getting the array if it is a key value pair */
        jarray = json_object_object_get (jobj, key);
    }
   
    /*Getting the length of the array */
    int arraylen = json_object_array_length (jarray);
    json_object *jvalue;
    int i;

    for (i = 0; i < arraylen; i++)
    {
        /*Getting the array element at position i */
        jvalue = json_object_array_get_idx (jarray, i);
        type = json_object_get_type (jvalue);

        switch (type)
        {
            case json_type_boolean:
            case json_type_double:
            case json_type_int:
            case json_type_string:
                extractJsonValue (jvalue, key);
            break;
            case json_type_object:
                parseJsonObject (jvalue);
            break;
            case json_type_array:
                parseJsonArray (jvalue, NULL);
            break;
        }
    }
}

void parseJsonObject (json_object * jobj)
{
    enum json_type type;
    json_object_object_foreach (jobj, key, val)
    /*Passing through every array element */
    {
        type = json_object_get_type (val);
        switch (type)
        {
            case json_type_boolean:
            case json_type_double:
            case json_type_int:
            case json_type_string:
                extractJsonValue (val, key);
            break;
            case json_type_object:
                jobj = json_object_object_get (jobj, key);
                parseJsonObject (jobj);
            break;
            case json_type_array:
                parseJsonArray (jobj, key);
            break;

        }
    }
}

int main(int argc, char **argv)
{
    if (argc <= 1)
    {
        printf("not enough args\n");
        return 1;
    }

    json_object *obj;
    enum json_type type;


    obj = createJsonObject(argv[1]);
    if (!obj)
        return 1;

    parseJsonObject (obj);

    json_object_put(obj);

    return 0;
}
/*************************************************/

nags

unread,
Nov 21, 2012, 1:55:41 AM11/21/12
to jso...@googlegroups.com
Yes that ll be working.
Thank you.
Reply all
Reply to author
Forward
0 new messages