gpt4 book ai didi

c - 类似于 scanf 的函数中的内存泄漏问题

转载 作者:太空狗 更新时间:2023-10-29 15:51:10 24 4
gpt4 key购买 nike

在下面的代码中,我试图重新创建 scanf 以从 stdin 读取所有内容,并在换行符处换行,返回字符串中读取的所有字符。

但问题是代码会泄漏一些内存,尤其是在调用 realloc 时。

我还想知道为什么 gets 是一个危险的函数

test.c:警告:'gets' 函数很危险,不应使用。

我的代码:-

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_BUF_LEN 128
#define __cdecl

//0 - Success
//-1 - Error in input
//1 - Error
__cdecl int read_input(char *s,int len){

char c,*t;
int l,i=0;

if(s==NULL || len < 1)
return -1;

while((c=getchar()) != '\n'){

//check if sufficient memory
//required + used > assigned
l=strlen(s);
if(l + 2 > len){

len += l + MAX_BUF_LEN; //realloc max to avoid subsequent realloc as its costly!

t = realloc(s,len);
if(t!=NULL)
s = t;
else
return 1; //No space to store content
}

s[i++] = c;

}

s[i++] = '\0'; //Null terminate the Buffer
return 0;
}

int main(int argc,char* argv[]){

int len = 5+1;
char *s = calloc(len,sizeof(char));

printf("Enter your name\n");

if(!read_input(s,len))
printf("Hi %s\n",s);

free(s);

return 0;
}

瓦尔格林德:

nimish:~/Desktop$ gcc -g -Wall test.c -o test
nimish~/Desktop$ clear && valgrind ./test --leak-check=full

==3670== Memcheck, a memory error detector
==3670== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==3670== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==3670== Command: ./test --leak-check=full
==3670==
Enter your name
Nimish Nicolus
==3670== Conditional jump or move depends on uninitialised value(s)
==3670== at 0x4027029: strlen (mc_replace_strmem.c:282)
==3670== by 0x804850E: read_input (test.c:23)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670== Invalid read of size 1
==3670== at 0x40831BF: vfprintf (vfprintf.c:1623)
==3670== by 0x40891BF: printf (printf.c:35)
==3670== by 0x80485E6: main (test.c:52)
==3670== Address 0x41a5028 is 0 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670== Invalid read of size 1
==3670== at 0x40A93A8: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
==3670== by 0x408346F: vfprintf (vfprintf.c:1623)
==3670== by 0x40891BF: printf (printf.c:35)
==3670== by 0x80485E6: main (test.c:52)
==3670== Address 0x41a502c is 4 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670== Invalid read of size 1
==3670== at 0x40A93BF: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
==3670== by 0x408346F: vfprintf (vfprintf.c:1623)
==3670== by 0x40891BF: printf (printf.c:35)
==3670== by 0x80485E6: main (test.c:52)
==3670== Address 0x41a502b is 3 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670== Invalid read of size 1
==3670== at 0x40A9330: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1349)
==3670== by 0x408346F: vfprintf (vfprintf.c:1623)
==3670== by 0x40891BF: printf (printf.c:35)
==3670== by 0x80485E6: main (test.c:52)
==3670== Address 0x41a5028 is 0 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670== Invalid read of size 1
==3670== at 0x40A933C: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1348)
==3670== by 0x408346F: vfprintf (vfprintf.c:1623)
==3670== by 0x40891BF: printf (printf.c:35)
==3670== by 0x80485E6: main (test.c:52)
==3670== Address 0x41a502a is 2 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
Hi Nimis
==3670== Invalid free() / delete / delete[]
==3670== at 0x4025BF0: free (vg_replace_malloc.c:366)
==3670== by 0x80485F2: main (test.c:54)
==3670== Address 0x41a5028 is 0 bytes inside a block of size 6 free'd
==3670== at 0x402695A: realloc (vg_replace_malloc.c:525)
==3670== by 0x8048537: read_input (test.c:28)
==3670== by 0x80485CD: main (test.c:51)
==3670==
==3670==
==3670== HEAP SUMMARY:
==3670== in use at exit: 139 bytes in 1 blocks
==3670== total heap usage: 2 allocs, 2 frees, 145 bytes allocated
==3670==
==3670== LEAK SUMMARY:
==3670== definitely lost: 139 bytes in 1 blocks
==3670== indirectly lost: 0 bytes in 0 blocks
==3670== possibly lost: 0 bytes in 0 blocks
==3670== still reachable: 0 bytes in 0 blocks
==3670== suppressed: 0 bytes in 0 blocks
==3670== Rerun with --leak-check=full to see details of leaked memory
==3670==
==3670== For counts of detected and suppressed errors, rerun with: -v
==3670== Use --track-origins=yes to see where uninitialised values come from
==3670== ERROR SUMMARY: 23 errors from 7 contexts (suppressed: 11 from 6)

编辑:- 请引用下面附带的新代码

新代码:-

__cdecl int read_input(char **s,int len){

char c,*t;
int l,i=0;

if((*s)==NULL || len < 1)
return -1;

while((c=getchar()) != '\n'){

//check if sufficient memory
//required + used > assigned
l=strlen((*s));
if(l + 2 > len){

len += l + MAX_BUF_LEN; //realloc max to avoid subsequent realloc as its costly!

t = realloc((*s),len);
if(t!=NULL)
(*s) = t;
else
return 1; //No space to store content
}

*((*s)+i++) = c;

}

*((*s)+i) = '\0'; //Null terminate the Buffer
return 0;
}

瓦尔格林德:

==4767== Memcheck, a memory error detector
==4767== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==4767== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==4767== Command: ./test --leak-check=full
==4767==
Enter your name
Nimish Nicolus
==4767== Conditional jump or move depends on uninitialised value(s)
==4767== at 0x4027029: strlen (mc_replace_strmem.c:282)
==4767== by 0x8048516: read_input (test.c:23)
==4767== by 0x80485DE: main (test.c:51)
==4767==
Hi Nimish Nicolus
==4767==
==4767== HEAP SUMMARY:
==4767== in use at exit: 0 bytes in 0 blocks
==4767== total heap usage: 2 allocs, 2 frees, 145 bytes allocated
==4767==
==4767== All heap blocks were freed -- no leaks are possible
==4767==
==4767== For counts of detected and suppressed errors, rerun with: -v
==4767== Use --track-origins=yes to see where uninitialised values come from
==4767== ERROR SUMMARY: 6 errors from 1 contexts (suppressed: 11 from 6)

它仍然存在一些问题。

最佳答案

这是 manual 的内容不得不说关于gets的问题:

Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.

泄漏问题的发生是因为指针 s 是按值传递的,所以任何更改,包括重新分配后的赋值,都是对其 副本 进行的,而不是对原始指针进行的.因此,释放 s 只会释放最初分配的内存,泄漏 realloc 的内存。要解决此问题,请更改 read_input 以获取指向指针的指针,如下所示:

int read_input(char **ps,int len)

&s传递给read_input,并在正文中使用(*ps)代替s函数。

关于c - 类似于 scanf 的函数中的内存泄漏问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10688381/

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