2011-03-06 112 views
7
# include <stdio.h> 
# include <stdbool.h> 
# include <string.h> 
# include <stdlib.h> 

int main() 
{ 
    char * buffer; 
    buffer = malloc (2); 

    if (buffer == NULL){ 
    printf("big errors"); 
    } 
    strcpy(buffer, "hello"); 
    printf("buffer is %s\n", buffer); 
    free(buffer); 
    return 0; 
} 

我给指针/字符缓冲区分配了2个字节的内存,但是如果给它分配“hello”,它仍会打印它,而不会给我任何错误。为什么编译器不给我一个错误,告诉我没有足够的内存分配?我阅读了几个问题,询问如何检查实际分配了多少内存,但我没有找到具体的答案。 free函数不应该确切地知道分配给buffer的内存有多少?Malloc - >分配了多少内存?

+0

你很幸运,你没有用你不拥有的4个额外字节覆盖任何重要的内存片段;你每次都不会那么幸运,而且会导致崩溃。 – holex 2015-03-04 12:38:17

回答

14

编译器不知道。这是属于运行时的C. malloc的欢乐和恐怖。所有的编译器都知道,你已经告诉它它返回一个void *,它不知道要多少,或者要拷贝多少。

像valgrind这样的工具可以检测出其中的一些错误。其他编程语言使得在脚下拍摄自己变得更加困难。不是C.

+2

但是在其他语言中,当你*自己在脚下开枪时,它会把你的整条腿都踢掉! – fouronnes 2011-03-06 21:20:23

1

malloc内部分配多少取决于实现和操作系统相关(例如8个字节或更多的倍数)。即使您的编译器和运行时没有检测到错误,您写入未分配的字节也可能导致覆盖其他变量的值。自由函数会记住与分配区域分开分配的字节数,例如在自由列表中。

1

为什么犯规编译器给我一个 错误,告诉我有不是足够 内存分配?

C不会阻止您使用您不应该使用的内存。您可以使用该内存,但它很糟糕,并导致未定义的行为。你正在写一本你不应该写的地方。该程序可能显示为正确运行,但可能会在以后崩溃。这是UB。你不知道会发生什么。

这就是strcpy()的情况。你写的地方你不拥有,但语言并不能保护你。所以你应该确保你总是知道你在写什么和在哪里,或者当你要超过有效的内存边界时,确保你停下来。

我看了几个问题是问 如何检查 多少内存的malloc分配实际,但我没有找到一个 具体的答案。不应该'免费' 函数必须知道有多少内存 正确地分配给'缓冲'?

malloc()可能会分配比请求的位填充更多的内存。

更多:http://en.wikipedia.org/wiki/Data_structure_alignment

free()免费-S您malloc()分配完全相同的量,但是它并不像你想象的那么聪明。例如:

int main() 
{ 
    char * ptr = malloc(10); 
    if(ptr) 
    { 
     ++ptr; // Now on ptr+1 
     free(ptr); // Undefined Behaviour 
    } 
} 

您应该始终指向第一个块的指针free()。做free(0)是安全的。

+0

错字末尾? – bmargulies 2011-03-06 21:04:12

+0

@bmaurgulies,对不起。固定。 – Muggen 2011-03-06 21:04:49

1

您已写过您分配的缓冲区的末尾。结果是未定义的行为。有些正确选项的运行时库至少有一些诊断类似问题的能力,但并非全部都是这样,甚至是那些只在运行时才这样做的功能,而且通常只有在使用正确的选项编译时才这样做。

4

没有生产malloc()执行应该会阻止您尝试写入您分配的内容。假设你分配了123个字节,你将使用全部或者少于你分配的内容。为了效率的缘故,不得不假定程序员要跟踪他们的指针。

使用内存,你没有明确,并成功地要求malloc()给你是未定义的行为。由于malloc()实现优化字节对齐,您可能要求n字节,但得到了n + x。或者你可以写信给黑洞。你永远不会知道,这就是为什么它是未定义的行为。

话虽这么说...

有,让你在statistics and debuggingmalloc()实现,但是这些需要代替标准malloc()设施的使用,就像你,如果你使用的是garbage collected variety

我还看到过严格为LD_PRELOAD设计的变体,这些变体暴露了一个函数,允许您使用至少一个void指针作为参数来定义回调函数。这个观点期望一个包含统计数据的结构。其他工具如electric fence将简单地停止您的程序的导致超出或访问无效块的确切指令。正如@R ..在评论中指出的那样,这对调试非常有用,但效率非常低。

在这种情况下,使用堆分析器(如Valgrind及其相关工具(massif))会非常容易或者(因为他们会说)的信息。在这个特殊的情况下,Valgrind会指出显而易见的 - 你写过分配的边界。但在大多数情况下,当这不是有意的,一个好的分析器/错误检测器是无价的。

使用分析器并不总是可能的,因为:

  • 时间问题探查器下运行时(但这些都是常见随时调用malloc()拦截)。
  • 探查不适用于你的平台/拱
  • 调试数据(从记录malloc())必须是

我们使用的是我在HELENOS链接库的变体方案的一个组成部分(我不确定他们是否还在使用它)很长一段时间,因为在VMM调试已知会导致疯狂。

不过,在考虑降低替代品时,请仔细考虑未来的后果,当涉及到malloc()设施时,您几乎总是希望使用系统所提供的功能。

+0

实际上,一个'malloc'实现可以保护你不会这样做,如果它将'N'字节安排到页面的最后'N'个字节,并且在它之后放置一个保护页... :-)这是真的效率不高,但它是一个很好的调试实现。 – 2011-03-07 05:46:52

+0

@R ..为了清晰起见,我更新了答案,我是在'为什么系统malloc()阻止我这样做的背景下讲话?' – 2011-03-07 23:46:35

0

Malloc - >分配了多少内存?

当您使用malloc分配内存。成功时分配内存,默认分配为128k。第一次调用malloc会给你128k。

你要求的是buffer = malloc (2);虽然你要求2个字节。它已经分配了128k。

strcpy(buffer, "hello");分配128k块它开始处理您的请求。 “你好” 字符串可以适应此。

这个pgm会让你清楚。

int main() 
{ 
int *p= (int *) malloc(2);---> request is only 2bytes 

p[0]=100; 
p[1]=200; 
p[2]=300; 
p[3]=400; 
p[4]=500; 

int i=0; 

为(;我< 5;我+ +,P ++)enter code here 的printf( “%d \ t” 的比较,* P);

} 

第一次调用malloc。它分配128k --->来处理你的请求(2字节)。字符串“你好”可以适应它。再次调用malloc时,它会从128k处理您的请求。

超过128k它使用mmap接口。你可以参考malloc的man page。

0

没有编译器/平台独立的方式来找出多少内存malloc实际分配。 malloc的将一般分配略多于你问它在这里看到:

http://41j.com/blog/2011/09/finding-out-how-much-memory-was-allocated/

在Linux上,你可以使用malloc_usable_size找出你可以使用多少内存。在MacOS和其他BSD平台上,您可以使用malloc_size。上面链接的文章有这两种技术的完整例子。