You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libjson-c中正确释放所有json_object对象内存,避免内存泄漏与Valgrind非法释放报错的方法

Correctly Freeing All json_object Instances in libjson-c to Avoid Memory Leaks and Invalid Frees

Let's break down what's happening here and fix your memory management issues with libjson-c. First, a quick refresher: libjson-c uses reference counting to manage object memory, and misunderstanding how this works is almost certainly causing your Valgrind errors.

Why Your Current Code Is Causing Problems

  1. Weak References Don't Need Manual put: When you fetch child objects with json_object_object_get_ex or json_object_array_get_idx, you're getting a weak reference to the object (the reference count isn't incremented). Calling json_object_put on these child objects directly would over-decrement their reference count, leading to invalid frees when the root object tries to clean them up later.
  2. Dangling Pointers from Internal Strings: json_object_get_string returns a pointer to the internal buffer of the json_object. If you save this pointer (like you did with serverName/team1Name) and then free the root parsed_json, those pointers become dangling—using them later causes undefined behavior, and trying to free them directly is a double-free error.
  3. Uncleaned Resources in Loops: If you're running this code in a loop, you're not freeing the manually allocated strings (like the ones you cast to char*) between iterations, leading to memory leaks.

Step-by-Step Fix

Here's how to adjust your code to handle memory correctly, with explanations of key changes:

// Declare persistent variables outside the loop so we can clean them up between iterations
char* serverName = NULL;
char* team1Name = NULL;
char* team2Name = NULL;

while (/* Your loop condition here */) {
    // Parse the config file (we own this object, so we'll need to put it later)
    struct json_object* parsed_json = json_object_from_file("config.json");
    if (!parsed_json) {
        printf("Failed to load config.json\n");
        goto cleanup_loop; // Clean up before exiting iteration
    }

    // Fetch and validate each field (all these are weak references)
    struct json_object* portInConfig = NULL;
    if (!json_object_object_get_ex(parsed_json, "port", &portInConfig)) {
        printf("Failed to find port number in config\n");
        goto cleanup_json;
    }

    struct json_object* masterInConfig = NULL;
    if (!json_object_object_get_ex(parsed_json, "master", &masterInConfig)) {
        printf("Failed to find master variable in config\n");
        goto cleanup_json;
    }

    // ... Repeat this pattern for all other config fields ...

    // Handle strings: copy to our own buffer (don't rely on internal json pointers)
    free(serverName); // Clean up previous iteration's allocation
    serverName = strdup(json_object_get_string(serverNameInConfig));
    if (!serverName) {
        printf("Failed to allocate memory for server name\n");
        goto cleanup_json;
    }

    free(team1Name);
    team1Name = strdup(json_object_get_string(team1NameInConfig));
    if (!team1Name) {
        printf("Failed to allocate memory for team1 name\n");
        goto cleanup_json;
    }

    free(team2Name);
    team2Name = strdup(json_object_get_string(team2NameInConfig));
    if (!team2Name) {
        printf("Failed to allocate memory for team2 name\n");
        goto cleanup_json;
    }

    // Handle array values (still weak references, no need to put)
    uint8 team1Color[3];
    uint8 team2Color[3];
    for (int i = 0; i < 3; ++i) {
        team1Color[i] = json_object_get_int(json_object_array_get_idx(team1ColorInConfig, i));
        team2Color[i] = json_object_get_int(json_object_array_get_idx(team2ColorInConfig, i));
    }

    uint8 mapArrayLen = json_object_array_length(mapInConfig);
    char mapArray[mapArrayLen][64]; // Stack-allocated, auto-cleaned when loop iteration ends
    for (int i = 0; i < mapArrayLen; ++i) {
        struct json_object* mapObj = json_object_array_get_idx(mapInConfig, i);
        const char* mapStr = json_object_get_string(mapObj);
        size_t strLen = strlen(mapStr);
        if (strLen >= 64) continue;
        strncpy(mapArray[i], mapStr, strLen);
        mapArray[i][strLen] = '\0'; // Ensure proper string termination
    }

    // Extract scalar values (safe, since we're copying the value, not a pointer)
    int port = json_object_get_int(portInConfig);
    int master = json_object_get_int(masterInConfig);
    uint8 gamemode = json_object_get_int(gamemodeInConfig);

cleanup_json:
    // Free the root object: this recursively frees ALL child objects (portInConfig, etc.)
    json_object_put(parsed_json);

    // If we hit an error, skip to next iteration after cleaning up
    if (/* Check for error state here */) {
        continue;
    }

    // ... Your business logic using the parsed values goes here ...

cleanup_loop:
    // If we exit the iteration early, ensure we don't leave dangling allocations
    // (Note: strdup returns NULL on failure, so free(NULL) is safe)
    free(serverName);
    serverName = NULL;
    free(team1Name);
    team1Name = NULL;
    free(team2Name);
    team2Name = NULL;
}

// Clean up persistent variables after the loop finishes
free(serverName);
free(team1Name);
free(team2Name);

Key Takeaways

  1. Only put What You Own: You only need to call json_object_put on objects you created directly (like the one returned by json_object_from_file). Child objects fetched via get_ex or array_get_idx are managed by the root object.
  2. Copy Internal Strings: Never save pointers returned by json_object_get_string long-term—use strdup to copy them to your own buffer, and free that buffer when you're done.
  3. Clean Up Resources in Loops: Always free manually allocated memory (like the duplicated strings) between loop iterations to avoid leaks.
  4. Validate Types (Optional but Recommended): Add checks with json_object_is_type (e.g., json_object_is_type(portInConfig, json_type_int)) to ensure the config file has the correct data types, preventing crashes from invalid casts.

内容的提问来源于stack exchange,提问作者Haxk20

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:42:35