You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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指向栈内存)。

排查与修复步骤

  1. 检查operand的内存分配
    • 确认分配长度:比如operand为"12h"时,需分配strlen("12h") + 1字节,不能只分配3字节(未留\0位置)。
    • 排查越界写入:检查往operand写入字符串时,是否超过了分配的内存长度。
  2. 确认CURRENT_PARSED_STRING的内存有效性
    • 若为栈上结构体,确认其未超出作用域;若为堆上结构体,确认未被提前free。
  3. 检查栈内存越界
    • 排查之前的代码是否存在栈数组越界写入的情况,这类操作会破坏栈帧,引发后续内存篡改。
  4. 临时验证方案
    • 将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,提问作者Иван Алленов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 09:52:23