2013-03-17 64 views
0

我讀取特殊格式的二進制文件。我必須使用動態數組讀取具有未知大小的字符串。所有工作正常,但valgrind中有錯誤。 \ 0的賦值不是問題,我沒有嘗試過。我不知道還有什麼可能是錯的。無效的大小爲1的讀取,新的運算符

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) 
+2

你用'-g'標誌建立了嗎?它應該給你行號... – 2013-03-17 11:02:34

回答

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操作implementaion char陣列的4個字節的倍數,以便使這種優化安全。但Valgrind在檢查出界問題時可能並不在意。

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之外。

+0

+1,'int l = 0; i.read((char *)&l,4);')看起來並不那麼熱,因爲它假設一個4字節的'int' *和*對於endian不匹配沒有任何作用。 – WhozCraig 2013-03-17 13:56:22

相關問題