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

调用free函数触发段错误的原因(Myers Diff算法C实现)

问题:Myers Diff算法实现中free(path)触发段错误

在用C语言实现Myers Diff算法时,尝试释放path变量的内存时触发段错误。path通过malloc分配,释放时不为空,但执行free(path)时崩溃。相关代码如下:

int ** MakeMoveSet(Comparison_t * comp) {
  int **moveset, *path;
  int64_t n = comp->file1LineCount, m = comp->file2LineCount;
  int64_t max_tries = n + m;
  int64_t max_index = 2 * max_tries + 1;
  int64_t prev, next;
  int x,y;

  fprintf(stderr, "max_tries=%ju, max_index=%ju\n", max_tries, max_index);
  
  path = malloc(sizeof(int) * max_index); //Array of ints;
  moveset = malloc(sizeof(path) * max_tries); //Array of paths

  path[1] = 0;

  for (int d = 0; d < max_tries; d++) {

    for (int k = -d; k <=d; k+=2) {
      fprintf(stderr, "d=%d,k=%d\n", d, k);
      prev = k - 1;
      next = k + 1;

      // Determine whether to move up or down
      if (k == -d || (k != d && path[prev] < path[next])) {
        x = path[next];
      } else {
        x = path[prev] + 1;
      }

      y = x - k;
      
      // Check diagonals to settle x at deepest point
      while ((x < n && y < m) && (strcmp(comp->file1Lines[x], comp->file2Lines[y]) == 0)) {
        x ++;
        y ++;
      }
      
      path[k] = x;

      fprintf(stderr, "x = %d, y=%d\n", x, y);

      if (x >= n && y >= m) {
        free(path); //Segfault occurs here
        fprintf(stderr, "Bailing\n");
        comp->shortest_edit_path = d;
        fprintf(stderr, "Shortest edit path = %d\n", d);
        return moveset;
      }
    }
  }

  return NULL;
  
}

错误原因分析

  • 数组负索引访问破坏内存:
    C语言不支持数组负索引,但代码中k的取值范围是-d到d(比如d=1时k=-1、1),直接用k作为path数组的索引(如path[k]、path[prev])会访问非法内存区域。这会覆盖malloc分配的内存块之外的空间,破坏内存分配器的元数据,最终导致free(path)时触发段错误。

    解决办法是给索引加上偏移量,把负的k转换为合法的非负索引:比如用k + max_tries作为path的索引,因为max_tries = n+m,k的最小值是-(n+m),加上max_tries后索引范围变为0到2*(n+m),刚好匹配max_index = 2*max_tries +1的数组大小。

  • 未初始化数组元素引发逻辑错误:
    代码只初始化了path[1],但循环中会访问path[prev]、path[next]等未初始化的位置,这些位置的值是随机垃圾值,可能导致逻辑错误,进一步加剧内存访问问题。需要在分配path后用memset初始化所有元素,或者根据逻辑初始化必要的位置。

  • moveset分配的潜在问题:
    moveset = malloc(sizeof(path) * max_tries);中sizeof(path)是指针的大小(比如64位系统是8字节),而moveset是int**类型,应该用sizeof(int*)来分配,虽然这不是直接导致段错误的原因,但会导致分配的内存大小不符合预期,后续使用moveset时可能出现问题。

核心修复示例

修改索引计算,添加偏移量:

// 计算索引时加上偏移量max_tries
int64_t offset = max_tries;
// 初始化正确的索引位置
path[offset + 1] = 0;

for (int d = 0; d < max_tries; d++) {
  for (int k = -d; k <=d; k+=2) {
    prev = k - 1;
    next = k + 1;
    // 访问path时加上偏移量
    if (k == -d || (k != d && path[offset + prev] < path[offset + next])) {
      x = path[offset + next];
    } else {
      x = path[offset + prev] + 1;
    }
    // ...
    // 赋值时也加上偏移量
    path[offset + k] = x;
    // ...
  }
}

内容的提问来源于stack exchange,提问作者Charlie Benger-Stevenson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:40:05