简体   繁体   English

家庭作业:我在某个地方有内存泄漏,但我找不到它。 关于如何更有效地使用valgrind的任何提示?

[英]Homework: I have a memory leak somewhere, but I can't find it. Any tips on how to use valgrind more effectively?

Okay, first off, fair warning, this is a project for a class. 好的,首先,公平警告,这是一个班级的项目。 I am not looking for any help on it other than fixing my memory leak. 除了修复内存泄漏之外,我不是在寻找任何帮助。 I imagine I have followed some horrendous coding practices over the space of this C code. 我想我已经在这个C代码的空间上遵循了一些可怕的编码实践。 Regardless, when I run Valgrind to search for where the memory leaks are happening, it is not at all clear to me what memory leaks I am missing. 无论如何,当我运行Valgrind来搜索内存泄漏发生的位置时,我一点都不清楚我错过了什么内存泄漏。 I know that there are at least two strings that I am not freeing, but that I malloc()ed, based purely on the size of the valgrind output. 我知道至少有两个字符串,我没有释放,但我malloc()编辑,纯粹基于valgrind输出的大小。 Because I took some of the extraneous code out of the project, the valgrind line numbers, may very well be off, because of this I marked them with comments for your convenience. 因为我从项目中获取了一些无关的代码,valgrind行号很可能已经关闭,因此为了方便起见,我将它们标记为注释。

A little background, I am writing the basic functions of a shell. 一点背景,我正在编写shell的基本功能。 It currently does the following: 它目前执行以下操作:

1.Take user input 1.接受用户输入

2.Parse the input into a cmdin struct 2.将输入解析为cmdin结构

3.Execute the command, provided it doesn't have a pipe in it. 3.执行命令,前提是它没有管道。

4.free the space from the cmdin I created, and start over at step 1. This is where the problem occurs. 4.从我创建的cmdin中取出空间,然后从步骤1重新开始。 这就是问题发生的地方。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_SIZE 1024
#define MAX_CLEN 2097152
#define READ_END 0
#define WRITE_END 1
#define CHILD_STATUS 0
struct cmdin
{
    char *cmd;
    char **args;
    int nargs;
    int pipeflag;
};

//check if the last argument of the command passed to it is a pipe.
//if so, return the position of the pipe, otherwise, return 0
//if it has already found a pipe, it will return the position of that pipe
int conpipe(struct cmdin * cmd)
{
    if(!cmd->pipeflag)
    {
        if(!strcmp(cmd->args[cmd->nargs], "|"))
        {
            return cmd->nargs;
        }
        else
        {
            return 0;
            /* PROBLEM LINE BELOW */
        }  // line 46, where valgrind claims one of the problems exists
    }
    else
    {
        //printf("pipeflag: %d\n", cmd->pipeflag);
        return (cmd->pipeflag);
    }
}

//free the command after each runthrough
int freeze(struct cmdin cmd)
{
    int i;
    for(i=0; i <= (cmd.nargs); i++)
    {
        //printf("cmd.args[%d]: %s\n",i, cmd.args[i]);
        /* PROBLEM LINE BELOW*/
        free(cmd.args[i]); //this is line 62, as noted by valgrind
    }
    free(cmd.args);
    free(cmd.cmd);
    return 0;
}

//parse input, and add a null to the end
struct cmdin * parse(char *cmd)
{
    //allocate space for the command 
    struct cmdin *ped = malloc(sizeof(struct cmdin)); 
    //declare pipeflag, and nargs as 0
    ped->pipeflag = 0;
    ped->nargs = 0;
    //allocate space for the array of strings, and for the string cmd.
    ped->args =  malloc(sizeof(char*) * MAX_SIZE);
    ped->cmd = malloc(sizeof(char) * MAX_SIZE);
    //scan the input, and put the first argument into the cmd string
    sscanf(cmd, "%s %[^\n]", ped->cmd, cmd);
    //allocate space for the next string, and then copy cmd to it.
    ped->args[ped->nargs] =  malloc(sizeof(char) * MAX_SIZE);
    strcpy(ped->args[ped->nargs], ped->cmd);
    ped->pipeflag = conpipe(ped);

    /* PROBLEM LINE BELOW*/
    ped->nargs++;     // line 86, where valgrind claims the second leak is called?
    ped->args[ped->nargs] =  malloc(sizeof(char) * MAX_SIZE);
    //loop that allocates space for a command, and then assigns
    //the next arg to it.
    while(sscanf(cmd, " %s %[^\n]", ped->args[ped->nargs], cmd) == 2)
    {
        ped->pipeflag = conpipe(ped);
        ped->nargs++;
        ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE);
    }

    strncpy(ped->args[ped->nargs], cmd, strlen(cmd)-1);
    ped->nargs++;
    //ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE);
    ped->args[ped->nargs] = NULL;

    return ped;

}

int main()
{
    char cwd[MAX_CLEN];
    getcwd(cwd, sizeof(cwd));
    char input[MAX_CLEN]; 
    char *exit  = "exit\n";
    char *cd = "cd";

    //Command to take input
    printf("tosh$ ");
    fgets(input, sizeof input, stdin);    

    while(strcmp(input, exit))
    {
       //Command to parse input
       struct cmdin *cmd;
       cmd = parse(input);
       //if there is not a pipeflag
       if(!cmd->pipeflag)
       {
            //Change directories
            if(!strcmp(cd, cmd->args[0]))
            {
                chdir(cmd->args[1]); 
                getcwd(cwd, sizeof(cwd));
            }
            else if(strcmp(input, exit))
            {
                //command to run input
                int child_pid;
                child_pid = fork();
                if(child_pid == 0)
                {
                    if(strcmp(cmd->args[1],cmd->args[0]))
                    {
                        execvp(cmd->cmd, cmd->args);
                    }
                    else
                    {
                        free(cmd->args[1]);
                        cmd->args[1] = NULL;
                        cmd->nargs--;
                        execvp(cmd->cmd, cmd->args);

                    }
                }
                else
                {
                    wait(&child_pid);
                }
            }
            freeze(*cmd);
            free(cmd);
        }       
        //Command to take input
        printf("tosh$ ");
        fgets(input, sizeof input, stdin);
    }
    return 0;
}

Note: the input for this valgrind, looked like this: 注意:这个valgrind的输入,如下所示:

tosh$ ls -al
tosh$ exit

The valgrind Heap and Leak Summaries, are as follows: valgrind Heap和Leak Summaries如下:

HEAP SUMMARY:
==4901==     in use at exit: 4,096 bytes in 2 blocks
==4901==   total heap usage: 6 allocs, 4 frees, 24,600 bytes allocated
==4901== 
==4901== 2,048 bytes in 1 blocks are definitely lost in loss record 1 of 2 
==4901==    at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4901==    by 0x400A48: parse (tosh.c:46)
==4901==    by 0x400C97: main (tosh.c:86)
==4901== 
==4901== 2,048 bytes in 1 blocks are definitely lost in loss record 2 of 2
==4901==    at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4901==    by 0x400BDE: parse (tosh.c:62)
==4901==    by 0x400C97: main (tosh.c:86)
==4901== 
==4901== LEAK SUMMARY:
==4901==    definitely lost: 4,096 bytes in 2 blocks
==4901==    indirectly lost: 0 bytes in 0 blocks
==4901==      possibly lost: 0 bytes in 0 blocks
==4901==    still reachable: 0 bytes in 0 blocks
==4901==         suppressed: 0 bytes in 0 blocks

UPDATE: As per request. 更新:根据要求。 My Makefile: 我的Makefile:

CC=gcc
CFLAGS=-g -Wall
TARGET=tosh

$(TARGET): $(TARGET).c
    $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c

Valgrind Version: valgrind-3.7.0 Valgrind版本:valgrind-3.7.0

gcc Version: gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 gcc版本:gcc(Ubuntu / Linaro 4.7.2-2ubuntu1)4.7.2

echo $LD_PRELOAD: echo $ LD_PRELOAD:

(This printed nothing) (这没什么打印)

Have not managed to reproduce. 没有设法重现。 But a couple of notes. 但是有几个笔记。

  1. Use what you have available of error and warnings. 使用您提供的错误和警告。

     gcc -Wall -Wextra -pedantic … 
  2. Check return values and success of operations. 检查返回值和操作是否成功。 This is imperative for reducing bugs, especially those that only a user case a mile down the road reveals. 这对于减少错误是必不可少的,特别是那些只有一英里的用户案例显示的错误。


if (!(foo = malloc(size))) {
    perror("mem");
}

...


/* This line is no good: */
sscanf(cmd, "%s %[^\n]", ped->cmd, cmd);
/*      |                           |
 *      +----------+----------------+
 *                 |
 *                 +--- Not good. UB. (Input / Output same.)
 */

You could add a routine to get count and sizes ... 可以添加一个例程来获取数量和大小......

i = sscanf(cmd, "%s%n %[^\n]%n", ped->cmd, &n1, cmd, &n2);

if (i < 2) {
    /* Debug print. */
    fprintf(stderr, 
            "%s:%-3d; "
            "sscanf => %d items and %d bytes str[%d]<%s>\n", 
            __FILE__, __LINENO_,
            i, n2, n1, ped->cmd
    );
}

etc. 等等

Okay, I just figured out what the problem is. 好的,我只知道问题所在。 Most of the commentors were right. 大部分评论员都是对的。 It was that I was running valgrind on different source code. 我在不同的源代码上运行valgrind。 I have been keeping a copy of tosh in my ~/usr/bin (which is in my $PATH). 我一直在〜/ usr / bin中保留tosh的副本(在我的$ PATH中)。 I forgot to update that piece of code with the my most recent changes (including the ones that fixed my memory leak problems). 我忘了用我最近的更改(包括解决我的内存泄漏问题的那些更新)更新那段代码。

When I ran valgrind I used the following command from the directory containing tosh.c tosh: 当我运行valgrind时,我使用了包含tosh.cosh的目录中的以下命令:

$ valgrind tosh

What I should have run was: 我应该跑的是:

$ valgrind ./tosh

When I made the update to my command, the code ran fine with no memory leaks. 当我对命令进行更新时,代码运行良好,没有内存泄漏。 Thank you for all of your help! 谢谢你的帮助! Sorry it took me so long to figure this out. 对不起,我花了很长时间才想到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM