调用fscanf传入malloc(0)分配指针未触发SIGSEGV的原因问询
现象原因解释
- C语言本身无内置边界检查机制
C语言标准没有要求对动态内存、数组做访问边界校验,写入超出分配范围的内存属于未定义行为。未定义行为没有任何强制约束,程序可能直接崩溃、输出异常结果,也可能看起来完全正常运行,不报错不代表代码逻辑合法,只是当前运行环境下暂时没有触发异常而已。 - malloc(0)的实现特性
C标准中malloc(0)的行为是实现定义的:要么返回空指针,要么返回一个合法但不允许解引用的非空指针。主流C标准库(如glibc、MSVC CRT)都会返回一个满足最小内存对齐要求的非空地址,但该地址指向的空间并不属于当前程序的合法可写范围,后续写入内容本质都是越界访问。 - fscanf无缓冲区校验逻辑
你使用的%[^\n]格式符本身没有任何长度校验能力,只要传入一个指针,fscanf就会不断把读取到的内容写入该指针指向的后续地址,完全不会判断你为这个指针分配了多大的内存空间,其他没有明确指定长度限制的stdio输入函数都存在同样的问题。 - 未触发报错是偶然现象
当前测试环境下没有触发崩溃,只是因为你越界写入的内存暂时没有被其他程序逻辑占用、也没有触发操作系统的页访问保护(比如没有写到堆的保护页、没有覆盖其他正在使用的内存数据),一旦运行环境变化、输入内容变长,大概率会触发段错误、数据污染等异常,这类越界写入也是典型的缓冲区溢出漏洞来源。
修复建议
- 分配内存时明确申请足够容纳目标内容的空间,比如要存最长1023字节的字符串,就申请
1024字节的空间(预留字符串结束符\0的位置) - 使用
fscanf时给格式符加长度限制,比如%1023[^\n],限制最多读取1023个字符,避免溢出 - 更安全的做法是先用
fgets读取整行内容到固定长度缓冲区,再用sscanf解析内容,降低溢出风险 - 增加
malloc返回值的判空逻辑,避免空指针解引用
内容的提问来源于stack exchange,提问作者YayL
相关产品推荐
相关产品推荐

