English 中文(简体)
类似scanf 的函数中的内存泄漏问题
原标题:Memory Leak Issue in function similar to scanf

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

但问题是代码会泄漏一些内存,特别是当 realloc 被引用时。

我也想知道为什么 使 成为危险功能

test.c: 警告: 获取函数危险, 不应使用 。

我的代码:

#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()) !=  
 ){

    //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++] =   ;      //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
");

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

free(s);

return 0;
}

Valgrind :

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()) !=  
 ){

    //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) =   ;       //Null terminate the Buffer
return 0;   
} 

Valgrind :

==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)

这仍然引起一些问题。

最佳回答

以下是"""http://linux.die.net/man/3/gets" rel="nofollow" >manual 必须谈论的gets 问题:

永远不要使用“ 获取 () ” () 。 因为如果事先不知道数据会读取多少字符( ), 就无法分辨数据, 而由于“ 获取 () ” 将继续在缓冲结尾处存储字符, 使用该字符非常危险。 它被用来破坏计算机安全 。 代之以使用 fgets () 。

出现泄漏问题的原因是指针 被值传递,因此任何更改,包括重新分配后的分配,都针对其 copy ,而不是原指针。因此,释放 只释放原先分配的内存,泄漏 realloc -ed one。要解决这个问题,更改 read_input ,将指针移到指示器上,例如:

int read_input(char **ps,int len)

pass to read_input ,并使用 (*ps) 代替函数正文中的

问题回答

您没有将指针返回到指定的缓冲区 。 因此, < code> free 没有按您预期的那样行事 。 < code> realloc 无法保证在同一地点提供额外空间。 因此, 缓冲区可以移动。 解决方案是将指针传给指针到指针, 或者返回指针, 而不是 < code>int , 并使用 NULL 表示错误 。

PS - 还有其他问题,这是非常不安全的代码。

在循环中,您使用的是:

l=strlen(s);

s 并没有在循环中的任意位置以空号终止 。 因此当您在循环中调用 strlen () 时, 它不会给您带来预期的结果, 这可能是内存泄漏的原因 。 所以, 请确保您在循环中用空号终止字符串 。

ges 是危险的, 因为它允许您阅读超过您指定空间的读数 。

获取( ) 是危险的, 因为它没有信息显示您的缓冲实际上有多大, 因此无法防止大输入线上的缓冲溢出。 对于坏人来说, 缓冲溢出是一个非常常见的攻击矢量。 使用以 Stdin 的 fget () 作为第一个参数, 这样您就可以指定缓冲的大小 。





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签