DaveGamble / cJSON

Ultralightweight JSON parser in ANSI C
MIT License
10.28k stars 3.15k forks source link

Inconsistent error in cJSON_AddItemReferenceToObject #825

Open tregua87 opened 5 months ago

tregua87 commented 5 months ago

I found an inconsistent behavior in the cJSON_AddItemReferenceToObject API that appears up to commit version v1.7.17. As you see in the following example, cJSON_AddItemReferenceToObject allows to append a string to a string. From my understanding, it is treating the cjson_0 as a dictionary. Moreover, the return value of cJSON_AddItemReferenceToObject indicates the object manipulation was correct. However, this behaviors leads to inconsistent results and strange memory corruptions.

The output of this example is:

int_0: 1
cjson_1: "XXXXX"
cjson_0: "XXXXX"
cjson_0: 0x606000000020
cjson_1: 0x606000000080
<asan report>

Where cjson_0 and cjson_1 print the same object (i.e., a string), but the address of the objects is different.

Minimal test:

#include <cjson/cJSON.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>

int main(int argc, char** argv) {

    cJSON *cjson_0 = nullptr;
    cJSON *cjson_1 = nullptr;

    int int_0 = 0;
    int int_1 = 0;
    int int_2 = 0;

    char *x = "\"XXXXX\"";

    cjson_0 =  cJSON_Parse(x);
    if (cjson_0 == 0)
        return 1;
    int_0 =  cJSON_AddItemReferenceToObject(cjson_0, "", cjson_0);
    printf("int_0: %d\n", int_0);
    cjson_1 =  cJSON_GetArrayItem(cjson_0, 0);
    if (cjson_1 == 0) return 1;
        printf("cjson_1: %s\n", cJSON_Print(cjson_1));
    int_1 =  cJSON_ReplaceItemInObject(cjson_0, "", cjson_0);
    printf("cjson_0: %s\n", cJSON_Print(cjson_0));
    printf("cjson_0: %p\ncjson_1: %p\n", cjson_0, cjson_1);
    int_2 =  cJSON_AddItemReferenceToObject(cjson_0, "", cjson_1); // bug here

    return 0;
}

Compilation:

clang++ -g -std=c++11 -I${INSTALL}/include -fsanitize=address \
        test.cc -Wl,--whole-archive ${INSTALL}/libcjson.a -Wl,--no-whole-archive \
        -lz -ljpeg -Wl,-Bstatic -llzma -Wl,-Bdynamic -lstdc++ -o test