gpt4 book ai didi

c - 作业 : I have a memory leak somewhere, 但我找不到它。关于如何更有效地使用 valgrind 的任何提示?

转载 作者:太空狗 更新时间:2023-10-29 17:22:12 26 4
gpt4 key购买 nike

好的,首先,公平警告,这是一个类(class)项目。除了修复内存泄漏外,我不寻求任何帮助。我想我在这段 C 代码空间中遵循了一些可怕的编码实践。无论如何,当我运行 Valgrind 来搜索发生内存泄漏的位置时,我完全不清楚我遗漏了什么内存泄漏。我知道至少有两个字符串我没有释放,但是我 malloc()ed,纯粹基于 valgrind 输出的大小。因为我从项目中删除了一些无关代码,所以 valgrind 行号很可能会被关闭,因此我用注释标记了它们以方便您使用。

一些背景知识,我正在编写 shell 的基本功能。它目前执行以下操作:

1.获取用户输入

2.将输入解析为 cmdin 结构

3.执行命令,前提是命令中没有管道。

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;
}

注意:此 valgrind 的输入如下所示:

tosh$ ls -al
tosh$ exit

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

更新:根据要求。我的生成文件:

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

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

Valgrind 版本: valgrind-3.7.0

海湾合作委员会版本: gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

回声 $LD_PRELOAD:

(这什么也没打印)

最佳答案

没有设法重现。但有几点要注意。

  1. 使用可用的错误和警告。

    gcc -Wall -Wextra -pedantic …
  2. 检查返回值和操作是否成功。这对于减少错误至关重要,尤其是那些只有一英里外的用户案例才能揭示的错误。


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

...


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

可以添加一个例程来获取计数和大小......

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
);
}

等等

关于c - 作业 : I have a memory leak somewhere, 但我找不到它。关于如何更有效地使用 valgrind 的任何提示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19698486/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com