Segmentation Fault after incrementing number, making a JSON interpreter in C

Viewed 44

I am making a JSON interpreter. The problem I am running across is that every time I add the value of an object, it will result in a segmentation fault once i call json->pairsSize++. I have tried looking through the code, and found that every time i call realloc or malloc on json->pairs[json->pairsSize]->values inside of case NEXT_PAIR, it will cause the error, but if i were to comment out the json->pairsSize++, the code will run fine, since it is replacing already existing data.

json.c

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdbool.h>

#include <json.h>

/* Local Data */
void remove_spacing(char * contents);

/* Init/Cleanup */
struct JSON * init_json() {
    struct JSON * json = malloc(sizeof(struct JSON)+1);
    json->objectName = malloc(1);
    json->objectName[0] = '\0';
    json->pairs = malloc(sizeof(struct Pair *));
    json->pairsSize = 0;
    json->objects = malloc(sizeof(struct JSON *));
    json->objectsSize = 0;
    json->prev = NULL;
    return json;
}
struct Pair * init_pair() {
    struct Pair * pair = malloc(sizeof(struct Pair));
    pair->key = malloc(1);
    pair->key[0] = '\0';
    pair->values = malloc(sizeof(void*));
    pair->valuesSize = 0;
    return pair;
}
void interpret(struct JSON * json, char * filePath) {
    FILE * json_file;
    json_file = fopen(filePath, "r");

    if (!json_file) {
        printf("Couldn't find JSON file %s\n", filePath);
        exit(EXIT_FAILURE);
    }

    char * jsonContent = malloc(1);
    unsigned int jsonContentPtr = 0;
    char ch;
    while(!feof(json_file)) {
        ch = fgetc(json_file);
        jsonContent = realloc(jsonContent, jsonContentPtr+1);
        jsonContent[jsonContentPtr] = ch;
        jsonContentPtr++;
    }
    jsonContent[jsonContentPtr] = '\0';
    printf("%s\n", jsonContent);

    // Now the fun begins...
    size_t jsonContentLen = strlen(jsonContent);
    char * placeHolder = malloc(1);
    unsigned int placeHolderIndex = 0;
    bool isArray = false;

    for (size_t i = 0; i < jsonContentLen; i++) {
        switch(jsonContent[i]) {
            case OBJECT_OPEN: {
                if (i != 0 && isArray == false) {
                    struct JSON * newJson = init_json();
                    add_object(json, newJson);
                    json = json->objects[json->objectsSize-1];

                    // // Set objectName
                    placeHolder[placeHolderIndex] = '\0';
                    set_objectName(json, placeHolder);
                    placeHolder[0] = '\0';
                    placeHolderIndex = 0;
                }
                else if (isArray == true) {

                }
                break;
            }
            case OBJECT_CLOSE: {
                // Add last value

                if (json->prev != NULL) {
                    json = json->prev;
                }
                break;
            }
            case KEYPAIR_DELIM: {
                placeHolder[placeHolderIndex] = '\0';

                json->pairs = realloc(json->pairs, sizeof(struct Pair *) * (json->pairsSize+1));
                json->pairs[json->pairsSize] = init_pair();
                json->pairs[json->pairsSize]->key = realloc(json->pairs[json->pairsSize]->key, placeHolderIndex+1);
                strncpy(json->pairs[json->pairsSize]->key, placeHolder, placeHolderIndex+1);
                printf("%s\n", json->pairs[json->pairsSize]->key);

                placeHolder[0] = '\0';
                placeHolderIndex = 0;

            }
            case NEXT_PAIR: {
                placeHolder[placeHolderIndex] = '\0';
                size_t placeHolderLen = strlen(placeHolder);

                // Where the error occurs everytime i have json->pairsSize++ uncommented
                json->pairs[json->pairsSize]->values = realloc(json->pairs[json->pairsSize]->values, sizeof(void *) * (json->pairs[json->pairsSize]->valuesSize+1));
                json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize] = malloc(placeHolderLen+1);
                
                strncpy(json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize], placeHolder, placeHolderLen+1);
                printf("%s\n", json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize]);

                placeHolder[0] = '\0';
                placeHolderIndex = 0;
                json->pairs[json->pairsSize]->valuesSize++;
                
                if (isArray == false) {

                    // Causes a segmentation fault for some reason, can't figure it out
                    json->pairsSize++;
                }
                break;
            }
            case DOUBLE_QUOTE: {
                break;
            }
            default: {
                placeHolder = realloc(placeHolder, placeHolderIndex+1);
                placeHolder[placeHolderIndex] = jsonContent[i];
                placeHolderIndex++;
                break;
            }
        }
    }

    free(placeHolder);
    fclose(json_file);
}

/* Setters */
void set_objectName(struct JSON * json, char * value) {
    size_t valueLen = strlen(value);
    json->objectName = realloc(json->objectName, valueLen+1);
    strcpy(json->objectName, value);
}

void add_object(struct JSON * json, struct JSON * newJSON) {
    newJSON->prev = json;
    json->objects = realloc(json->objects, sizeof(struct JSON *)*(json->objectsSize+1));
    json->objects[json->objectsSize] = newJSON;
    json->objectsSize++;
}

json.h

#ifndef C_JSON_H
#define C_JSON_H

#define DOUBLE_QUOTE '"'
#define KEYPAIR_DELIM ':'
#define OBJECT_OPEN '{'
#define OBJECT_CLOSE '}'
#define ARRAY_OPEN '['
#define ARRAY_CLOSE ']'
#define NEXT_PAIR ','

struct Pair {
    char * key;
    void ** values;
    unsigned int valuesSize;
};

struct JSON {
    char * objectName;

    struct Pair ** pairs;
    unsigned int pairsSize;

    struct JSON ** objects;
    unsigned int objectsSize;
    struct JSON * prev;
};

struct JSON * init_json();
struct Pair * init_pair();
void interpret(struct JSON * json, char * filePath);

/* Setters */
void set_objectName(struct JSON * json, char * value);

#endif

main.c

#include <json.h>
#include <stdio.h>

int main(void) {
    struct JSON * json = init_json();
    interpret(json, "./tests/objects.json");
    printf("\n%s\n", json->objects[0]->pairs[0]->key);
    return 0;
}

JSON test file (objects.json)

{
    "Test-Object-1": {
        "Song": "My Heroine",
        "Author": "Silverstein",
        "Length": 240
    }
}
1 Answers

problems i have identified:

  • init_json() allocates 1 extra byte for json struct for some reason

  • interpret() uses a loop with !feof() condition which is incorrect

  • interpret() uses char ch for fgetc() , it should use int since fgetc can return EOF

  • interpret() has a buffer overflow in line jsonContent[jsonContentPtr] = '\0';

The code looks quite messy, you should take some time to rethink your approach.

Related