C &引用;大小为“1”的写入无效;指针有正确的内存地址,但仍然会抛出错误
下面的代码给了我2个错误-C &引用;大小为“1”的写入无效;指针有正确的内存地址,但仍然会抛出错误,c,memory-management,valgrind,free,C,Memory Management,Valgrind,Free,下面的代码给了我2个错误-大小为1的无效写入,地址0x41f52a8在分配大小为128的块后为0字节。下面是完整的valgrind堆栈 我可以做一个猜测工作并确定memcpy(content2+totalLength+1,fileContentTemp,readBytes)代码行有问题。因此,我将其更正为memcpy(content2+totalLength,fileContentTemp,readBytes)
大小为1的无效写入
,地址0x41f52a8在分配大小为128的块后为0字节
。下面是完整的valgrind堆栈
我可以做一个猜测工作并确定memcpy(content2+totalLength+1,fileContentTemp,readBytes)代码>代码行有问题。因此,我将其更正为memcpy(content2+totalLength,fileContentTemp,readBytes)然后我的valgrind变得非常高兴,一切都过去了
但我无法理解原因。对我来说,从第二次开始,我需要做+1
,因为我不希望memcpy
从content2+totalLength
地址开始写入,因为它是最后一个字节写入的地址,所以我想从下一个地址开始递增
另外,另一个有趣的部分是,如果我不纠正它,那么我会在./server_issue中得到以下运行时错误***错误:双重免费或损坏(!prev):0x08c24170***
,我猜是因为这行代码免费(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;
}
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)
这归结为一个事实,即前N个整数的列表,从0开始,以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
的事实应该会引起警钟 谢谢你的意见。我想了想,但后来-假设我的第一个内存位置是0x100,我写了4个字节,所以最后一个字节写在0x103。现在,当我说memcpy(content2+totalLength,fileContentTemp,readBytes)
那么这意味着我的内存地址将变成content2
即0x100+totalLength
即4,因此等于0x103。这就是我怀疑memcpy是否会从0x103开始写的地方,所以我做了+1
。呃,这不是如何将4添加到0x100。0x100+4是0x104。哦,我很惭愧,我真傻!我应用了逻辑,我有4个字节要写,我从0x100开始,所以我将以0x103结束(这是真的),但这是简单的数学,不是关于写字节。对于./server_issue中的***错误:双重释放或损坏(!prev):0x08c24170***
您认为这是因为memcpy
的内存损坏吗?是的,您损坏了堆,然后可能会发生任何事情