如果我使用大小错误的malloc会发生什么?

时间:2013-04-01 05:20:18

标签: c malloc

我正在尝试更多地了解内存分配,因此我在下面编写了一些测试代码,看看如果我尝试分配比我需要的内存更小的内存会发生什么。

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

typedef struct {
    char *message;
    int number;
} Object;

int main(int argc, char *argv[]) {
    Object *obj = malloc(sizeof(Object) - 8);   
    printf("The size of the struct is: %ld\n", sizeof(Object));
    printf("The size of what was allocated is: %ld\n", sizeof(*obj));

    obj->message = "Hello there! My name is Chris!";
    obj->number = 435543;

    puts(obj->message);
    printf("%d\n", obj->number);

    free(obj);

    return 0;
}

首先,sizeof(* obj)是查看在这种情况下实际分配了多少内存的正确方法吗?第二,为什么即使我没有分配足够的空间,我仍然能够为结构对象赋值?

我的操作系统是Ubuntu 12.10 64bit,编译器是gcc 4.7.2

这是valgrind输出:

==14257== Memcheck, a memory error detector
==14257== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==14257== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==14257== Command: ./ex
==14257== 
The size of the struct is: 16
The size of what was allocated is: 16
==14257== Invalid write of size 4
==14257==    at 0x400640: main (ex.c:15)
==14257==  Address 0x51f1048 is 0 bytes after a block of size 8 alloc'd
==14257==    at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14257==    by 0x400604: main (ex.c:10)
==14257== 
Hello there! My name is Chris!
==14257== Invalid read of size 4
==14257==    at 0x40065A: main (ex.c:18)
==14257==  Address 0x51f1048 is 0 bytes after a block of size 8 alloc'd
==14257==    at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14257==    by 0x400604: main (ex.c:10)
==14257== 
435543
==14257== 
==14257== HEAP SUMMARY:
==14257==     in use at exit: 0 bytes in 0 blocks
==14257==   total heap usage: 1 allocs, 1 frees, 8 bytes allocated
==14257== 
==14257== All heap blocks were freed -- no leaks are possible
==14257== 
==14257== For counts of detected and suppressed errors, rerun with: -v
==14257== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

4 个答案:

答案 0 :(得分:2)

你正在进行这种探索是件好事。大多数标准c库包括非标准扩展,允许您在分配后检查内存大小。从malloc返回后应该调用它,如果想要了解有关如何实现malloc的更多信息,请查看标准库实际分配的内存量。你可能会发现像malloc(1)这样简单的东西可以返回一个相当大的内存块。

正如其他一些读者指出的那样,如果要在32位系统上重新编译,可能会要求malloc在示例代码中分配零字节。它会愉快地遵守并返回NULL

答案 1 :(得分:2)

在这种特定情况下,您可能尝试分配0个字节,因为在大多数32位编译器中sizeof(Object)为8。 malloc(0)将返回NULL作为要分配的无效大小,并且尝试写入地址NULL肯定会使您的应用程序崩溃。

但是假设您成功分配了4个字节,并尝试在其中写入8个字节。在单线程应用程序中它应该没有问题,因为尽管你将写入未分配的内存空间,但它不会写入虚拟内存中丢失的一些疯狂地址。

然而,如果你这样做:

Object* a = (Object*)malloc(4);
Object* b = (Object*)malloc(4);

ab可能在系列中分配。这意味着,在大多数32位编译器中,写入a->number将使用相同的值覆盖b->message,反之亦然,因为两者都将尝试将信息存储到内存中的同一空间。

答案 2 :(得分:1)

它取决于编译器和操作系统。在许多人身上,它最终会崩溃。绝对不推荐。也可能导致缓冲区溢出。

答案 3 :(得分:0)

要回答关于sizeof:sizeof的子问题,会根据您使用的类型生成结果(在C中,可变长度数组有一个单独的情况)。如果你写

T* obj = malloc (any value);

然后sizeof(* obj)只查看* obj的类型,它是T,并产生类型为T的对象的大小。分配失败并且obj实际上是NULL是无关紧要,或者是否你分配的字节数少于T的大小,如果你根本没有调用malloc并且obj是一个未初始化的变量,那么它甚至不重要。