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

如何解决C语言程序中检测到的heap buffer overflow问题

问题描述

程序看似运行正常,但用AddressSanitizer编译时触发heap buffer overflow(堆缓冲区溢出),问题出在findInArray函数中。该函数接收二维数组replace(replace[a][0]为待查找单词)和字符串start,功能是在start中查找是否存在replace中的单词。

函数代码如下:

const char * findInArray(const char * (*replace)[2], char * start) // function goes through a array 'start' and searches if the word is also in 'replace'
{ 
  char * copy = (char *) malloc (strlen(start)+1); // I made a copy of a field, so I do not modify the one I passed to function
  char * total = (char *) malloc (strlen(start)+2); // Here I will add words from copy one by one

  memmove(copy,start,strlen(start)+1); // I fill the copy array

  char * tokens = strtok (copy," "); // I split copy array 
  while (tokens != NULL)
  {
  printf("%lu ",strlen(total));
  memmove(total+strlen(total)+1,tokens,strlen(tokens)); // I add words to a new array                                                                    one by one
  memmove (total + strlen(total)," ",1); // at the end of each word I add space
  for (int i = 0 ; replace[i][0] != NULL; i++) // I search if word is in array or not, if yes I return its adress
    {const char *ptr = strstr(total,replace[i][0]); 
    if (ptr != NULL) // If there is match - I return pointer to a word that will be replaced
      {
        free (total);
        return replace[i][0];
      }
    }
    //printf("%s\n",tokens);
    tokens = strtok(NULL, " ");
  }
  free (total);
  return NULL;
  
}

AddressSanitizer给出的错误信息:

==58229==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x000104d00bbb at pc 0x000102c7468c bp 0x00016d562b20 sp 0x00016d5622d8
READ of size 44 at 0x000104d00bbb thread T0
    #0 0x102c74688 in wrap_strlen+0x164 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x14688)
    #1 0x10289e4dc in findInArray test 4.c:39 // the line of moving memory to total
    #2 0x10289ee14 in newSpeak test 4.c:129
    #3 0x10289f880 in main test 4.c:186
    #4 0x1b4df7e4c  (<unknown module>)

0x000104d00bbb is located 0 bytes to the right of 43-byte region [0x000104d00b90,0x000104d00bbb)
allocated by thread T0 here:
    #0 0x102c9eca8 in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3eca8)
    #1 0x10289e480 in findInArray test 4.c:31 // the line of allocating total array
    #2 0x10289ee14 in newSpeak test 4.c:129
    #3 0x10289f880 in main test 4.c:186
    #4 0x1b4df7e4c  (<unknown module>)

问题分析与修复

核心问题

  1. 未初始化的total导致越界读取:malloc分配的内存未清零,strlen(total)会一直读取到内存中的第一个\0,这个位置大概率超出total的分配范围,直接触发溢出。
  2. 写入位置错误:memmove(total+strlen(total)+1, tokens, strlen(tokens))中的+1是多余的,会导致写入位置跳过一个字节,后续追加空格后容易超出total的容量。
  3. 内存泄漏:copy指针未被free,函数退出后会残留内存泄漏。

修复后的代码

const char * findInArray(const char * (*replace)[2], char * start)
{ 
  char * copy = (char *)malloc(strlen(start)+1);
  if (!copy) return NULL; // 增加内存分配失败检查
  char * total = (char *)malloc(strlen(start)+2);
  if (!total) { free(copy); return NULL; } // 分配失败时释放已分配内存

  memmove(copy, start, strlen(start)+1);
  total[0] = '\0'; // 初始化total为空字符串,确保strlen返回正确值

  char * tokens = strtok(copy, " ");
  while (tokens != NULL)
  {
    size_t current_len = strlen(total);
    // 直接追加tokens到total当前末尾
    memmove(total + current_len, tokens, strlen(tokens));
    current_len += strlen(tokens);
    // 添加空格并确保字符串以\0结尾
    total[current_len] = ' ';
    total[current_len + 1] = '\0';

    for (int i = 0 ; replace[i][0] != NULL; i++)
    {
      const char *ptr = strstr(total, replace[i][0]); 
      if (ptr != NULL)
      {
        free(total);
        free(copy); // 释放copy内存
        return replace[i][0];
      }
    }

    tokens = strtok(NULL, " ");
  }

  free(total);
  free(copy); // 释放copy内存
  return NULL;
}

额外优化说明

  • 增加了内存分配失败的检查,避免空指针访问导致的崩溃。
  • 手动维护current_len变量,减少strlen的重复调用,提升效率的同时确保total始终是合法的C字符串。
  • 所有分支都确保copy和total被正确释放,彻底消除内存泄漏风险。

内容的提问来源于stack exchange,提问作者Matouš Kovář

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:45:32