繁体   English   中英

`realloc(): invalid next size` 尝试处理未知大小的输入

`realloc(): invalid next size` while trying to handle input of unknown size

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我有以下代码: function get_unlimited_input如果NULL被传递,则分配一个新字符串,否则它只是将字符附加到现有字符串。 最后它会截断多余的字节。 DEFAULT_BUFFER_SIZE设置为5以测试许多重新分配的情况)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_BUFFER_SIZE 5

char *get_unlimited_input(char *buffer) {
    size_t current_size;
    if (buffer == NULL) {
        buffer = malloc(DEFAULT_BUFFER_SIZE * sizeof(char));
        current_size = DEFAULT_BUFFER_SIZE;
    } else {
        current_size = strlen(buffer) + DEFAULT_BUFFER_SIZE;
    }
    char *cursor = buffer + current_size - DEFAULT_BUFFER_SIZE;
    for (;;) {
        int current = getchar();
        *cursor = (char)current;
        cursor++;
        if (current == '\n' || current == EOF)
            break;
        if (cursor >= buffer + current_size) {
            current_size += DEFAULT_BUFFER_SIZE;
            buffer = realloc(buffer, current_size);
            cursor = buffer + current_size - DEFAULT_BUFFER_SIZE;
        }
    }
    *cursor = '\0';
    buffer = realloc(buffer, cursor - buffer);
    return buffer;
}

int main() {
    printf(">");
    char *buffer = get_unlimited_input(NULL);
    printf(">");
    get_unlimited_input(buffer);
}

在大多数情况下,它工作得很好,但如果我先传递 117 个字符,然后再传递 12 个字符,它就会崩溃:

>.....................................................................................................................
>............
realloc(): invalid next size
Aborted (core dumped)
python3 -c "print('.'*117+'\n'+'.'*12)" | ./_buffer
realloc(): invalid next size
Aborted (core dumped)

问题是什么?

4 个回复

在其他问题中,您在返回缓冲区之前修剪了缓冲区中的所有额外空间。 但是,如果您将缓冲区传递给 function,您会认为它仍然有额外的空间。 因此,您不得将从 function 返回的缓冲区传递回 function。 但你正是这样做的。

    } else {
        current_size = strlen(buffer) + DEFAULT_BUFFER_SIZE;
    }
...
    buffer = realloc(buffer, cursor - buffer);

此外,正如 KamilCuk 所指出的,您不会在返回的字符串中为终止符留出空间,因此在其上调用strlen是不安全的。

您应该记录 function 的输入要求是什么,以及保证 function 的 output 满足哪些要求。 这使得发现这样的错误变得更加容易。

只要你看到,“如果一个缓冲区被传递给这个 function,它必须有额外的空间”和“从这个 function 返回的缓冲区没有任何额外的空间”,很明显你不能将返回的缓冲区传递回function 因为 output 保证不满足输入要求。

基本问题是,当您使用非空指针(先前调用的预先存在的缓冲区)调用get_unlimited_input时,它假定缓冲区大小为strlen(buffer) + DEFAULT_BUFFER_SIZE ,这是错误的。 先前的调用实际上将重新分配缓冲区以匹配不包括终止 NUL 的字符串长度(这意味着终止 NUL 本身很可能会丢失。)

您可以通过在存储 NUL 之后和重新分配之前增加 cursor 来修复这些问题(因此 realloc 将足够大),然后在传递非空指针时将 current_size 的计算更改为strlen(buffer) + 1

另一个问题是,当您从 getchar 获取 EOF 时,您会将该 EOF 转换为 char 并将其存储在缓冲区中。 EOF 不是一个有效字符——让getchar返回一个int而不是一个char的全部意义在于它可以将 EOF 与任何字符区别开来。 因此,在 EOF 上,您在缓冲区中存储了一些随机垃圾字符(或非字符),它们可能只是显示为垃圾,或者可能导致 output 上的崩溃或错误(取决于系统)。

如果您从mallocreallocfree收到运行时错误,则表示您已损坏堆。 堆损坏的常见原因包括在释放 memory 块后使用它(这包括两次调用free )和缓冲区溢出(和下溢)。

损坏发生在运行时错误之前。 它可能发生在很久以前,所以如果你只是在错误发生的时候开始调试程序,可能很难重建发生了什么。 还有其他工具可以帮助您更准确地定位问题。 在具有 GCC 或 Clang 的类 Unix 系统上, AddressSanitizer非常有用。

# Settings for Ubuntu 20.04; you may need to adapt for your system
$ export ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-10/bin/llvm-symbolizer
$ gcc -O -Wall -Wextra a.c -fsanitize=address,undefined && python3 -c "print('.'*117+'\n'+'.'*12)" | ./a.out
=================================================================
==446177==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c000000236 at pc 0x7f246fc0ea6d bp 0x7ffd4e309380 sp 0x7ffd4e308b28
READ of size 119 at 0x60c000000236 thread T0
    #0 0x7f246fc0ea6c  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x67a6c)
    #1 0x55c04dfb32e7 in get_unlimited_input (.../65891246/a.out+0x12e7)
    #2 0x55c04dfb34b1 in main (.../65891246/a.out+0x14b1)
    #3 0x7f246f06f0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #4 0x55c04dfb320d in _start (.../65891246/a.out+0x120d)

0x60c000000236 is located 0 bytes to the right of 118-byte region [0x60c0000001c0,0x60c000000236)
allocated by thread T0 here:
    #0 0x7f246fcb4ffe in __interceptor_realloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10dffe)
    #1 0x55c04dfb345c in get_unlimited_input (.../65891246/a.out+0x145c)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x67a6c) 
Shadow bytes around the buggy address:
  0x0c187fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c187fff8000: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c187fff8010: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa
  0x0c187fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
  0x0c187fff8030: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x0c187fff8040: 00 00 00 00 00 00[06]fa fa fa fa fa fa fa fa fa
  0x0c187fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c187fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c187fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c187fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c187fff8090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==446177==ABORTING

你。 最重要的部分是堆栈跟踪,以及缓冲区溢出发生在“118 字节区域”上的指示,这表明它发生在第一次调用get_unlimited_input的最后或第二次调用的开始。 堆栈跟踪为您提供了发生溢出的确切代码地址,您可以使用它在调试器中设置断点; 你会看到它接近 function 的末端。 正如其他人已经指出的那样,

    *cursor = '\0';
    buffer = realloc(buffer, cursor - buffer);

错了:你没有为'\0'终止符留出空间。 你需要

    *(cursor++) = '\0';
    buffer = realloc(buffer, cursor - buffer);

或者

    *cursor = '\0';
    buffer = realloc(buffer, cursor - buffer + 1);

我还没有审查其他错误(它不是唯一的)。

您的代码中存在多个问题,导致堆损坏,如诊断所示:

  • 您对当前分配大小的假设不正确: current_size = strlen(buffer) + DEFAULT_BUFFER_SIZE; 太乐观了。 由于您在返回之前将缓冲区重新分配给cursor - buffer字节,因此字符串末尾没有松弛。

  • 在将字节存储到数组后测试'\n'EOF 这可能是换行符的预期行为,但对于不是字符的EOF是不正确的。

  • 使用buffer = realloc(buffer, cursor - buffer);重新分配buffer is incorrect too: cursor points to the null terminator, hence you should use a size of cursor + 1 - buffer to keep the null terminator inside the allocated block.

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_BUFFER_SIZE  16  /* use address alignment as incremental size */

char *get_unlimited_input(char *buffer) {
    size_t current_size, pos;
    char *p;

    if (buffer == NULL) {
        pos = 0;
        current_size = DEFAULT_BUFFER_SIZE;
        buffer = malloc(DEFAULT_BUFFER_SIZE);
        if (buffer == NULL)
            return NULL;
    } else {
        pos = strlen(buffer);
        current_size = pos + 1;
    }
    for (;;) {
        int c = getchar();
        if (c == EOF || c == '\0')
            break;
        if (pos + 1 == current_size) {
            // reallocate the buffer
            current_size += DEFAULT_BUFFER_SIZE;
            p = realloc(buffer, current_size);
            if (p == NULL)
                break;
            buffer = p;
        }
        buffer[pos++] = (char)c;
        if (c == '\n')
            break;
    }
    buffer[pos] = '\0';
    p = realloc(buffer, pos + 1);
    return (p != NULL) ? p : buffer;
}

int main() {
    printf("> ");
    char *buffer = get_unlimited_input(NULL);
    printf("got: %s\n", buffer);
    printf("> ");
    get_unlimited_input(buffer);
    printf("got: %s\n", buffer);
    return 0;
}
1 处理未知大小的输入

程序的输入包括两个部分。 输入的第一行是元素数,第二行是所有元素。 这是一个示例输入: 有没有一种方法可以处理这种输入,而无需使用std::string并将其解析为ints的向量? ...

2019-08-28 22:07:02 1 56   c++
3 如何在将它们作为神经网络的输入时处理不同大小的句子?

我给一个句子作为树结构神经网络的输入,其中叶节点将是句子中单词的单词向量。 该树将是一个二值化的选区 (参见二元vs n-ary分支部分)解析树。 我正在尝试开发句子的语义表示。 问题是 ,由于每个句子将具有不同的解析树和不同的长度,每个句子将具有不同的神经网络。 由于这种不 ...

6 处理Image2D时为INVALID_WORK_GROUP_SIZE

我正在尝试在AMD CPU上使用OpenCL 1.1 C ++处理图像。 特点是: 目前内核是空的: 执行调用为: 如果l_width=558和l_height=328 ,则l_localWorkSize不能大于(2,2),否则,我将收到此错误:“无效的工作组大小” ...

2013-01-02 09:37:21 2 620   opencl
8 在C中编码realloc:尝试首先改变分配的大小

我试图在C中重新编写realloc,我有一个关于man和realloc函数的问题,因为它没有完全与realloc的人说的那样。 这是我的代码: 但那个男人说: realloc()函数尝试将ptr指向的分配大小更改为size,并返回ptr。 如果没有足够的空间来扩大ptr ...

9 未知输入大小cin

我确信这是一个简单的问题。 老实说,这应该是编写SAT求解器最简单的部分,但是,我应该有这样的用户输入数据: 所以,我将这些子句存储到字符串向量中,并且它们都会进入另一个向量。 那么从用户那里得到这个输入的最佳方法是什么? 最初没有给出条款数量的事实是让我感到困惑的部分。 我会尝 ...

10 尝试输入时出现 UFuncTypeError

当我尝试输入值时出现(以下)错误,但当我静态分配它们时却没有,我真的不知道为什么。 我正在尝试输入 inn 和 out 的值。 我收到错误代码,但我真的不知道如何修复它。 工作代码: 错误代码: ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM