信号11(SIGSEGV)

时间:2011-09-16 16:17:15

标签: c sigsegv

我写了以下代码:

FILE *book;
wchar_t bufferln[FILE_READ_BUFFER];
wchar_t buffer[FILE_READ_BUFFER];
book = fopen(file, "r");
if(book == NULL){
    perror("Es ist ein Fehler beim lesen des Buches aufgetreten");
    return EXIT_FAILURE;
}
while(fgetws(buffer, FILE_READ_BUFFER, book) != NULL){
    if(wcscmp(buffer, L"\n") == 0){
        bufferln[0] = L'\0';
        continue;
    }
    buffer[wcsnlen(buffer, FILE_READ_BUFFER)-1] = L' ';
    wcsncat(bufferln, buffer, FILE_READ_BUFFER);
}
return EXIT_SUCCESS;

它与SIGSEGV崩溃。我跑了valgrind,显示以下内容:

==11251== Conditional jump or move depends on uninitialised value(s)
==11251==    at 0x40BD5CF: wcsncat (wcsncat.c:36)
==11251==    by 0x804865D: read_book (book.c:18)
==11251==    by 0x804872B: main (main.c:19)
==11251==  Uninitialised value was created by a stack allocation
==11251==    at 0x80485B7: read_book (book.c:3)
==11251== 
==11251== Invalid read of size 4
==11251==    at 0x40A58E2: fgetws (iofgetws.c:52)
==11251==    by 0x804867D: read_book (book.c:12)
==11251==    by 0x6D: ???
==11251==  Address 0x65 is not stack'd, malloc'd or (recently) free'd
==11251== 
==11251== 
==11251== Process terminating with default action of signal 11 (SIGSEGV)
==11251==  Access not within mapped region at address 0x65
==11251==    at 0x40A58E2: fgetws (iofgetws.c:52)
==11251==    by 0x804867D: read_book (book.c:12)
==11251==    by 0x6D: ???
==11251==  If you believe this happened as a result of a stack
==11251==  overflow in your program's main thread (unlikely but
==11251==  possible), you can try to increase the size of the
==11251==  main thread stack using the --main-stacksize= flag.
==11251==  The main thread stack size used in this run was 8388608.

我认为这个问题与我使用wcsncat有什么关系(写入* book内存可能?)但为什么呢? 我想逐段阅读一份文件(UTF-8),然后做一些本代码中没有的内容。

3 个答案:

答案 0 :(得分:2)

您没有初始化bufferln,因此当您将新行连接(wcsncat())到未初始化数据的末尾时,您不知道代码将在何处写入。

你还在输入缓冲区buffer的末尾的空终止符上写了一个(宽)空格,所以你不知道什么会被复制到随机位置;复制将在下一次广泛的NUL上停止。

答案 1 :(得分:1)

可能发生的是你的wcsncat(),根据文档的说法:

” 描述 wcsncat()函数只将ws2指向的字符串的前n个字符追加到ws1指向的字符串的末尾。如果在n个字符之前在ws2中出现NULL字符,则所有直到NULL字符的字符都将附加到ws1。 ws2的第一个字符覆盖ws1的终止NULL字符。 NULL终止字符始终附加到结果,如果用于复制的对象重叠,则行为未定义。 “

因此它会通过覆盖第一次出现的NULL字符而继续追加到bufferln。因此,如果if(wcscmp(buffer,L“\ n”)== 0)返回FALSE,您将最终超出分配的FILE_READ_BUFFER缓冲区并将文件溢出到bufferln边界之外,最终可能最终破坏堆栈。

在大多数情况下,堆栈会向下扩展并且必须到达某些实际上为FAULT的区域,因为在大多数系统上不允许访问虚拟地址页面的前2页。这是一个没有实际意义的原因。但主要原因是,一旦读取数据,就必须尝试将数据写入,因为读写缓冲区的长度相同。

HTH

答案 2 :(得分:0)

如果该行为空(\ n被\ 0替换),则字符串长度为null,并且strlen()-1指向缓冲区。

编辑: 我弄错了;你只是追加太多了。增加缓冲区大小,读取较短的行或两者。 并避免使用strcat();