我读了一种特殊格式的二进制文件。我必须使用动态数组来读取具有未知大小的字符串。一切正常,但valgrind有错误。 \ 0的赋值不是问题,我没有它就试过了。我不知道还有什么可能是错的。
int ReadInt(ifstream& i)
{
int x=0;
i.read((char*)&x,4);
return x;
}
bool BINtoCSV ( const char * inFileName, const char * outFileName )
{
ifstream i(inFileName,ios::binary|ios::in);
if(i.fail()) return false;
ofstream o(outFileName,ios::binary|ios::out);
if(o.fail()) return false;
char eater[4];
for(unsigned f=0;f<4;f++)eater[f]='\0';
int rows=0,inLine=0;
char c='k';
i.read(eater,1);//H
i.read(eater,4);//num
i.read((char*)&rows,4);//rows
i.read((char*)&inLine,4);//inlines
for(int a=0;a<rows;a++){
i.read((char*)&c,1);
if(c!='R') {if(a==0){i.close(); o.close(); return true;}i.close(); o.close();
return false;}
i.read(eater,4);
for(int b=0;b<inLine;b++)
{
for(unsigned f=0;f<4;f++)eater[f]='\0';
i.read((char*)&c,1);
if(c=='I') { o<<ReadInt(i)<<(!((b+1)%inLine)?'\n':';');}
else if(c=='S')
{
int l=0; i.read((char*)&l,4);
char* block=new char[l];
for(int a=0;a<l;a++) block[a]='\0';
i.read(block,l);
o<<block<<(!((b+1)%inLine)?'\n':';');
delete [] block;
}
else
{
i.close();
o.close();
return false;
}
}
}
i.close();
o.close();
return true;
}
有来自valgrind的日志示例。
Invalid read of size 1
at 0x4C2BFB4: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x4EC62E0: std::basic_ostream<char, std::char_traits<char> >& std::operator<<
<std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char
const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
by 0x401841: BINtoCSV(char const*, char const*) (in /home/ondrnovy/Plocha/a.out)
by 0x401EA7: main (in /home/ondrnovy/Plocha/a.out)
Address 0x5a07683 is 0 bytes after a block of size 3 alloc'd
at 0x4C2AC27: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)
by 0x40179F: BINtoCSV(char const*, char const*) (in /home/ondrnovy/Plocha/a.out)
by 0x401EA7: main (in /home/ondrnovy/Plocha/a.out)
答案 0 :(得分:2)
在这部分
char* block=new char[l];
for(int a=0;a<l;a++) block[a]='\0';
i.read(block,l);
o<<block<<(!((b+1)%inLine)?'\n':';');
您尝试使用需要C样式字符串的运算符block
来编写<<
,但block
未正确终止。
运算符将使用strlen
来查找字符串的结尾,但没有一个,它在buffer
之外读取。
答案 1 :(得分:0)
我不熟悉GNU的amd64标准库实现,但我在基于ARM的平台上看到了Valgrind的相同类型的警告。他们在那里使用的strlen
实现已经过优化,每次迭代处理一个字(4个字节)(问题here's the code)。
C的等价物可能是这样的:
uint32_t dat, *p;
uint32_t temp;
int len = 0;
p = (uint32_t*)inputstring;
dat = *p++;
len -= (int)p;
// The only case where ((x-1) & 0x80) & ~x will be non-zero is
// if x == 0. So loop as long as the result is zero, i.e. no
// word has been loaded that contains a NUL-byte.
do {
temp = dat - 0x01010101;
temp &= 0x80808080;
temp &= ~dat;
if (!temp) dat = *p++;
} while (!temp);
len += (int)p;
if (dat & 0xFF) {
len++;
if (dat & 0xFF00) {
len++;
if (dat & 0xFF0000) {
len++;
}
}
}
return len;
我只能猜测在该平台上使用的new
运算符实现将char
数组填充为4个字节的倍数,以便使此优化安全。但Valgrind在检查越界问题时可能并不关心。