没有 AddressSanitizer 也能正常工作

it works fine without AddressSanitizer

世界!我不擅长动态内存分配,所以请帮助我!问题是,当我在没有消毒剂的情况下编译 c 文件时,它可以正常执行。

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

int main()
{
        char *str = (char *)malloc(sizeof(char));
        int i = 1;
        while (str[i - 2] != '\n')
        {
                str = (char *)realloc(str, i * sizeof(char));
                str[i - 1] = getchar();
                i++;
        }
        str[++i] = '[=10=]';
        fputs(str, stdout);
        free(str);
        return 0;
}

这是消毒剂所说的:

==7174==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000000f at pc 0x55739456b340 bp 0x7fffba0090f0 sp 0x7fffba0090e0
READ of size 1 at 0x60200000000f thread T0
    #0 0x55739456b33f in main (/home/bek/diff1+0x133f)
    #1 0x7fd15ff780b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #2 0x55739456b1ad in _start (/home/bek/diff1+0x11ad)

0x60200000000f is located 1 bytes to the left of 1-byte region [0x602000000010,0x602000000011)
allocated by thread T0 here:
    #0 0x7fd160250bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x55739456b27e in main (/home/bek/diff1+0x127e)
    #2 0x7fd15ff780b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/bek/diff1+0x133f) in main

你有问题

 while (str[i - 2] != '\n')

对于第一次迭代,i1,因此索引值为 -1,这是一个无效索引。

话虽如此,还有两件更重要的事情:

  • malloc() 返回的内存未初始化。如果您在为内存分配任何值之前尝试读取它,您将遇到不确定的值并且程序行为不可预测。

  • 语法

    str = (char *)realloc(str, i * sizeof(char));
    

    是一个非常有问题的指针,万一 realloc() 失败并且 returns 一个 NULL,您最终也会丢失原始指针!

    在将返回值分配给变量之前,始终检查 realloc() 调用是否成功,例如

    char * tmp = NULL;
    tmp = realloc(str, i);  // cast not needed, sizeof(char) == 1 in C
    if (!tmp) { exit(1); /* or cleanup*/}
    str = tmp;              // assign otherwise
    
  • Please see this discussion on why not to cast the return value of malloc() and family in C..

由于您使用的是 POSIX 系统,只需使用轮子而不是重新发明它:

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>

int main(void) {
    char *str = NULL;
    size_t n = 0;
    ssize_t result = getline(&str, &n, stdin);

    if (result < 0) {
        perror("An error occurred in getline");
        exit(1);
    }

    fputs(str, stdout);
    free(str);
}

如果您需要尝试使用较小的系统,可以使用标准 C 库设施实现标准 getline 的许多实现。