1 Replies - 109 Views - Last Post: 25 February 2018 - 09:52 PM Rate Topic: -----

#1 exapno   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 25-February 18

How to resolve memory leak in GEDCOM parser?

Posted 25 February 2018 - 09:34 PM

Hi, I am attempting to resolve some memory leak issues I am having in a GEDCOM parser I am attempting to make.

I believe that the issue is in that I am overwriting an existing pointer where I am creating new individuals/families (allocating memory). Lines 68 and 99.

I have tried freeing to pointer before allocating more memory, however, this seems to lead to more issues and I am not confident that it's the best approach. I suspect this may be changing the address of all the individuals or it might be pointing to the same address every time but my lists seem to be populating as expected.

I would very much appreciate any advice/help.

    GEDCOMobject *newGEDCOM = malloc(sizeof(GEDCOMobject));
    *obj = newGEDCOM;
    GEDCOMerror error;
    error.type = OK;
    error.line = 1;

    FILE *file = fopen(fileName, "r");
    char currentRecord[4];
    size_t n = 0;
    int c;

    if (file == NULL)
        return error; //could not open file
    fseek(file, 0, SEEK_END);
    fseek(file, 0, SEEK_SET);

    enum file_level
    {
        upper_level,
        mid_level,
        lower_level
    } file_level = upper_level;

    char line[255] = {0}; // max gedcon line length
    int index = 0;
    int prev = 0;

    Individual *newIndividual = NULL;

    Header *newHeader = NULL;
    Submitter *newSubmitter = NULL;
    Family *newFamily = NULL;

    List individuals = {NULL};
    List families = {NULL};

    while ((c = fgetc(file)) != EOF)
    {
        switch (file_level)
        {
        case upper_level:
            // check top level
            line[index++] = (char)c;

            if (c == '\n')
            {
                memmove(line, line + 1, strlen(line + 1) + 1);
                char **args = NULL;
                tokenizeLine(line, &args);

                if (strcmp(args[0], "HEAD") == 0 || strcmp(args[0], "HEAD\n") == 0)
                {
                    strcpy(currentRecord, "HEAD");
                    newHeader = calloc(5, sizeof(Header));
                    newGEDCOM->header = newHeader;
                    printf("HEAD Created \n");
                }
                if (args[1] != NULL)
                {
                    if (strcmp(args[1], "INDI") == 0 || strcmp(args[1], "INDI\n") == 0)
                    {
                        IndiTracker *it = malloc(sizeof(IndiTracker));
                        it->identifier = malloc(strlen(args[0]) + 1);

                        strcpy(currentRecord, "INDI");

                        // problem is here
                        newIndividual = calloc(5, sizeof(Individual));
                        it->individual = newIndividual;

                        strncpy(it->identifier, args[0], strlen(args[0]) + 1);

                        if (individuals.length <= 0)
                        {
                            individuals = initializeList(&printIndiTracker, &deleteIndiTracker, &compareIndiTracker);
                            insertFront(&individuals, it);
                            printf("Created INDIVIDUALS list and added %s \n", it->identifier);
                        }
                        else
                        {
                            insertBack(&individuals, it);
                            printf("ADDED %s to INDIVIDUALS list \n", it->identifier);
                        }
                    }
                    if (strcmp(args[1], "SUBM") == 0 || strcmp(args[1], "SUBM\n") == 0)
                    {
                        strcpy(currentRecord, "SUBM");
                    }
                }
                if (args[1] != NULL)
                {
                    if (strcmp(args[1], "FAM") == 0 || strcmp(args[1], "FAM\n") == 0)
                    {
                        FamTracker *ft = malloc(sizeof(FamTracker));
                        ft->identifier = malloc(strlen(args[0]) + 1);

                        strcpy(currentRecord, "FAM");

                        newFamily = calloc(5, sizeof(Family));
                        ft->family = newFamily;

                        strncpy(ft->identifier, args[0], strlen(args[0]) + 1);

                        if (families.length <= 0)
                        {
                            families = initializeList(&printFamTracker, &deleteFamTracker, &compareFamTracker);
                            insertFront(&families, ft);
                            printf("FAMILES list created and added %s \n", ft->identifier);
                        }
                        else
                        {
                            insertBack(&families, ft);
                            printf("ADDED %s to FAMILIES list \n", ft->identifier);
                        }
                    }
                }

                // reset the stuff
                index = 0;
                free(args);
                memset(line, 0, 255);
            }

            if (prev == '\n')
                if (c == '1')
                    file_level = mid_level;
            break;
        case mid_level:
            if (prev != '\n')
                line[index++] = (char)c;

            if (c == '\n')
            {
                memmove(line, line + 1, strlen(line + 1) + 1);
                char **args = NULL;

                tokenizeLine(line, &args);

                if (strcmp(currentRecord, "HEAD") == 0)
                {
                    if (strcmp(args[0], "SOUR") == 0)
                    {
                        if (newGEDCOM->header != NULL)
                        {
                            strncpy(args[1], newGEDCOM->header->source, strlen(args[1]) + 1);
                            printf("%s Added to Header \n", args[0]);
                        }
                        else
                        {
                            error.type = INV_HEADER;
                            printf("Header doesn't exist \n");
                        }
                    }
                    else if (strcmp(args[0], "GEDC") == 0 || strcmp(args[0], "GEDC\n") == 0)
                    {
                        strcpy(currentRecord, "GEDC");
                    }
                    else if (strcmp(args[0], "CHAR") == 0)
                    {
                        if (strcmp(args[0], "ANSEL"))
                        {
                            newGEDCOM->header->encoding = ANSEL;
                        }
                        else if (strcmp(args[0], "UTF8"))
                        {
                            newGEDCOM->header->encoding = UTF8;
                        }
                        else if (strcmp(args[0], "UNICODE"))
                        {
                            newGEDCOM->header->encoding = UNICODE;
                        }
                        else if (strcmp(args[0], "ASCII"))
                        {
                            newGEDCOM->header->encoding = ASCII;
                        }

                        printf("Set CHARSET to %s", args[1]);
                    }
                    else if (strcmp(args[0], "SUBM") == 0)
                    {
                        newSubmitter = malloc(sizeof(Submitter));
                        newGEDCOM->header->submitter = newSubmitter;

                        printf("New SUBMITTER: %s", args[1]);
                    }
                    else
                    {
                        int index = 1;
                        int valueSize = 0;
                        Field *toAdd = malloc(sizeof(Field));

                        while (args[index] != NULL)
                        {
                            valueSize += strlen(args[index]) + 2;
                            index++;
                        }
                        index = 1;

                        toAdd->tag = malloc(strlen(args[0]) + 1);
                        toAdd->value = calloc(valueSize, valueSize);

                        strncpy(toAdd->tag, args[0], strlen(args[0]) + 1);
                        while (args[index] != NULL)
                        {
                            strncat(toAdd->value, args[index], strlen(args[index]) + 1);
                            strncat(toAdd->value, " ", 1);
                            index++;
                        }
                        index = 1;

                        if (newGEDCOM->header->otherFields.length > 0)
                        {
                            insertBack(&(newGEDCOM->header->otherFields), toAdd);
                            printf("Added %s field to OTHERFIELDS in %s \n", toAdd->tag, currentRecord);
                        }
                        else
                        {
                            newGEDCOM->header->otherFields = initializeList(&printIndividual, &deleteIndividual, &compareIndividuals);
                            insertFront(&(newGEDCOM->header->otherFields), toAdd);

                            printf("Created OTHERFIELDS list and added %s field \n", toAdd->tag);
                        }
                    }
                }
                if (strcmp(currentRecord, "INDI") == 0)
                {
                    if (strcmp(args[0], "NAME") == 0)
                    {
                        if (args[2] == NULL)
                        {
                            newIndividual->givenName = malloc(strlen(args[1]) + 1);
                            //memset(newIndividual->givenName, 0, strlen(args[1]) + 1);

                            strncpy(newIndividual->givenName, args[1], strlen(args[1]) + 1);

                            printf("CREATED INDIVIDUAL %s", newIndividual->givenName);
                        }
                        else if (args[2] != NULL)
                        {
                            args[2]++;
                            args[2][strlen(args[2]) - 2] = 0;

                            newIndividual->givenName = malloc(strlen(args[1]) + 1);

                            newIndividual->surname = malloc(strlen(args[2]) + 1);

                            strncpy(newIndividual->givenName, args[1], strlen(args[1]) + 1);
                            strncpy(newIndividual->surname, args[2], strlen(args[2]) + 1);

                            printf("CREATED INDIVIDUAL %s %s \n", newIndividual->givenName, newIndividual->surname);
                        }

                        //free(newIndividual->givenName);
                    }
                    else if (strcmp(args[0], "ADOP") == 0 ||
                             strcmp(args[0], "BIRT") == 0 ||
                             strcmp(args[0], "BAPM") == 0 ||
                             strcmp(args[0], "BARM") == 0 ||
                             strcmp(args[0], "BASM") == 0 ||
                             strcmp(args[0], "BLES") == 0 ||
                             strcmp(args[0], "BURI") == 0 ||
                             strcmp(args[0], "CENS") == 0 ||
                             strcmp(args[0], "CHR") == 0 ||
                             strcmp(args[0], "CHRA") == 0 ||
                             strcmp(args[0], "CONF") == 0 ||
                             strcmp(args[0], "CREM") == 0 ||
                             strcmp(args[0], "DEAT") == 0 ||
                             strcmp(args[0], "EMIG") == 0 ||
                             strcmp(args[0], "FCOM") == 0 ||
                             strcmp(args[0], "GRAD") == 0 ||
                             strcmp(args[0], "IMMI") == 0 ||
                             strcmp(args[0], "NATU") == 0 ||
                             strcmp(args[0], "ORDN") == 0 ||
                             strcmp(args[0], "RETI") == 0 ||
                             strcmp(args[0], "PROB") == 0 ||
                             strcmp(args[0], "WILL") == 0 ||
                             strcmp(args[0], "EVEN") == 0)
                    {
                        if (newIndividual->events.length > 0)
                        {
                            // TODO: EVENTS
                            insertBack(&(newIndividual->events), newFamily);
                            printf("ADDED EVENT %s TO %s", args[1], newIndividual->givenName);
                        }
                        else
                        {
                            newIndividual->events = initializeList(&printIndividual, &deleteIndividual, &compareIndividuals);
                            insertFront(&(newIndividual->events), newFamily);
                            printf("CREATED EVENT FOR %s and ADDED EVENT %s", newIndividual->givenName, args[1]);
                        }
                    }
                    else if (strcmp(args[0], "FAMS") == 0)
                    {
                        FamTracker *ft = {NULL};

                        if (families.length <= 0)
                        {
                            ft = malloc(sizeof(FamTracker));
                            ft->family = calloc(5, sizeof(Family));
                            ft->identifier = malloc(strlen(args[1]) + 1);

                            strncpy(ft->identifier, args[1], strlen(args[1]) + 1);

                            families = initializeList(&printFamTracker, &deleteFamTracker, &compareFamTracker);
                            insertFront(&families, ft);
                            printf("FAMILES list created and added %s", ft->identifier);
                        }
                        else
                        {
                            ft = getFromBack(families);
                            Node *temp = families.head;

                            while (temp->next != NULL)
                            {
                                if (strcmp(((FamTracker *)(temp->data))->identifier, args[1]))
                                    ft = (FamTracker *)temp->data;

                                temp = temp->next;
                            }

                            //printf("last fam: %s \n", ft->identifier);
                        }

                        if (newIndividual->families.length > 0)
                        {
                            insertBack(&(newIndividual->families), ft->family);
                            printf("ADDED %s TO FAMILY %s", newIndividual->givenName, args[1]);
                        }
                        else
                        {
                            newIndividual->families = initializeList(&printFamily, &deleteFamily, &compareFamilies);
                            insertFront(&(newIndividual->families), ft->family);
                            printf("%s HAS FAMILY %s", newIndividual->givenName, args[1]);
                        }
                    }
                    else
                    {
                        int index = 1;
                        int valueSize = 0;
                        Field *toAdd = malloc(sizeof(Field));

                        while (args[index] != NULL)
                        {
                            valueSize += strlen(args[index]) + 2;
                            index++;
                        }
                        index = 1;

                        toAdd->tag = malloc(strlen(args[0]) + 1);
                        toAdd->value = calloc(valueSize, valueSize);

                        strncpy(toAdd->tag, args[0], strlen(args[0]) + 1);
                        while (args[index] != NULL)
                        {
                            strncat(toAdd->value, args[index], strlen(args[index]) + 1);
                            strncat(toAdd->value, " ", 1);
                            index++;
                        }
                        index = 1;

                        if (newIndividual->otherFields.length > 0)
                        {
                            insertBack(&(newIndividual->otherFields), toAdd);
                            printf("Added %s field to OTHERFIELDS in %s \n", toAdd->tag, newIndividual->givenName);
                        }
                        else
                        {
                            newIndividual->otherFields = initializeList(&printField, &deleteField, &compareFields);
                            insertFront(&(newIndividual->otherFields), toAdd);

                            printf("Created OTHERFIELDS list and added %s field for %s \n", toAdd->tag, newIndividual->givenName);
                        }

                    }

                }

                // reset the stuff
                index = 0;
                free(args);
                memset(line, 0, 255);
            }

            if (prev == '\n')
            {
                if (c == '0')
                    file_level = upper_level;
                else if (c == '2')
                    file_level = lower_level;
            }
            break;
        case lower_level:
            // check bottom level type
            if (prev != '\n')
                line[index++] = (char)c;

            if (c == '\n')
            {
                memmove(line, line + 1, strlen(line + 1) + 1);
                char **args = NULL;

                //printf("line: %s \n", line);
                tokenizeLine(line, &args);

                if (strcmp(currentRecord, "HEAD") == 0)
                {
                    int index = 1;
                    int valueSize = 0;
                    Field *toAdd = malloc(sizeof(Field));

                    while (args[index] != NULL)
                    {
                        valueSize += strlen(args[index]) + 2;
                        index++;
                    }
                    index = 1;

                    toAdd->tag = malloc(strlen(args[0]) + 1);
                    toAdd->value = calloc(valueSize, valueSize);

                    strncpy(toAdd->tag, args[0], strlen(args[0]) + 1);
                    while (args[index] != NULL)
                    {
                        strncat(toAdd->value, args[index], strlen(args[index]) + 1);
                        strncat(toAdd->value, " ", 1);
                        index++;
                    }
                    index = 1;

                    if (newGEDCOM->header != NULL)
                    {
                        if (newGEDCOM->header->otherFields.length > 0)
                        {
                            insertBack(&(newGEDCOM->header->otherFields), toAdd);
                            printf("Added %s field to OTHERFIELDS in %s \n", args[0], currentRecord);
                        }
                        else
                        {
                            newGEDCOM->header->otherFields = initializeList(&printField, &deleteField, &compareFields);
                            insertFront(&(newGEDCOM->header->otherFields), toAdd);

                            printf("Created OTHERFIELDS list and added %s field \n", toAdd->tag);
                        }
                    }
                    else
                    {
                        error.type = INV_HEADER;
                        printf("Header doesn't exist \n");
                    }

                }
                else if (strcmp(args[0], "VERS") == 0 && strcmp(currentRecord, "GEDC") == 0)
                {
                    if (newGEDCOM->header != NULL)
                    {
                        newGEDCOM->header->gedcVersion = atof(args[1]);
                        printf("GEDC VERSION set to %.1f in %s \n", atof(args[1]), currentRecord);
                        strcpy(currentRecord, "HEAD");
                    }
                    else
                    {
                        error.type = INV_HEADER;
                        printf("Header doesn't exist \n");
                    }
                }
                else
                {
                    Field *toAdd = malloc(sizeof(Field));
                    toAdd->tag = malloc(strlen(args[0]) * sizeof(char) + 1);
                    toAdd->value = malloc(strlen(args[1]) * sizeof(char) + 1);

                    strcpy(toAdd->tag, args[0]);
                    strcpy(toAdd->value, args[1]);

                    if (newGEDCOM->header->otherFields.length > 0)
                    {
                        insertBack(&(newGEDCOM->header->otherFields), toAdd);
                        printf("Added %s field to OTHERFIELDS in %s \n", toAdd->tag, currentRecord);
                    }
                    else
                    {
                        newGEDCOM->header->otherFields = initializeList(&printIndividual, &deleteIndividual, &compareIndividuals);
                        insertFront(&(newGEDCOM->header->otherFields), toAdd);

                        printf("Created OTHERFIELDS list and added %s field \n", toAdd->tag);
                    }

                }

                // reset the stuff
                index = 0;
                free(args);
                memset(line, 0, 255);
            }

            if (prev == '\n')
                if (c == '1')
                    file_level = mid_level;

            break;
        default:
            printf("unidentified file level");
            break;
        }
        prev = c;

        n++;
    }

    printf("END \n");
    clearList(&individuals);
    clearList(&families);

    return error;



Is This A Good Question/Topic? 0
  • +

Replies To: How to resolve memory leak in GEDCOM parser?

#2 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6216
  • View blog
  • Posts: 21,454
  • Joined: 05-May 12

Re: How to resolve memory leak in GEDCOM parser?

Posted 25 February 2018 - 09:52 PM

Wow! 514 lines all in a single function! 70's style C code is alive and well. The modern style is to break things up into smaller functions since the calling overhead is not as bad as it was when back when CPUs and memory was slow.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1