"无效的写入大小1和#34;和指针有正确的内存地址但仍然是罚球错误

时间:2016-03-08 22:39:38

标签: c memory-management valgrind free

我有下面的代码,它给了我2个错误 - Invalid write of size 1Address 0x41f52a8 is 0 bytes after a block of size 128 alloc'd。下面是完整的valgrind堆栈。

我可以做一个猜测工作,并确定memcpy(content2 + totalLength + 1, fileContentTemp, readBytes);代码行有问题。所以,我把它更正为memcpy(content2 + totalLength, fileContentTemp, readBytes);然后我的valgrind变得非常开心并且全部通过了。

但我无法理解原因。对我来说,从第2次起,我需要做+ 1因为我不希望memcpycontent2 + totalLength地址开始写,因为它是写入最后一个字节的地址所以我以为从下一个地址开始递增。

另外,另一个有趣的部分是,如果我不纠正它,那么我得到跟随运行时错误*** Error in ./server_issue': double free or corruption (!prev): 0x08c24170 ***,我想因为这行代码free(content2);而来。 free基本上释放指针,现在如果指针具有正确的内存地址(我验证content2具有正确的内存地址),那么为什么会发生异常。

代码:

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

typedef char BYTE;
bool load(FILE*, BYTE**, size_t*);

int main(void) {
    FILE *file = fopen("/home/jharvard/psets/pset6/pset6_working/public/hello.html", "r");
    BYTE *content;
    size_t length;
    load(file, &content, &length);
}

bool load(FILE *file, BYTE **content, size_t *length) {
    //printf("file %p\n", file);

    int totalLength = 0;
    int readBytes = 0;
    BYTE *content2 = NULL;

    BYTE *fileContentTemp[64]; // working with 222222
    while ((readBytes = fread(fileContentTemp, 1, 64, file)) > 0) {
        printf("Reallocating %d bytes, ", readBytes);
        content2 = realloc(content2, sizeof(BYTE) * (totalLength + readBytes));

        printf("%p\n", content2);
        if (totalLength != 0) {
            memcpy(content2 + totalLength + 1, fileContentTemp, readBytes);        
        } else {
            memcpy(content2 + totalLength, fileContentTemp, readBytes);        
        }
        totalLength = totalLength + readBytes;
    }

    *length = totalLength;
    *content = content2;

    free(content2);

    //printf("CC image: %s\n", *content);
    //printf("length is %d\n", *length);
    //printf("fileContent %p\n", *content);
    //printf("file %p\n", file);

    fclose(file);

    //printf("length is %d\n", *length);

    return true;
}

Valgrind筹码:

appliance (~/psets/pset6/pset6_working): valgrind ./server_issue
==3206== Memcheck, a memory error detector
==3206== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3206== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==3206== Command: ./server_issue
==3206== 
Reallocating 64 bytes, 0x41f51b8
Reallocating 64 bytes, 0x41f5228
==3206== Invalid write of size 1
==3206==    at 0x402F04B: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3206==    by 0x80486AC: load (in /home/jharvard/psets/pset6/pset6_working/server_issue)
==3206==    by 0x8048599: main (in /home/jharvard/psets/pset6/pset6_working/server_issue)
==3206==  Address 0x41f52a8 is 0 bytes after a block of size 128 alloc'd
==3206==    at 0x402C324: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3206==    by 0x804865C: load (in /home/jharvard/psets/pset6/pset6_working/server_issue)
==3206==    by 0x8048599: main (in /home/jharvard/psets/pset6/pset6_working/server_issue)
==3206== 
Reallocating 64 bytes, 0x41f52d8
Reallocating 64 bytes, 0x41f53c8
Reallocating 60 bytes, 0x41f54f8
==3206== 
==3206== HEAP SUMMARY:
==3206==     in use at exit: 0 bytes in 0 blocks
==3206==   total heap usage: 6 allocs, 6 frees, 1,308 bytes allocated
==3206== 
==3206== All heap blocks were freed -- no leaks are possible
==3206== 
==3206== For counts of detected and suppressed errors, rerun with: -v
==3206== ERROR SUMMARY: 4 errors from 1 contexts (suppressed: 0 from 0)

1 个答案:

答案 0 :(得分:1)

这归结为这样一个事实,即从0开始的前N个整数的列表以N-1结束。

让我们尝试一个具体的例子。假设您从索引0写入4个字节。您可以编写索引0,1,2和3.这总共是4个字节。所以右边的下一个是索引4,而不是5.

假设您从索引M写入N个字节。您可以编写M,M + 1,...,M + N-1。你写的下一个是M + N.

所以用

替换整个if语句
memcpy(content2 + totalLength, fileContentTemp, readBytes); 

if应该感觉不对。这样的操作不需要特殊的套管,所以你有一个if的事实应该会引起警钟。