而当系统调用执行完毕后 , 其对应的返回值将会被放置在寄存器 rax 中 。 因此 , 你可以看到:在代码的第 14 行 , 我们将该寄存器中的值传送到了变量 fd 在栈内存中的位置 。 至此 , 程序对系统调用 open 的使用过程便结束了 , 是不是非常简单?
其实 , 除了低级 IO 接口以外 , C 标准库中还有很多其他的功能函数 , 它们的实际执行也都依赖于所在操作系统提供的系统调用接口 。 因此 , 我们可以得到 C 标准库、系统调用 , 以及应用程序三者之间的依赖关系 , 如下图所示:
这个关系看起来比较清晰 , 但隐藏在操作系统背后的系统调用函数实现细节 , 以及调用细节却非常复杂 。 这里不讨论 。
危险的 gets 函数最后 , 我们再来聊聊标准 IO 与代码安全的相关话题 。
实际上 , C 语言提供的标准 IO 接口并非都是完备的 。 自 C90 开始 , 一个名为 gets 的 IO 函数被添加进标准库 。 该函数主要用于从标准输入流中读取一系列字符 , 并将它们存放到由函数实参指定的字符数组中 。 例如 , 你可以这样来使用这个函数:
#include <stdio.h>
void foo(void) {
char buffer[16
;
gets(buffer);
int main(void) {
foo();
return 0;
可以看到 , 函数的使用方式十分简单 。 在上述代码的第 3 行 , 我们声明了一个 16 字节大小的字符数组 。 紧接着 , 该数组作为实参被传递给了调用的 gets 函数 。 而此时 , 所有来自用户的输入都将被存放到这个名为 buffer 数组中 。 一切看似美好 , 但问题也随之而来 。
实际上 , gets 函数在其内部实现中 , 并没有对用户的输入内容进行边界检查(Bound Check) 。 因此 , 当用户实际输入的字符数量超过数组 buffer 所能承载的最大容量时 , 超出的内容将会直接覆盖掉栈帧中位于高地址处的其他数据 。 而当别有用心的攻击者精心设计输入内容时 , 甚至可以在某些情况下直接“篡改”当前函数栈帧的返回地址 , 并将其指向另外的 , 事先准备好的攻击代码 。
正因如此 , gets 函数已经在 C99 标准中被弃用 , 并在 C11 及以后的标准中移除 。 不仅如此 , 如今的主流编译器在遇到使用了 gets 函数的代码时 , 也会给予相应的安全性提示 。 另外 , DEP、ASLR、Canary 等技术也在一定程度上降低了此类安全事故发生的风险 。 但无论如何 , 请不要在代码中使用 gets 函数 。
- 加州大学|马斯克脑机接口公司被指虐猴,参加实验的23只猴子死了15只
- 互联网|传统企业里,产品经理的价值衡量难题
- 企业|裁员,降薪,大牛出走:AI大退却的始末缘由
- 界面设计中的分割方式
- 权限|CRM 05:基于RBAC理论的权限设计
- 小米科技|家电升级计划:幸福感+N,盘点近期入手的家电好物
- 机箱|内外设置精致双屏幕,二手金立w900体验,国产翻盖手机中的贵族
- 算法|千人千面的算法,走到了十字路口
- 熟人|年轻人都在玩的“啫喱”,没撑过3天?
- 千人千面的算法,走到了十字路口
