2017-05-26 3 views
-2

Ich weiß nicht, was mit der folgenden Funktion falsch ist, die eine beliebig lange Textzeile lautet:C sehr lange Linie zu lesen - Speicherprobleme

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; 
} 

Mein Test-Client ist einfach:

int main() { 
    char *line; 

    line = GetLine(stdin); 

    return 0; 
} 

Es funktioniert gut mit nicht zu langen Linien (wie die der Länge unter 8.000), aber es knackt für eine Linie der Länge ca 16.000. Mein BUFSIZE ist 8192

Hier ist, was Valgrind berichtet:

==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]_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) 

Es sieht aus wie ein Heapzuordnung Problem (ich vermute realloc), aber ich kann nicht die genaue Quelle der es

+2

Sehen Sie zunächst [Warum ist während (! Feof (Datei)) immer falsch?] (Https://stackoverflow.com/questions/5431941/why-is-which-feof-file-always-wrong)). –

+1

Zwei Dinge: [Verwende nicht 'while (! Feof (...))'] (http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong), und weisen Sie nicht demselben Zeiger zu, den Sie an 'realloc' übergeben (denken Sie daran, was passiert, wenn' realloc' 'NULL' zurückgibt). –

+0

Führt '' last> = 0' keine Compiler-Warnung aus? (Oder haben Sie vergessen, Compiler-Warnungen zu aktivieren?) Da 'last' nicht vorzeichenbehaftet ist, muss der Vergleich wahr sein, was ein Problem verursacht, wenn' len' 0 ist. Wenn 'fgets'' NULL' zurückgibt, kehren Sie einfach zurück . Dadurch wird Speicher verloren und die aktuelle Zeile wird effektiv verworfen. Wenn Ihre Eingabe nicht mit einem Zeilenumbruch endet, wird die letzte Zeile in den Bitbucket eingefügt. Das ist nicht streng falsch - Textdateien sollten keine unvollendeten Zeilen haben - aber es könnte überraschend sein. – rici

Antwort

5

Das Problem sehen hier ist:

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

Wenn last nicht Null ist dann der fgets Anruf kann außerhalb der Grenzen Ihres bu schreiben ffer. Sie müssen höchstens size - last Bytes lesen.

Verwandte Themen