clinked-listfree

Memory Management Issue with Linked List Freeing in C Program


I'm currently tackling the Advent of Code 2022 Day 9 challenge and encountered an unexpected issue with freeing a dynamically allocated linked list in my C program. Although my code runs smoothly without freeing the linked list, adhering to best practices by deallocating the memory leads to unexpected behavior. Previously, similar code utilizing the same linked list freeing function worked flawlessly. I'm puzzled about what could be causing this discrepancy.

Here's a condensed version of the relevant parts of my code: (or you can also see the full code here)

// ... some code ....

void freeLinkList(IntPairNode *linkList) {
  while (linkList != NULL) {
    IntPairNode *temp = linkList;
    linkList = linkList->next;
    free(temp);
  }
}

int findVisited(IntPair *pairList, const Instruction *instructList) {
  // pairList and instructList must be properly terminated.
  if (pairList[0].isNull == '\0' || pairList[1].isNull == '\0') {
    perror("pairList must have at least 2 elements");
    return -1;
  }
  IntPairNode *linkList = malloc(sizeof(IntPairNode));
  linkList->x = 0;
  linkList->y = 0;
  int linkListLength = 1;

  // ...
  // freeLinkList(linkList); // problemetic line

  return linkListLength;
}

// ... some helper function ....

int main(int argc, char *argv[]) {
  FILE *file = NULL;
  if (!fileOpener(argc, argv, &file)) {
    return 1;
  }
  Instruction *instructList = buildInstructList(file);
  if (instructList == NULL) {
    printf("Failed to build instruction list.\n");
    return 1;
  }
  fclose(file);

  IntPair pairList1[3];
  IntPair pairList2[11];
  for (int i = 0; i < 2; i++) {
    pairList1[i].x = 0;
    pairList1[i].y = 0;
    pairList1[i].isNull = 'F';
  }
  pairList1[2].isNull = '\0';

  for (int i = 0; i < 10; i++) {
    pairList2[i].x = 0;
    pairList2[i].y = 0;
    pairList2[i].isNull = 'F';
  }
  pairList2[10].isNull = '\0';

  int visited1 = findVisited(pairList1, instructList);
  printf("%d\n", visited1); // always works
  int visited2 = findVisited(pairList2, instructList);
  printf("%d\n", visited2);
  free(instructList);
}

The problem arises specifically in the findVisited function when attempting to free the linked list using the freeLinkedList function. However, when I comment out the freeLinkList(linkList) line, the program runs without any issues, although I'm aware this could lead to memory leaks.

I'd appreciate any insights or suggestions on how to address this memory management issue while ensuring proper deallocation of the linked list.


Solution

  •   IntPairNode *linkList = malloc(sizeof(IntPairNode));
      linkList->x = 0;
      linkList->y = 0;
      int linkListLength = 1;
    
      // ...
      // freeLinkList(linkList); // problemetic line
    

    Note that you have not assigned a value to the next member of your linkList struct. This value is indeterminate, which may be NULL but may also be anything else, so your freeLinkList function doesn't see that the list only contains one node and ends up trying to dereference an uninitialized pointer, leading to undefined behavior.

    To avoid this you could explicit initialize next.

      IntPairNode *linkList = malloc(sizeof(IntPairNode));
      linkList->x = 0;
      linkList->y = 0;
      linkList->next = NULL;
    

    Or you might allocate using calloc rather than malloc which initializes the allocated memory to zero.

      IntPairNode *linkList = calloc(1, sizeof(IntPairNode));