0

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?

Techie-Guy
  • 131
  • 8
  • 2
    I don't think `valuestring` makes a copy of the string, it just returns the pointer. When you do `cJSON_Delete(textureJson);` all the nested pointers are freed. – Barmar Apr 26 '23 at 17:35
  • Wow, it works. Please post this as the answer. – Techie-Guy Apr 26 '23 at 17:45

1 Answers1

3
    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.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278