使用atoi()与strtol()函数时结构体成员内存被意外修改的问题
问题分析与解决:atoi/strtol执行后字符串指针内容被篡改
问题复现
给定代码片段:
char *op = CURRENT_PARSED_STRING.operand; if(op){ printf("%s\n", op); char q[] = "12h"; int a = atoi(q); printf("%d %s\n", a, op); }
结构体定义:
typedef struct ASSEMBLY_LINE{ char *marker; char *operator; char *operand; char *comment; } ASSEMBLY_LINE;
执行int a = atoi(q);后,CURRENT_PARSED_STRING.operand和op指向的内容被篡改,执行输出:
12h //op content before 12 Q4R //correct value and garbage
替换为strtol()后问题依旧,调试确认执行前结构体字段正常,所有字符串以空字符结尾,未使用字段为NULL,全编译选项也无法解决。
核心原因分析
这种执行标准库函数后无关内存被篡改的情况,99%是堆/栈内存越界导致的:
- 若
operand是malloc分配的字符串,但分配长度不足(比如只分配了实际字符数,未预留\0的位置),后续操作(包括标准库函数的内部栈操作)会覆盖相邻内存。 - 若
CURRENT_PARSED_STRING本身的内存非法(比如指向已释放的堆内存,或栈上已销毁的变量),atoi执行时的栈操作会覆盖这块内存。 - 若之前存在栈数组越界写入(比如某个栈数组写入内容超过其长度),会破坏栈帧结构,后续函数调用(如
atoi)的栈操作会间接篡改op指向的内容(若op指向栈内存)。
排查与修复步骤
- 检查
operand的内存分配- 确认分配长度:比如
operand为"12h"时,需分配strlen("12h") + 1字节,不能只分配3字节(未留\0位置)。 - 排查越界写入:检查往
operand写入字符串时,是否超过了分配的内存长度。
- 确认分配长度:比如
- 确认
CURRENT_PARSED_STRING的内存有效性- 若为栈上结构体,确认其未超出作用域;若为堆上结构体,确认未被提前
free。
- 若为栈上结构体,确认其未超出作用域;若为堆上结构体,确认未被提前
- 检查栈内存越界
- 排查之前的代码是否存在栈数组越界写入的情况,这类操作会破坏栈帧,引发后续内存篡改。
- 临时验证方案
- 将
op指向的内容复制到局部安全数组后再执行atoi,验证原内存是否安全:
若此方案输出正常,说明原if(op){ printf("%s\n", op); char op_copy[100]; // 根据实际字符串长度调整 strcpy(op_copy, op); char q[] = "12h"; int a = atoi(q); printf("%d %s\n", a, op_copy); }op指向的内存本身存在安全问题,需重点排查内存分配环节。
- 将
额外提示
标准库函数atoi/strtol本身不会主动修改传入参数以外的内存,出现此类问题必然是代码存在内存越界或非法内存引用,与标准库无关。
内容的提问来源于stack exchange,提问作者Иван Алленов
相关产品推荐
相关产品推荐

