c - 为什么 char name[1] 可以容纳 1 个以上的字符?

标签 c gcc segmentation-fault buffer

<分区>

遇到这种情况时,我正在对某个主题进行一些研究。 假设以下 C 代码:

#include <stdio.h>
int main() {
char name[1];
scanf("%s",name);
printf("Hi %s",name);
return 0;
}

我使用 -fno-stack-protector 进行了编译,并使用长度超过 1 的输入对其进行了测试,例如 John,令我惊讶的是,它有效!
当输入长于 1 时,它不应该抛出段错误吗?
最终它打破了 Alexander 作为输入 (9) 但它适用于小于 9 的任何东西。
为什么它使用比名称数组长度更长的输入?
P.S:我正在使用 Ubuntu(64 位)、gcc 版本 4.8.4(Ubuntu 4.8.4-2ubuntu1~14.04)和 CLion 作为 IDE。

最佳答案

这是未定义的行为。您的程序发生了缓冲区溢出,因为它恰好分配了一个字符,足以存储空的以 null 结尾的字符串。

但是,与您的缓冲区相邻的内存尚未分配给您的程序。 scanf 将您的输入放入内存中,因为它不知道您的字符串缓冲区有多长。这是一个很大的危险,也是无数黑客攻击的根源,当一个预先确定的字节序列被放入您的字符串中,希望覆盖一些重要元素,并最终获得控制权。

这就是为什么在不指定大小的情况下使用 %s 是危险的。您需要始终为 %s 添加适当的大小限制,否则您的程序有缓冲区溢出的危险。

char name[120];
scanf("%119s",name);

这个程序是安全的,因为即使恶意用户键入超过 120 个字符,scanf 也会忽略第 119 个字符之后的所有内容,如 %119s 格式所指定.

关于c - 为什么 char name[1] 可以容纳 1 个以上的字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31760510/

相关文章:

c++ - 为什么结构体的 sizeof 不等于每个成员的 sizeof 之和?

gcc - 我应该为 GCC 的 modbus 协议(protocol)使用什么 modbus 库

我可以安全地假设所有(或大部分) "cc"在 *nix 系统上支持 "-Wall"吗?

c++ - 定义为 "_end[LEN]"的数组在 C/C++ 中导致段错误

c - NASM 猜数游戏出了问题

c - 适用于异构元组的快速 8 位校验和算法

c++ - 如何同时迭代两个 Boost 预处理器序列?

c++ - Cortex A9 NEON 与 VFP 使用混淆

c - 无法编译C程序

linux - 如何将/var/log/messages 中的段错误指令指针地址映射到 .map 文件中的地址/函数?