无法弄清楚我哪里有内存泄漏
Can't figure out where I have memory leak
我是 C 的新手,仍然不知道如何使用 valgrind。我正在做一个项目,我需要创建一个函数,该函数 returns 每次仅使用一个静态变量调用时来自文件描述符的一行文本。
Repeated calls (e.g., using a loop) to your get_next_line() function should let
you read the text file pointed to by the file descriptor, one line at a time.
我想到了这个,但我找不到内存泄漏的地方:
char *output(char **backup, char *rbackup, int ret, int fd)
{
int value;
char *temp;
if (ret < 0)
return (NULL);
else if (ret == 0 && backup[fd] == NULL)
return (NULL);
value = (int)(ft_strchr(backup[fd], '\n') - backup[fd] + 1);
rbackup = ft_substr(backup[fd], 0, value);
temp = ft_substr(backup[fd], value, BUFFER_SIZE * BUFFER_SIZE);
free(backup[fd]);
if (temp[0] == '[=10=]')
{
free(temp);
temp = NULL;
}
backup[fd] = temp;
return (rbackup);
}
char *get_next_line(int fd)
{
int ret;
char buf[BUFFER_SIZE + 1];
static char *backup[NUM_OF_FD];
char *rbackup;
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
while (ft_strchr(backup[fd], '\n') == NULL)
{
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '[=10=]';
if (ret <= 0)
break ;
if (backup[fd] == NULL)
backup[fd] = ft_strdup(buf);
else
{
rbackup = ft_strjoin(backup[fd], buf);
free(backup[fd]);
backup[fd] = rbackup;
}
}
return (output(backup, rbackup, ret, fd));
}
ft_函数 等同于 LibC 的对应物,但如果有错误,我会 post 它们这里:
void *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
i = -1;
if ((dst != src) && n)
while (++i < n)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return (dst);
}
size_t ft_strlen(const char *s)
{
size_t i;
i = 0;
while (s[i])
{
i++;
}
return (i);
}
char *ft_strchr(const char *s, int c)
{
char chr;
chr = (char)c;
if (s == NULL)
return (NULL);
while (*s && *s != chr)
s++;
if (*s == chr)
return ((char *)s);
else
return (NULL);
}
char *ft_substr(char const *s, unsigned int start, size_t len)
{
char *str;
if (!s)
return (NULL);
if (len > ft_strlen(s))
len = ft_strlen(s);
if (start > ft_strlen(s))
len = 0;
str = malloc(sizeof(char) * (len + 1));
if (!str)
return (NULL);
str = ft_memcpy(str, &s[start], len);
str[len] = '[=11=]';
return (str);
}
char *ft_strdup(const char *s1)
{
size_t len;
void *new;
len = ft_strlen(s1) + 1;
new = malloc(len);
if (new == NULL)
return (NULL);
return ((char *) ft_memcpy(new, s1, len));
}
char *ft_strjoin(char const *s1, char const *s2)
{
int i;
char *str;
size_t size;
if (!s1 || !s2)
return (NULL);
i = 0;
size = (ft_strlen(s1) + ft_strlen(s2) + 1);
str = malloc(sizeof(char) * size);
if (!str)
return (NULL);
while (*s1)
str[i++] = *s1++;
while (*s2)
str[i++] = *s2++;
str[i] = '[=11=]';
return (str);
}
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = -1;
while (++i < len)
((unsigned char *)b)[i] = (unsigned char)c;
return (b);
}
我的代码有没有菜鸟错误?
好吧,我 运行 你的代码是这样的
int main(int a, char**b)
{
int f = open("poop.c", O_RDONLY);
for(int i = 0; i < 10; i++)
{
char *x = get_next_line(f);
printf("x");
free(x);
}
}
阅读前 10 行。 valgrind 没有检测到泄漏(一旦我在循环中添加了 free)
虽然它确实抱怨其他事情
==3695== Invalid read of size 1
==3695== at 0x109270: ft_memcpy (poop.c:26)
==3695== by 0x1093BB: ft_substr (poop.c:70)
==3695== by 0x109619: output (poop.c:120)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695== Address 0x4a4a0a5 is 0 bytes after a block of size 101 alloc'd
==3695== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3695== by 0x109408: ft_strdup (poop.c:81)
==3695== by 0x109724: get_next_line (poop.c:147)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109546: output (poop.c:114)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109556: output (poop.c:116)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
好像是读取了一个空行导致的未初始化读取
这里是无效读取
((unsigned char*)dst)[i] = ((unsigned char*)src)[i];
如果您有 C 文件的 Makefile,那么您可以在 Makefile 的标志后添加 -g
。如果直接使用clang
或gcc
编译C文件,可以在clang
或gcc
后加上-g
。然后您可以获得有关您的问题的更多信息。 -g
用于调试。如果您不添加它,Valgrind 只会告诉您需要调试的部分(如特定功能)。但是如果你加上-g
,你就可以知道你需要调试哪一行了。
你肯定有问题:
static char *backup[NUM_OF_FD];
您检查 fd 是否大于 NUM_OF_FD,但 NUM_OF_FD 仍会尝试在备份数组之外进行索引。
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
应该是
if (fd < 0 || fd >= NUM_OF_FD)
return (NULL);
还要注意 read() 可以 return -1,所以这段代码可能有问题:
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '[=13=]';
if (ret <= 0)
break ;
使用前检查 return 值。
我是 C 的新手,仍然不知道如何使用 valgrind。我正在做一个项目,我需要创建一个函数,该函数 returns 每次仅使用一个静态变量调用时来自文件描述符的一行文本。
Repeated calls (e.g., using a loop) to your get_next_line() function should let you read the text file pointed to by the file descriptor, one line at a time.
我想到了这个,但我找不到内存泄漏的地方:
char *output(char **backup, char *rbackup, int ret, int fd)
{
int value;
char *temp;
if (ret < 0)
return (NULL);
else if (ret == 0 && backup[fd] == NULL)
return (NULL);
value = (int)(ft_strchr(backup[fd], '\n') - backup[fd] + 1);
rbackup = ft_substr(backup[fd], 0, value);
temp = ft_substr(backup[fd], value, BUFFER_SIZE * BUFFER_SIZE);
free(backup[fd]);
if (temp[0] == '[=10=]')
{
free(temp);
temp = NULL;
}
backup[fd] = temp;
return (rbackup);
}
char *get_next_line(int fd)
{
int ret;
char buf[BUFFER_SIZE + 1];
static char *backup[NUM_OF_FD];
char *rbackup;
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
while (ft_strchr(backup[fd], '\n') == NULL)
{
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '[=10=]';
if (ret <= 0)
break ;
if (backup[fd] == NULL)
backup[fd] = ft_strdup(buf);
else
{
rbackup = ft_strjoin(backup[fd], buf);
free(backup[fd]);
backup[fd] = rbackup;
}
}
return (output(backup, rbackup, ret, fd));
}
ft_函数 等同于 LibC 的对应物,但如果有错误,我会 post 它们这里:
void *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
i = -1;
if ((dst != src) && n)
while (++i < n)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return (dst);
}
size_t ft_strlen(const char *s)
{
size_t i;
i = 0;
while (s[i])
{
i++;
}
return (i);
}
char *ft_strchr(const char *s, int c)
{
char chr;
chr = (char)c;
if (s == NULL)
return (NULL);
while (*s && *s != chr)
s++;
if (*s == chr)
return ((char *)s);
else
return (NULL);
}
char *ft_substr(char const *s, unsigned int start, size_t len)
{
char *str;
if (!s)
return (NULL);
if (len > ft_strlen(s))
len = ft_strlen(s);
if (start > ft_strlen(s))
len = 0;
str = malloc(sizeof(char) * (len + 1));
if (!str)
return (NULL);
str = ft_memcpy(str, &s[start], len);
str[len] = '[=11=]';
return (str);
}
char *ft_strdup(const char *s1)
{
size_t len;
void *new;
len = ft_strlen(s1) + 1;
new = malloc(len);
if (new == NULL)
return (NULL);
return ((char *) ft_memcpy(new, s1, len));
}
char *ft_strjoin(char const *s1, char const *s2)
{
int i;
char *str;
size_t size;
if (!s1 || !s2)
return (NULL);
i = 0;
size = (ft_strlen(s1) + ft_strlen(s2) + 1);
str = malloc(sizeof(char) * size);
if (!str)
return (NULL);
while (*s1)
str[i++] = *s1++;
while (*s2)
str[i++] = *s2++;
str[i] = '[=11=]';
return (str);
}
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = -1;
while (++i < len)
((unsigned char *)b)[i] = (unsigned char)c;
return (b);
}
我的代码有没有菜鸟错误?
好吧,我 运行 你的代码是这样的
int main(int a, char**b)
{
int f = open("poop.c", O_RDONLY);
for(int i = 0; i < 10; i++)
{
char *x = get_next_line(f);
printf("x");
free(x);
}
}
阅读前 10 行。 valgrind 没有检测到泄漏(一旦我在循环中添加了 free)
虽然它确实抱怨其他事情
==3695== Invalid read of size 1
==3695== at 0x109270: ft_memcpy (poop.c:26)
==3695== by 0x1093BB: ft_substr (poop.c:70)
==3695== by 0x109619: output (poop.c:120)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695== Address 0x4a4a0a5 is 0 bytes after a block of size 101 alloc'd
==3695== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3695== by 0x109408: ft_strdup (poop.c:81)
==3695== by 0x109724: get_next_line (poop.c:147)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109546: output (poop.c:114)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109556: output (poop.c:116)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
好像是读取了一个空行导致的未初始化读取
这里是无效读取
((unsigned char*)dst)[i] = ((unsigned char*)src)[i];
如果您有 C 文件的 Makefile,那么您可以在 Makefile 的标志后添加 -g
。如果直接使用clang
或gcc
编译C文件,可以在clang
或gcc
后加上-g
。然后您可以获得有关您的问题的更多信息。 -g
用于调试。如果您不添加它,Valgrind 只会告诉您需要调试的部分(如特定功能)。但是如果你加上-g
,你就可以知道你需要调试哪一行了。
你肯定有问题:
static char *backup[NUM_OF_FD];
您检查 fd 是否大于 NUM_OF_FD,但 NUM_OF_FD 仍会尝试在备份数组之外进行索引。
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
应该是
if (fd < 0 || fd >= NUM_OF_FD)
return (NULL);
还要注意 read() 可以 return -1,所以这段代码可能有问题:
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '[=13=]';
if (ret <= 0)
break ;
使用前检查 return 值。