地址检查器:地址上的堆缓冲区溢出问题

58

我正在学习C语言的入门阶段。

我正在尝试编写一个函数来打开文件,读取BUFFER_SIZE个字符,将内容存储在数组中,然后跟踪字符'\n'(因为我想获取输入的每一行)。

当我将BUFFER_SIZE设置得非常大时,我可以获得第一行。 当我将BUFFER_SIZE设置得相对较小(比如42),这还不是第一行的结尾时,它会打印出一些奇怪的符号,但我猜这是我的代码中的某个错误。

然而,当我将BUFFER_SIZE设置得非常小,比如= 10,并使用-fsanitizer = address检查内存泄漏时,它会抛出一堆错误信息:

==90673==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000fb at pc 0x000108868a95 bp 0x7fff573979a0 sp 0x7fff57397998
READ of size 1 at 0x6020000000fb thread T0

如果有人能够以通俗易懂的方式解释:

  • 什么是fsanitizer = address标志?

  • 什么是堆缓冲区溢出?

  • 什么是地址和线程?有什么标志可以在屏幕上看到带颜色的线程?

  • 为什么会说“读取大小为1的地址…”?

非常感谢 <3


@n.m. 真有趣,这正是我提到的“我的代码”中出现的同样错误。我确实分配了一个额外的字节,但我没有放置0来确保结束该缓冲区。 :D - Dr Linh Chi Nguyen
3个回答

57

什么是fsanitizer=address标志?

通常,C编译器不会为内存访问添加边界检查。有时由于代码错误,会从缓冲区外部读取或写入数据,这种错误通常很难检测到。使用此标志,编译器将添加一些边界检查,以确保您不会使用缓冲区来超出其分配范围。

什么是堆缓冲区溢出?

使用一个数组达到其分配之后的位置,

char* x = malloc(10);
char n=x[11]; //heap-buffer-overflow
(下溢是指达到分配之前)
char* x = malloc(10);
char n=x[-11]; //heap-buffer-underflow

地址和线程是什么?

地址是内存中的位置,线程是进程中运行代码序列的一部分。

为什么它说“在地址处读取1个字节的大小..”?

这意味着你从给定的地址读取单个字节。


我认为你的问题是你将BUFFER_SIZE分配给缓冲区,并将相同的BUFFER_SIZE读入其中。正确的方法是总是声明比你要读取的字节数多至少一个字节。 像这样:

char* buff = malloc(BUFFER_SIZE+1);//notice to +1
fread(buff,1,BUFFER_SIZE,fp);

2
一个数组通常不位于堆上;它要么在栈上,要么在bss中,这取决于它被声明的作用域。堆空间通常由malloc()分配。 - Ctx
在这种情况下,分配之外有READ。我猜是在打印缓冲区时出现的。 - SHR
我试图解释,在你的例子int n=x[11];中,x既不是堆缓冲区,也不是缓冲区溢出。你应该为你的部分“什么是堆缓冲区溢出”提供一个更合适的例子。 - Ctx
2
这个 C 语言错误是常青的 :D 我从几年前遇到的这个问题中得到了稳定的声望积分 ^^ - Dr Linh Chi Nguyen
通常,当分配一个缓冲区来容纳一个C字符串及其尾随的空字节时,会执行 size + 1。如果您存储的不是C字符串,也不会被视为C字符串,则多余的字节是无意义的。另外,在最后一个示例中打印缓冲区时,无法保证缓冲区以空字节结束,因此仍可能读取越界! - multithr3at3d
显示剩余4条评论

13

简单来说,使用new关键字创建的变量出现了分段错误,因为所有这些变量都存储在堆内存区域中。

解释 - 您正在尝试访问未声明变量的地址,要查找所有这些错误,请重新审查您的条件并检查是否超出了边界。


-1

这也可以通过进行快速输入/输出来纠正:

//用于快速 I/O

    **ios_base::sync_with_stdio(false);
    cin.tie(NULL);**

这个问题是关于C错误的,你的解决方案是关于C++的。 - wowonline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接