Search code examples
cmemory-leaksstrdup

Strdup free still result in memory leaks


I am still not able to get my head around why there is still memory leak here because of strdup (that's what the error says), I made sure I freed all the allocated memory of strdup before removing the node and I freed all the nodes at the end of the program. What did I miss?

Here is the code I wrote:

struct background_processes *head = NULL;

struct background_processes {
    int pid;
    char *cmd_name;
    struct background_processes *next;
};

// Add a background process to the Background processes LinkedList
void add_background_process(int pid, char *name) {
    if (head == NULL) {
        head = malloc(sizeof(struct background_processes));
        if (head == NULL) {
            exit(EXIT_FAILURE);
        }
        head->pid = pid;
        head->cmd_name = strdup(name);
        head->next = NULL;
    } else {
        struct background_processes *current = head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = malloc(sizeof(struct background_processes));
        if (current->next == NULL)
            exit(EXIT_FAILURE);
        current->next->pid = pid;
        current->next->cmd_name = strdup(name);
        current->next->next = NULL;
    }
}

// Remove a background process from the Background processes LinkedList
void remove_background_process(int pid) {
    struct background_processes *current = head;
    struct background_processes *prev = NULL;
    while (current != NULL) {
        /* If the process is running */
        if (pid == current->pid) {
            if (current == head) {
                head = head->next;
                free(current->cmd_name);
                free(current);
                current = head;
            } else {
                prev->next = current->next;
                free(current->cmd_name);
                free(current);
                current = prev->next;
            }
        } else {
            prev = current;
            current = current->next;
        }
    }
}

void free_linkedlist() {
    struct background_processes *current = head;
    struct background_processes *after;

    while (current != NULL) {
        after = current->next;
        free(current->cmd_name);
        free(current);
        current = after;
    }
}

int main() {
    // Some code 

    while (1) {
        // Some other code
        
        execute_pipeline(l);
    }
    // Freeing all allocated memory
    free_linkedlist();
}

I appreciate your help. Thanks!


Solution

  • There is no visible leak in the posted code. The problem must be somewhere else:

    • the list might be corrupted during the execution of unpublished code.
    • unpublished code might allocate memory with strdup() and leak it.
    • some of the nodes might get modified, overwriting cmd_name fields.
    • some other undefined behavior might have this side effect.

    It is recommended to avoid duplicating the allocation and deallocation code.

    Here is a modified version:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct background_processes {
        int pid;
        char *cmd_name;
        struct background_processes *next;
    };
    
    struct background_processes *head = NULL;
    
    // Add a background process to the Background processes LinkedList
    void add_background_process(int pid, const char *name) {
        // Allocate and initialize a new node
        struct background_processes *node = malloc(sizeof(*node));
        if (node == NULL) {
            exit(EXIT_FAILURE);
        }
        node->pid = pid;
        node->cmd_name = strdup(name);
        node->next = NULL;
    
        // Append the new node to the list
        if (head == NULL) {
            head = node;
        } else {
            struct background_processes *current = head;
            while (current->next != NULL) {
                current = current->next;
            }
            current->next = node;
        }
    }
    
    // Remove a background process from the Background processes LinkedList
    void remove_background_process(int pid) {
        struct background_processes *current = head;
        struct background_processes *prev = NULL;
        while (current != NULL) {
            struct background_processes *next = current->next;
            // If the process is running
            if (pid == current->pid) {
                // detach the node
                if (current == head) {
                    head = next;
                } else {
                    prev->next = next;
                }
                // deallocate the node
                free(current->cmd_name);
                free(current);
                current = next;
            } else {
                prev = current;
                current = next;
            }
        }
    }
    
    void free_linkedlist(void) {
        struct background_processes *current = head;
        while (current != NULL) {
            struct background_processes *next = current->next;
            free(current->cmd_name);
            free(current);
            current = next;
        }
    }