Search code examples
chashmapcjson

Using Item from Hashmap causes segmentation fault


I am trying to fill a hashmap of Spritesheets. The data for the Spritesheet is read from a json file.

I am using hashmap.c for the hashmap and cJSON for parsing the json data

The SpriteSheet struct

typedef struct
{
    char* name;
    char* path;
    int width;
    int height;
} SpriteSheet;

Example Json Data

"spriteSheets": [
    {
        "name": "player",
        "path": "player.png",
        "width": 192,
        "height": 64
    }
]

The Code

spriteSheetHashMap = hashmap_new(sizeof(SpriteSheet), 0, 0, 0, spriteSheetHash, spriteSheetCompare, NULL, NULL);

cJSON* textureJson = cJSON_Parse(textureJsonString);

cJSON* spriteSheetsJson = cJSON_GetObjectItemCaseSensitive(textureJson, "spriteSheets");

cJSON* spriteSheetJson;
cJSON_ArrayForEach(spriteSheetJson, spriteSheetsJson)
{
    char* sheetName = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "name")->valuestring;
    char* sheetPath = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "path")->valuestring;
    int sheetWidth = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "width")->valueint;
    int sheetHeight = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "height")->valueint;

    hashmap_set(spriteSheetHashMap, &(SpriteSheet){
        .name=sheetName,
        .path=sheetPath,
        .width=sheetWidth, .height=sheetHeight,
        .spriteHashMap=spriteHashMap
    });
}

cJSON_Delete(textureJson);

When I access this in some other file, I get a segmentation fault

SpriteSheet* spriteSheet = hashmap_get(spriteSheetHashMap, &(SpriteSheet){ .name="map" });
printf("%s, %s", spriteSheet->name, spriteSheet->path); // This line causes the segmentation fault

But, If I add the items explicitly, it doesn't segfault and prints the values

hashmap_set(spriteSheetHashMap, &(SpriteSheet){
        .name="map",
        .path="image.png",
        .width=4, .height=8
});
// OR
char* a = "map";
char* b = "image.png";
hashmap_set(spriteSheetHashMap, &(SpriteSheet){
        .name=a,
        .path=b,
        .width=4, .height=8
});

Why is this happening? How can I fix it?


Solution

  •     char* sheetName = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "name")->valuestring;
        char* sheetPath = cJSON_GetObjectItemCaseSensitive(spriteSheetJson, "path")->valuestring;
    

    The two lines of code above get pointers to parts of spriteSheetJson.

    hashmap_set(spriteSheetHashMap, &(SpriteSheet){
        .name=sheetName,
        .path=sheetPath,
        .width=sheetWidth, .height=sheetHeight,
        .spriteHashMap=spriteHashMap
        });
    

    The line of code above saves those pointers.

    cJSON_Delete(textureJson);
    

    But this line of code above deletes the object that those pointers pointed into. They now point to where the JSON object's data used to be.

    SpriteSheet* spriteSheet = hashmap_get(spriteSheetHashMap, &(SpriteSheet){ .name="map" });
    printf("%s, %s", spriteSheet->name, spriteSheet->path); // This line causes the segmentation fault
    

    This code tries to dereference the pointers you saved, pointers that pointed to parts of an object that no longer exists.

    You need to make copies of the data. The easiest way is to call strdup on the values returned by cJSON_GetObjectItemCaseSensitive. Then they're yours to free when you are done.