open-source-parsers / jsoncpp

A C++ library for interacting with JSON.
Other
8.06k stars 2.63k forks source link

Memory corruption when using Json::Value member creation operator "[]" #1549

Closed aslobodaNV closed 1 month ago

aslobodaNV commented 1 month ago

Describe the bug When adding entries to a Json::Value instance, I am seeing instances of memory corruption. I have been able to distill the behavior down to a very simple struct wherein member variables of that struct are corrupted when adding entries to a Json::Value instance.

To Reproduce The following code exhibits the errant behavior:

#include <json/json.h>

typedef struct Device_t {
    const char *address;
    const char *name;
    int node;
    const char *type;
}Device_t;

int example(void) {

    Device_t dev;
    dev.address="addr";
    dev.name="sys";
    dev.node=1;
    dev.type="dev";

    Json::Value devJSON(Json::objectValue);
    devJSON["node"]=1;
    devJSON["address"]=2;
    devJSON["type"]=dev.type;

    return 0;
}

int main() {
    int ret = example();
    return ret;
}

When this code is compiled and run with gdb, I am able to observe the corruption:

Temporary breakpoint 1, main () at example.cc:27
27              int ret = example();
(gdb) b example.cc:18
Breakpoint 2 at 0x55555555526d: file example.cc, line 18.
(gdb) c
Continuing.

Breakpoint 2, example () at example.cc:18
18              Json::Value devJSON(Json::objectValue);
(gdb) p dev
$1 = {address = 0x555555556004 "addr", name = 0x555555556009 "sys", node = 1, type = 0x55555555600d "dev"}
(gdb) watch dev
Hardware watchpoint 3: dev
(gdb) n
19              devJSON["node"]=1;
(gdb) n

Hardware watchpoint 3: dev

Old value = {address = 0x555555556004 "addr", name = 0x555555556009 "sys", node = 1, type = 0x55555555600d "dev"}
New value = {address = 0x0, name = 0x555555556009 "sys", node = 1, type = 0x55555555600d "dev"}
0x00007ffff7f95e66 in Json::Value::initBasic(Json::ValueType, bool) () from /lib/x86_64-linux-gnu/libjsoncpp.so.25
(gdb) bt
#0  0x00007ffff7f95e66 in Json::Value::initBasic(Json::ValueType, bool) () from /lib/x86_64-linux-gnu/libjsoncpp.so.25
#1  0x00007ffff7f972b5 in Json::Value::Value(int) () from /lib/x86_64-linux-gnu/libjsoncpp.so.25
#2  0x000055555555528f in example () at example.cc:19
#3  0x0000555555555400 in main () at example.cc:27
(gdb) f 2
#2  0x000055555555528f in example () at example.cc:19
19              devJSON["node"]=1;
(gdb) p dev
$2 = {address = 0x0, name = 0x555555556009 "sys", node = 1, type = 0x55555555600d "dev"}

In the gdb output snippet above I see that the variable, "dev", has a member "address" with value 0x555555556004. I have printed the full contents of "dev" and added a watchpoint to the variable. I then add two new fields to the variable devJSON, an instance of Json::Value. In the process of adding the second field, the watchpoint triggers and indicates that "address" has changed to the value 0x0. I see from the backtrace that this occurred within a call to "Json::Value::initBasic(Json::ValueType, bool)". Going back up to the frame of the caller, I print out "dev" and confirm that it has been corrupted.

Expected behavior I expected no changes to the member variables of the struct "dev", especially since the change occurs when the jsoncpp calls are not interacting with the struct.

Desktop (please complete the following information): OS: Ubuntu 24.04 LTS Codename: noble Kernel: 6.8.0-31-generic

Additional context Compiled using g++-13 as follows: g++ -I ../../lib/third-party/json/include -Wall -std=c++17 example.cc -o example -ljsoncpp -g Removing additional fields from the definition of the Device_t struct appears to circumvent the underlying issue. I am not sure why.

BillyDonahue commented 1 month ago

Thanks for the report. I'm concerned that the version of jsoncpp you're linking with might not match the header you're using. Can you verify this?

g++ -I ../../lib/third-party/json/include -Wall -std=c++17 example.cc -o example -ljsoncpp -g

In particular I'm concerned that the -ljsoncpp is finding a "system" install. That's what this looks like to me.

Maybe rerun that g++ command in verbose mode.

Looking at your backtraces, the libjsoncpp.so is: /lib/x86_64-linux-gnu/libjsoncpp.so.25

Pretty sure that's the problem.

aslobodaNV commented 1 month ago

This was exactly my issue, thanks for noticing the mismatched library. I have updated my compilation command and find that I no longer can replicate the issue.