struct导致sysMalloc断言失败并加倍free()错误

时间:2014-05-31 20:34:34

标签: c memory-management valgrind

我正在编写一个名为Process的非常简单的结构,代码似乎在快速浏览时正确实现,但是在测试我的代码时,它似乎一直在崩溃程序,无论是sysMalloc断言失败还是双重free()错误一个人试图释放它。

一些相关代码:

声明

typedef struct Process{
    int pid;
    int background;
    int group;
    int status;
    char* name = 0;
} Process;

构造

Process* Process_init(char* name, int pid, int group, int background){
    Process* output    = (Process*)calloc(1, sizeof(Process*));
    output->name       = name;
    output->pid        = pid;
    output->group      = group;
    output->background = background;
    output->status     = 0;

    return output;
}

致电代码

char* command = "python";
char* command1= "cat < testing";

Process* proc = Process_init("command", 1, 1, 1);
Process* proc2 = Process_init("command1", 1, 1, 1);

有一些奇怪的行为,它似乎第一次工作,但在第二次调用时导致sysMalloc错误(这就是我称之为两次的原因。)

我尝试使用Valgrind,它给了我以下内容:

invalid write of size 4
==3485==    at 0x8049A03: Process_init (process.c:6)
==3485==    by 0x80488C2: main (test.c:58)
==3485==  Address 0x419e730 is 12 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488C2: main (test.c:58)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A14: Process_init (process.c:8)
==3485==    by 0x80488C2: main (test.c:58)
==3485==  Address 0x419e728 is 4 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488C2: main (test.c:58)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A1D: Process_init (process.c:9)
==3485==    by 0x80488C2: main (test.c:58)
==3485==  Address 0x419e724 is 0 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488C2: main (test.c:58)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A23: Process_init (process.c:10)
==3485==    by 0x80488C2: main (test.c:58)
==3485==  Address 0x419e72c is 8 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488C2: main (test.c:58)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A03: Process_init (process.c:6)
==3485==    by 0x80488EA: main (test.c:59)
==3485==  Address 0x419e768 is 12 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488EA: main (test.c:59)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A14: Process_init (process.c:8)
==3485==    by 0x80488EA: main (test.c:59)
==3485==  Address 0x419e760 is 4 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488EA: main (test.c:59)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A1D: Process_init (process.c:9)
==3485==    by 0x80488EA: main (test.c:59)
==3485==  Address 0x419e75c is 0 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488EA: main (test.c:59)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x8049A23: Process_init (process.c:10)
==3485==    by 0x80488EA: main (test.c:59)
==3485==  Address 0x419e764 is 8 bytes after a block of size 4 alloc'd
==3485==    at 0x402425F: calloc (vg_replace_malloc.c:467)
==3485==    by 0x80499F9: Process_init (process.c:5)
==3485==    by 0x80488EA: main (test.c:59)
--Snip--

所以,看起来问题出现在构造函数中,但我不确定为什么会这样,因为它看起来像是一个非常直接的变量。

1 个答案:

答案 0 :(得分:3)

Process* output    = (Process*)calloc(1, sizeof(Process*));

不正确。您只为指针(4或8字节)分配足够的内存。

正确的代码:

Process* output    = calloc(1, sizeof(*output));

改进:

  1. 现在是正确的!我们为output个点分配了足够的字节,这是一个Process,而不是只有指针Process的足够字节。
  2. 通过说sizeof(*output),我们删除了对类型名称(DRY)的附加引用,这可以确保您的代码正确无误,即使有人更改了output指向的类型,并忘记改变其余部分。
  3. calloc的结果是removed the castcalloc返回void*,可以在没有强制转换的情况下将其分配给任何指针类型变量。
  4. 此外,您应该检查任何函数的返回值,特别是返回内存的函数:

    Process* Process_init(char* name, int pid, int group, int background){
        Process* output    = calloc(1, sizeof(*output));
        if (output == NULL)
            return NULL;
    
        output->name       = name;
        output->pid        = pid;
        output->group      = group;
        output->background = background;
        output->status     = 0;
    
        return output;
    }
    

    此函数的任何使用者也应检查其返回值。