2017-05-26 8 views
-2

を発行し、私は、任意の長いテキスト行を読み込み、以下の機能に問題があるのか​​分からない:C - メモリが

char *GetLine(FILE * f) { 
    size_t size = 0; 
    size_t len = 0; 
    size_t last = 0; 
    char *buf = NULL; 
    bool line_end = false; 

    while (!feof(f) && !line_end) { 
     printf("[GetLine] size = %ld, BUFSIZE = %d\n", size, BUFSIZ); 
     size += BUFSIZ; 
     buf = realloc(buf, size); 
     assert(buf); 
     if (fgets(buf + last, (int) size, f) == NULL) 
      return NULL; 
     len = strlen(buf); 
     // overwrite '\0' at the end of the string that fgets put 
     last = len - 1; 
     if (last >= 0 && buf[last] == '\n') 
      line_end = true; 
    } 

    return buf; 
} 

私のテストクライアントは単純です:

int main() { 
    char *line; 

    line = GetLine(stdin); 

    return 0; 
} 

長すぎるライン(長さが8,000未満のもの)でもちゃんと動作しますが、長さ約16,000のラインではクラックします。私BUFSIZEはここで8192

でValgrindのレポートです:

==14413== WARNING: new redirection conflicts with existing -- ignoring it 
--14413--  old: 0x04017ca0 (strlen    ) R-> (0000.0) 0x38075d61 ??? 
--14413--  new: 0x04017ca0 (strlen    ) R-> (2007.0) 0x04c2c730 strlen 
--14413-- REDIR: 0x4017a50 (ld-linux-x86-64.so.2:index) redirected to 0x4c2c2e0 (index) 
--14413-- REDIR: 0x4017c70 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4c2d880 (strcmp) 
--14413-- REDIR: 0x40189a0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4c30330 (mempcpy) 
--14413-- Reading syms from /lib64/libc-2.19.so 
--14413-- REDIR: 0x4eba7f0 (libc.so.6:strcasecmp) redirected to 0x4a23770 (_vgnU_ifunc_wrapper) 
--14413-- REDIR: 0x4ebcae0 (libc.so.6:strncasecmp) redirected to 0x4a23770 (_vgnU_ifunc_wrapper) 
--14413-- REDIR: 0x4eb9f70 (libc.so.6:[email protected]LIBC_2.2.5) redirected to 0x4a23770 (_vgnU_ifunc_wrapper) 
--14413-- REDIR: 0x4eb82f0 (libc.so.6:rindex) redirected to 0x4c2bfc0 (rindex) 
--14413-- REDIR: 0x4ec1180 (libc.so.6:strchrnul) redirected to 0x4c2ff40 (strchrnul) 
[GetLine] size = 0, BUFSIZE = 8192 
--14413-- REDIR: 0x4eb0fd0 (libc.so.6:realloc) redirected to 0x4c2b3a0 (realloc) 
--14413-- REDIR: 0x4eb9640 (libc.so.6:memchr) redirected to 0x4c2d920 (memchr) 
--14413-- REDIR: 0x4ebf210 (libc.so.6:__GI_memcpy) redirected to 0x4c2e220 (__GI_memcpy) 
--14413-- REDIR: 0x4eb65f0 (libc.so.6:strlen) redirected to 0x4c2c670 (strlen) 
[GetLine] size = 8192, BUFSIZE = 8192 
==14413== Invalid write of size 1 
==14413== at 0x4C2E4C3: __GI_memcpy (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==14413== by 0x4E9F542: _IO_getline_info (in /lib64/libc-2.19.so) 
==14413== by 0x4E9E475: fgets (in /lib64/libc-2.19.so) 
==14413== by 0x4007B8: GetLine (in /home/.../alfa_1/src/linetest) 
==14413== by 0x400832: main (in /home/.../alfa_1/src/linetest) 
==14413== Address 0x51e3080 is 0 bytes after a block of size 16,384 alloc'd 
==14413== at 0x4C2B41E: realloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==14413== by 0x400777: GetLine (in /home/.../alfa_1/src/linetest) 
==14413== by 0x400832: main (in /home/.../alfa_1/src/linetest) 
==14413== 

valgrind: m_mallocfree.c:304 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed. 
valgrind: Heap block lo/hi size mismatch: lo = 16448, hi = 3903549025615949881. 
This is probably caused by your program erroneously writing past the 
end of a heap block and corrupting heap metadata. If you fix any 
invalid writes reported by Memcheck, this assertion failure will 
probably go away. Please try that before reporting this as a bug. 


host stacktrace: 
==14413== at 0x3805D3B6: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x3805D4E4: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x3805D666: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x3806A433: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x38056A8B: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x3805556B: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x380593DB: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x38054B67: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) 
==14413== by 0x808C61F58: ??? 
==14413== by 0x808B99EEF: ??? 

sched status: 
    running_tid=1 

Thread 1: status = VgTs_Runnable 
==14413== at 0x4E9E4E2: fgets (in /lib64/libc-2.19.so) 
==14413== by 0x4007B8: GetLine (in /home/.../alfa_1/src/linetest) 
==14413== by 0x400832: main (in /home/.../alfa_1/src/linetest) 

それはいくつかのヒープ割り当ての問題(私はreallocを疑う)のように見えますが、私はそれ

+2

まず、[なぜwhile(!feof(file))が常に間違っているのですか?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong)を参照してください。 )。 –

+1

2つのこと:[while(!feof(...))](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong)を使用しないでください。 'realloc'に渡すのと同じポインタに代入しないでください(' realloc'が 'NULL'を返した場合どうなるか考えてください)。 –

+0

'last> = 0'はコンパイラ警告を発しませんか? (または、コンパイラの警告を有効にするのを忘れたのですか?) 'last'は符号なしなので、比較は真でなければなりません。' len'が0の場合に問題を引き起こします。 'fgets'が' NULL'を返した場合、 。これはメモリをリークし、現在の行を効果的に破棄するので、入力が改行で終わらない場合、最後の行はbitbucketに落とされます。それは厳密に間違っているとは言えません - テキストファイルには終端がないはずはありませんが、驚くかもしれません。 – rici

答えて

5

問題の正確なソースを見ることができませんここにある:

fgets(buf + last, (int) size, f) 

lastが非ゼロの場合、fgets呼び出しは、あなたのBUの境界の外に書くことができますffer。最大でsize - lastバイトを読み取る必要があります。