在此 shell 模拟中,我的内存泄漏在哪里未被释放?

Where is my memory leak not being freed in this shell simulation?

我无法在使用 valgrind 工具的 shell 模拟 C 程序中找到未释放内存泄漏的位置。我还 运行 我的程序使用 gdb 调试器。 writableUsersArgs 包含“/usr/bin/vim”作为第一个元素,NULL 作为第二个元素。使用调试器,它显示数组 writableUsersArgs 被释放了两次。

包含内存泄漏的函数

int start(char* command){
        // pid uses status's value behind the scenes
        int status;
        int maxArgLength = 0;
        int argLength = 0;
        int index;

        // Split the user's command into seperate strings wherever the command has spaces
        char** usersArgs = commandDelimeter(command);
        int numberArgs = countArgs(command);
        // Calculate maxArgLength to allocate correct amount of memory
        for(index = 0; index < numberArgs; index++) {
                argLength = countLongestArg(usersArgs[index]);
                if(argLength > maxArgLength) {
                        maxArgLength = argLength;
                }
        }
        // Allocate memory for the array that gets passed to exec() function
        char* writableUsersArgs[numberArgs+1];
        for(index = 0; index < numberArgs + 1; index++) {
                writableUsersArgs[index] = (char*)malloc(maxArgLength*sizeof(char));
        }
        // Copy the strings from the read only array to a writable array of strings
        for(index = 0; index < numberArgs; index++) {
                strcpy(writableUsersArgs[index], usersArgs[index]);
        }
        // Last entry of array must be NULL for exec() function to work properly
        writableUsersArgs[index] = NULL;

        // Create a child process
        pid_t pid = fork();
        if(pid == -1) {
                printf("Error forking");
                return -1;
        } else if(pid == 0) {
                // Jumps into new child process
                execv(writableUsersArgs[0], writableUsersArgs);
                return 2;
        } else {
                // Waits for child process to terminate before proceeding
                wait(&status);
                for(index = 0; index < numberArgs + 1; index++) {
                        free(usersArgs[index]);
                        free(writableUsersArgs[index]);
                }
                free(usersArgs);
                return 1;
        }
}

Valgrind 内存检查错误消息

==670== HEAP SUMMARY:
==670==     in use at exit: 26 bytes in 2 blocks
==670==   total heap usage: 73 allocs, 71 frees, 8,432 bytes allocated
==670==
==670== 13 bytes in 1 blocks are definitely lost in loss record 1 of 2
==670==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==670==    by 0x10ABC3: createArgsArray (mysh.c:579)
==670==    by 0x10A946: commandDelimeter (mysh.c:508)
==670==    by 0x109DB0: start (mysh.c:269)
==670==    by 0x109820: executeCommandWithArgs (mysh.c:151)
==670==    by 0x109641: executeCommand (mysh.c:115)
==670==    by 0x109542: insideShell (mysh.c:83)
==670==    by 0x1094C3: main (mysh.c:63)
==670==
==670== 13 bytes in 1 blocks are definitely lost in loss record 2 of 2
==670==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==670==    by 0x109EDB: start (mysh.c:281)
==670==    by 0x109820: executeCommandWithArgs (mysh.c:151)
==670==    by 0x109641: executeCommand (mysh.c:115)
==670==    by 0x109542: insideShell (mysh.c:83)
==670==    by 0x1094C3: main (mysh.c:63)
==670==
==670== LEAK SUMMARY:
==670==    definitely lost: 26 bytes in 2 blocks
==670==    indirectly lost: 0 bytes in 0 blocks
==670==      possibly lost: 0 bytes in 0 blocks
==670==    still reachable: 0 bytes in 0 blocks
==670==         suppressed: 0 bytes in 0 blocks

start中,您使用malloc分配内存并将其分配给一个指针,然后您使用NULL覆盖指针的内容。您现在已经忘记了 malloced 的记忆。

所以,在这个循环中:

for(index = 0; index < numberArgs + 1; index++) {
    writableUsersArgs[index] = (char*)malloc(maxArgLength*sizeof(char));
}

writableUsersArgs 的每个成员都分配了一个指向由 malloc 保留的唯一内存块的指针,包括数组成员 writableUsersArgs[numberArgs]

几行之后,你写

writableUsersArgs[index] = NULL;

她的indexnumberArgs一样值。您现在已经丢失了对 writableUsersArgs[index] 之前指向的 malloced 块的所有引用。

您可能想要 运行 循环 while index < numberArgs.

这仅说明了 start 中丢失的区块。除非您显示该代码,否则我不能对 commandDelimetercreateArgsArray 中丢失的块说任何话。但我怀疑这是同样的问题。

最后的注释:我认为在调用 fork/exec

之前不需要复制 creareArgsArray 返回的字符串