好的,首先,公平警告,这是一个班级的项目。除了修复内存泄漏之外,我不是在寻找任何帮助。我想我已经在这个C代码的空间上遵循了一些可怕的编码实践。无论如何,当我运行Valgrind来搜索内存泄漏发生的位置时,我一点都不清楚我错过了什么内存泄漏。我知道至少有两个字符串,我没有释放,但我malloc()编辑,纯粹基于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
更新:根据要求。 我的Makefile:
CC=gcc
CFLAGS=-g -Wall
TARGET=tosh
$(TARGET): $(TARGET).c
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c
Valgrind版本: 的valgrind-3.7.0
gcc版本: gcc(Ubuntu / Linaro 4.7.2-2ubuntu1)4.7.2
echo $ LD_PRELOAD:
(这没什么打印)
答案 0 :(得分:4)
没有设法重现。但是有几个笔记。
使用您提供的错误和警告。
gcc -Wall -Wextra -pedantic …
检查返回值和操作是否成功。这对于减少错误是必不可少的,特别是那些只有一英里的用户案例显示的错误。
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
);
}
等
答案 1 :(得分:3)
好的,我只知道问题所在。大部分评论员都是对的。我在不同的源代码上运行valgrind。我一直在〜/ usr / bin中保留tosh的副本(在我的$ PATH中)。我忘了用我最近的更改(包括解决我的内存泄漏问题的那些更新)更新那段代码。
当我运行valgrind时,我使用了包含tosh.cosh:
的目录中的以下命令 $ valgrind tosh
我应该跑的是:
$ valgrind ./tosh
当我对命令进行更新时,代码运行良好,没有内存泄漏。谢谢你的帮助!对不起,我花了很长时间才弄清楚这一点。