为什么 char name[1] 可以容纳 1 个以上的字符?
Why char name[1] can hold more than 1 character?
遇到这种情况时,我正在对一个主题进行一些研究。
假设以下 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.
您存储输入的变量的大小和类型与scanf
无关。
scanf
仅传递一个地址(指针),用于存放从用户那里获得的输入。
如果传递给 scanf
的格式字符串与参数类型不匹配,聪明的编译器现在会警告您,但原则上您甚至可以将 name
声明为整数:
int name;
它可以很好地保存输入字符串,最多三个字符(第四个用于字符串结尾,即零),假设 int
的大小为 32 位,即 4 个字节
它能工作的事实纯属倒霉,因为当输入数据由 scanf
存储时,运行超过了为其分配的缓冲区的末尾 (name
)。
注意:只为一个字符串分配一个字符是行不通的,即使对于只有一个字符的输入字符串也是如此。您始终需要考虑用于终止它们的 EOS。所以 name
至少应该声明为 char name[2];
。
这是未定义的行为。您的程序发生了缓冲区溢出,因为它恰好分配了一个字符,足以存储一个空的以 null 结尾的字符串。
但是,与您的缓冲区相邻的内存尚未分配给您的程序。 scanf
将您的输入放入该内存中,因为它不知道您的字符串缓冲区有多长。这是一个很大的危险,也是无数黑客攻击的根源,当一个预先确定的字节序列被放入您的字符串中,希望覆盖一些重要元素,并最终获得控制权。
这就是为什么在不指定大小的情况下使用 %s
是危险的。您需要始终为 %s
添加适当的大小限制,否则您的程序有缓冲区溢出的危险。
char name[120];
scanf("%119s",name);
这个程序是安全的,因为即使恶意用户键入超过 120 个字符,scanf
也会忽略第 119 个字符之后的所有内容,如 %119s
格式所指定。
遇到这种情况时,我正在对一个主题进行一些研究。 假设以下 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.
您存储输入的变量的大小和类型与scanf
无关。
scanf
仅传递一个地址(指针),用于存放从用户那里获得的输入。
如果传递给 scanf
的格式字符串与参数类型不匹配,聪明的编译器现在会警告您,但原则上您甚至可以将 name
声明为整数:
int name;
它可以很好地保存输入字符串,最多三个字符(第四个用于字符串结尾,即零),假设 int
的大小为 32 位,即 4 个字节
它能工作的事实纯属倒霉,因为当输入数据由 scanf
存储时,运行超过了为其分配的缓冲区的末尾 (name
)。
注意:只为一个字符串分配一个字符是行不通的,即使对于只有一个字符的输入字符串也是如此。您始终需要考虑用于终止它们的 EOS。所以 name
至少应该声明为 char name[2];
。
这是未定义的行为。您的程序发生了缓冲区溢出,因为它恰好分配了一个字符,足以存储一个空的以 null 结尾的字符串。
但是,与您的缓冲区相邻的内存尚未分配给您的程序。 scanf
将您的输入放入该内存中,因为它不知道您的字符串缓冲区有多长。这是一个很大的危险,也是无数黑客攻击的根源,当一个预先确定的字节序列被放入您的字符串中,希望覆盖一些重要元素,并最终获得控制权。
这就是为什么在不指定大小的情况下使用 %s
是危险的。您需要始终为 %s
添加适当的大小限制,否则您的程序有缓冲区溢出的危险。
char name[120];
scanf("%119s",name);
这个程序是安全的,因为即使恶意用户键入超过 120 个字符,scanf
也会忽略第 119 个字符之后的所有内容,如 %119s
格式所指定。