0

我读了一种特殊格式的二进制文件。我必须使用动态数组来读取大小未知的字符串。一切正常,但 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)
4

2 回答 2

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.

于 2013-03-17T12:08:44.190 回答
0

我不熟悉 GNU 的 amd64 标准库实现,但我在基于 ARM 的平台上看到了来自 Valgrind 的相同类型的警告。strlen他们在那里使用的实现经过优化,每次迭代处理一个字(4 个字节)(这里是有问题的代码)。

与此等效的 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 在检查越界问题时可能并不关心这一点。

于 2013-03-17T12:08:32.553 回答