调试内存泄漏

时间:2016-05-05 03:57:21

标签: c memory-leaks valgrind

Valgrind报告内存泄漏:

[18370]
==18367== Conditional jump or move depends on uninitialised value(s)
==18367==    at 0x4C2EDA1: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18367==    by 0x40334C: runCmd (main.c:444)
==18367==    by 0x40334C: command (main.c:661)
==18367==    by 0x40198E: main (main.c:755)
==18367== 
==18367== 
==18367== HEAP SUMMARY:
==18367==     in use at exit: 82,829 bytes in 175 blocks
==18367==   total heap usage: 274 allocs, 99 frees, 99,482 bytes allocated
==18367== 
==18367== 512 bytes in 1 blocks are definitely lost in loss record 70 of 93

********************* TEST WILDCARDS 
***** Press any key to listing all files in current directory...
==18367==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18367==    by 0x402A71: runCmd (main.c:307)
==18367==    by 0x402A71: command (main.c:661)
==18367==    by 0x40198E: main (main.c:755)
==18367== 
==18367== 2,585 (512 direct, 2,073 indirect) bytes in 1 blocks are definitely lost in loss record 80 of 93
==18367==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18367==    by 0x402A5D: runCmd (main.c:305)
==18367==    by 0x402A5D: command (main.c:661)
==18367==    by 0x40198E: main (main.c:755)
==18367== 
==18367== LEAK SUMMARY:
==18367==    definitely lost: 1,024 bytes in 2 blocks
==18367==    indirectly lost: 2,073 bytes in 6 blocks
==18367==      possibly lost: 0 bytes in 0 blocks
==18367==    still reachable: 79,732 bytes in 167 blocks
==18367==         suppressed: 0 bytes in 0 blocks
==18367== Reachable blocks (those to which a pointer was found) are not shown.
==18367== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==18367== 

这是有问题的代码:

main.c:444(" free(*matrix);")

 int row;
    if (*matrix != NULL) {
        for (row = 0; row < BUFFER_SIZE; row++) {
                free((*matrix)[row]);
        }
        free(*matrix);
        *matrix = NULL;
    }

main.c:307

 matrix[0] = malloc(BUFFER_SIZE * sizeof(**matrix));

main.c:305

char ***matrix = malloc(BUFFER_SIZE * sizeof(char *));

整个函数runCmd

static int runCmd(const char *cmd) {
    char *pString1[z];
    char *pString[z];
    *pString1 = "\0";
    *pString = "\0";
    bool quote = false;
    char **ptr;
    struct command shellcommand[64];
    char **ptr1;
    char **argv;
    int argc = 1;
    int n = 0;
    int status = 0;

    char *pString4[z][z];
    char **pString5[z];
    int i4 = 0;
    for (int f = 0; f < z; f++) {
        pString5[f] = NULL; /* initialize */
        for (i4 = 0; i4 < z; i4++) {
            pString4[f][i4] = NULL;
        }
    }
    char ***matrix = malloc(BUFFER_SIZE * sizeof(char *));
  //  *matrix = malloc(BUFFER_SIZE * sizeof(**matrix));
    matrix[0] = malloc(BUFFER_SIZE * sizeof(**matrix));
    //  if (cmd) {
    char *cmdtmp;
    char *pString3[64];
    cmdtmp = strdup(cmd);
    ptr1 = str_split(pString3, cmdtmp, '|');
    int w = 0;
    int i2 = 0;
    for (int i = 0; ptr1[i]; i++) { /* loop for each pipeline */
        n++;                 /* save number of pipelines */
        pString5[n] = NULL;
        char *string1[z];
        int e = 0;
        *pString = "\0";
        *string1 = strdup(ptr1[i]);
        if ((*string1[0] != '\0') &&
            !isspace(*string1[0])) {
            /*   parse_command(w, ptr, string1, pString, pString5, i2, n, quote, i, string, pString1,
                              e, &argc,  &argv, pInt, pString4);
               printf("string %s", * string[i]);*/
            char *pString2[64];
            ptr = str_split(pString2, *string1, ' ');
            pString5[i2] = ptr;
            i2++;
            char *temp = {'\0'};
            int y = 0;
            int p = 0;
            for (int j = 0; ptr[j]; j++) {
                if (ptr + j && !quote && strstr(ptr[j], "'")) {
                    quote = true;
                    strcpy(temp, ptr[j]);
                    if (y < 1) {
                        y++;
                    }
                }
                while_quote(&quote, y, i, ptr, j, temp, *matrix);
                bool keep = false;
                if (ptr + j) { ;
                    if (*(ptr + j)[0] == '{') {
                        keep = true;
                    }
                    if (testFn(*(ptr + j))) {
                        matrix[i][j - p] = concat(*pString1, ptr[j]);
                        keep = false;
                        free(*pString1);
                        continue;
                    }
                    char *str;
                    if (keep) {
                        str = concat(*pString1, ptr[j]);
                        *pString1 = concat(str, " ");
                        free(str);
                        p++;
                    } else {
                        bool b1 = false;
                        int i3 = j;
                        pString4[i][0] = *pString;
                        //   printf("i: %d", i);
                        str = "\0";
                        b1 = parse(b1, i, &j, &e, ptr, i3, pString, str, pString4[i]);
                        if (make_args(pString4[i][e - 1], &argc, (const char ***) &argv)) {
                            write_command(w, argc, argv, matrix);;
                            w++;
                        }
                        else if (!b1) {
                            for (int r = 0; argv[r] != NULL; r++) {
                                matrix[i][r] = argv[r];
                            }
                        }
                    }
                }
            }
            bool boo = false;
            //  dump_argv((const char *) "d", argc, argv, boo);
        }
        free(*string1);
    }
    for (int i = 0; i < n; i++) {
        shellcommand[i].argv = matrix[i];
    }
    fflush(NULL);
    /* refactor to a function */
    pid_t pid;
    pid = fork();
    if (pid < 0) {
        perror("fork failed");
        return -1;
    }
    /* If we are the child process, then go execute the string.*/
    if (pid == 0) {
        /* spawn(cmd);*/
        fork_pipes(n, shellcommand);
    }
    /*
     * We are the parent process.
     * Wait for the child to complete.
     */

    while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
    if (pid < 0) {
        fprintf(stderr, "Error from waitpid: %s", strerror(errno));
        free(cmdtmp);
        if (ptr1) {
            for (int i = 0; ptr1[i]; i++) {
                free(ptr1[i]);
            }
            printf("\n");
            free(ptr1);
        }
        return -1;
    }
    if (WIFSIGNALED(status)) {
        fprintf(stderr, "pid %ld: killed by signal %d\n",
                (long) pid, WTERMSIG(status));
        free(cmdtmp);
        if (ptr1) {
            for (int i = 0; ptr1[i]; i++) {
                free(ptr1[i]);
            }
            printf("\n");
            free(ptr1);
        }
        return -1;
    }

    free(cmdtmp);
    if (ptr1) {
        for (int i = 0; ptr1[i]; i++) {
            free(ptr1[i]);
        }
        printf("\n");
        free(ptr1);
    }

    int row;
    if (*matrix != NULL) {
        for (row = 0; row < BUFFER_SIZE; row++) {
                free((*matrix)[row]);
        }
        free(*matrix);
        *matrix = NULL;
    }


    int z;
    for (int f = 0; f < n; f++) {
        for (z = 0; pString4[f][z]; z++) {
            free(pString4[f][z]);
        }
        // free( pString4[f]);
    }
    //free(* pString4);
    //** pString4 = NULL;

    size_t idx;
    for (int f = 0; n > 1 && f < n; f++) {
        for (idx = 0; *(pString5[f] + idx) != NULL; idx++) {
            free(*(pString5[f] + idx));
        }
        free(pString5[f]);
    }
//    free(** pString5);
    *pString5 = NULL;
    free(*matrix );
    return WEXITSTATUS(status);
}

还有关于相同行的详细报告:

==19171== 512 bytes in 1 blocks are definitely lost in loss record 77 of 101
==19171==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19171==    by 0x402A5D: runCmd (main.c:305)
==19171==    by 0x402A5D: command (main.c:661)
==19171==    by 0x40194E: main (main.c:760)
==19171== 
==19171== 512 bytes in 1 blocks are definitely lost in loss record 78 of 101
==19171==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19171==    by 0x402A71: runCmd (main.c:307)
==19171==    by 0x402A71: command (main.c:661)
==19171==    by 0x40194E: main (main.c:760)

执行可能没有错误的进程的一些后端代码:

/* Helper function that forks pipes */
void fork_pipes(int n, struct command *cmd) {
    int i;
    int in = 0;
    int fd[2];

    for (i = 0; i < n - 1; ++i) {

        if (pipe(fd) == -1) {
            err_syserr("Failed creating pipe");
        }

        spawn_proc(in, fd[1], cmd + i);
        close(fd[1]);
        in = fd[0];
    }
    if (dup2(in, 0) < 0) {
        err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
    }
    /*fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd[i].argv[0]);*/
    fprintf(stderr, "\n");
    execvp(cmd[i].argv[0], cmd[i].argv);
    err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}

使用所有代码https://github.com/montao/openshell

链接到repo

1 个答案:

答案 0 :(得分:3)

你有问题的代码的关键是这样的:

char ***matrix = malloc(BUFFER_SIZE * sizeof(char *));
matrix[0] = malloc(BUFFER_SIZE * sizeof(**matrix));

pid = fork();

/* If we are the child process, then go execute the string.*/
if (pid == 0) {
    /* spawn(cmd);*/
    fork_pipes(n, shellcommand);
}
/*
 * We are the parent process.
 * Wait for the child to complete.
 */
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));

if (*matrix != NULL) {
    for (int row = 0; row < BUFFER_SIZE; row++) {
            free((*matrix)[row]);
    }
    free(*matrix);
    *matrix = NULL;
}

free(*matrix );

首先你创建matrix这是一个指向char**数组的指针,它基本上看起来像一个3D数组。请注意,sizeof(char*)char**不匹配,因此这是一个错误,但不是一个重要错误。

然后初始化matrix的第一个元素,现在是char*的数组。但那些指针是未初始化的。您稍后将*matrix(又名matrix[0])传递给您尚未向我们展示的功能。

所以整个事情都是一团糟,因为类型不匹配,数组很大程度上未被使用,并且大小可能是错误的,我们无法看到{{{}中存在的其他错误1}}。

但泄漏 - 它来自哪里?好吧,你while_quote(),然后孩子打电话给fork()。该函数永远不会返回,并且fork_pipes()在子进程中泄漏,或者它确实返回,然后其余代码错误,因为父逻辑继续在子进程中执行。

你看,当你matrix时,你最终得到了所有记忆的两份副本,包括fork(),并且你需要在每个过程中matrix

最后,底部的free()循环似乎调用了未定义的行为,因为它对free()的元素进行操作,这些元素从未被初始化。最后的matrix是多余的,另一个是红旗;你永远不会尝试free(*matrix),这可能是那里的意思。

编辑:也许你想要这样的东西:

free(matrix)

然后:

/* returns an array of arrays of char*, all of which NULL */
char*** alloc_matrix(unsigned rows, unsigned columns) {
    char*** matrix = malloc(rows * sizeof(char**));
    if (!matrix) abort();

    for (unsigned row = 0; row < rows; row++) {
        matrix[row] = malloc(columns * sizeof(char*));
        if (!matrix[row]) abort();
        for (unsigned column = 0; column < columns; column++) {
            matrix[row][column] = NULL;
        }
    }

    return matrix;
}

假设矩阵内的元素(字符串)填充了由/* deallocates an array of arrays of char*, calling free() on each */ void free_matrix(char*** matrix, unsigned rows, unsigned columns) { for (unsigned row = 0; row < rows; row++) { for (unsigned column = 0; column < columns; column++) { free(matrix[row][column]); } free(matrix[row]); } free(matrix); } malloc()等创建的字符串,这为您提供了一对匹配的函数,可用于可靠地分配和解除分配你的矩阵。确保在每个分叉进程中释放,而不仅仅是一个。