信号 11 (SIGSEGV)

发布于 2024-12-04 17:37:56 字数 1859 浏览 0 评论 0原文

我编写了以下代码:

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),然后执行此代码中尚未包含的操作。

I wrote the following code:

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;

It crashes with SIGSEGV. I ran valgrind which shows the following:

==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.

I think the problem is somehow related to my usage of wcsncat (writing into *book memory maybe?) but why?
I want to read a document (UTF-8) paragraph by paragraph and then do stuff that is not in this code yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

隔纱相望 2024-12-11 17:37:56

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

您还在输入缓冲区 buffer 末尾的空终止符上写了一个(宽)空格,因此您不知道什么将被复制到随机位置;当下次遇到宽 NUL 时,复制将停止。

You don't initialize bufferln, so you've no idea where your code is going to write when you concatenate (wcsncat()) the new line to the end of the uninitialized data.

You also write a (wide) space over the null terminator at the end of the input buffer buffer, so you've no idea what is going to be copied into the random location; copying will stop when it next hits a wide NUL.

不如归去 2024-12-11 17:37:56

可能发生的情况是,根据文档,您的 wcsncat() 会执行以下操作:


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

因此,它会通过覆盖第一次出现的 NULL 字符来不断追加到 bufferln。因此,在 if(wcscmp(buffer, L"\n") == 0) 返回 FALSE 的情况下,您最终将超出分配的 FILE_READ_BUFFER 缓冲区,并且将文件溢出到 bufferln 边界之外,并可能最终损坏堆栈。

在大多数情况下,堆栈向下增长,并且它必须到达某些实际上发生故障的区域,因为访问了前 2 页。大多数系统都不允许您的虚拟地址页。这是一个有争议的问题,但主要原因是您必须在读取数据后尝试将数据写入某处,因为您的读写缓冲区已满。 的长度。

相同

What could be happening is that your wcsncat() which as per documentation does :

"
DESCRIPTION
The wcsncat() function appends no more than the first n characters of the string pointed to by ws2 to the end of the string pointed to by ws1. If a NULL character appears in ws2 before n characters, all characters up to the NULL character are appended to ws1. The first character of ws2 overwrites the terminating NULL character of ws1. A NULL terminating character is always appended to the result, and if the objects used for copying overlap, the behavior is undefined.
"

So it keeps appending to bufferln starting by overwriting the first occurence of NULL character. So in cases where if(wcscmp(buffer, L"\n") == 0) returns FALSE you will end up overrunning your allocated buffer of FILE_READ_BUFFER and spill the file outside the bufferln boundary and possibly end up corrupting the stack.

In most cases stacks grow downwards and it must have reached some regions which actually FAULT because accessing the first 2 pages of your virtual address pages is not allowed on most systems. This is a moot point as to why it faulted there. But the main reason is that you have to try write the data somewhere once you have read it as your read and write buffers are of the same length.

HTH

泪意 2024-12-11 17:37:56

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

编辑:
我听错了;你只是附加了太多。增加缓冲区大小,读取较短的行,或两者兼而有之。
并避免 strcat();

If the line is empty (\n gets replaced by \0) , the string length is null, and strlen() -1 points below the buffer.

EDIT:
I got it wrong; you are just appending too much. Increase your buffer size, read shorter lines, or both.
And avoid strcat();

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文