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

重新分配动态数组时触发double corruption错误的排查求助

C++内存池析构触发double free错误的原因分析

问题描述

以下自定义内存池代码在运行时,程序结束阶段的~MemoryPool()析构函数调用delete[]时触发错误:

double free or corruption (out)
Aborted (core dumped)

使用valgrind检测指向reallocate()函数,现定位错误原因。

代码示例

#include <iostream>
#include <cstring>

using std::cout, std::endl;

struct Chunk{
  Chunk(){};
  int* get(){ return reinterpret_cast<int*>(&_data[0]);}
  unsigned char _data[sizeof(int)];
};

class MemoryPool{
public:
  MemoryPool(size_t capacity):_capacity(capacity)
  {
    _size=0;
    _data=new Chunk[_capacity];
    _vacant=new bool[_capacity];
    for(int i=0; i<_capacity; ++i) _vacant[i]=true;
  }
  ~MemoryPool()
  {
    delete [] _data;
    delete [] _vacant;
  }
  size_t size() const {return _size;}
  size_t capacity() const {return _capacity;}
  int* allocate()
  {
    int index=find_vacant();
    if(-1 == index)
    {
      reallocate();
      index=find_vacant();
    }
    _vacant[index]=false;
    ++_size;
    return get(index);
  }
  void reallocate()
  {
    const int new_capacity=2*_capacity+1;
    Chunk* new_data  =new Chunk[new_capacity];
    bool*  new_vacant=new bool[new_capacity];
    std::memcpy(new_data, _data, _size*sizeof(Chunk));
    std::memcpy(new_vacant, _vacant, _size*sizeof(bool));
    for(int i=_size; i<new_capacity; ++i) new_vacant[i]=true;
    std::swap(_data,new_data);
    std::swap(_vacant,new_vacant);
    delete [] new_data;
    delete [] new_vacant;
    _capacity=new_capacity;
  }  
  int* get(int index)
  {
    return reinterpret_cast<int*>(&_data[index]);
  }
  int find_vacant()
  {
    int index=-1;
    for(int i=0; i<(int)_capacity; ++i)
    {
      if(_vacant[i])
      {
        index=i;
        break;
      }
    }
    return index;
  }  
private:
  size_t _size;
  size_t _capacity;
  Chunk* _data;
  bool* _vacant;
};

int main()
{
  MemoryPool pool(10);
  cout<<"pool.size()="<<pool.size()<<endl;
  for(int i=0; i<11; ++i)
  {
    int* ptr=pool.allocate();
    *ptr=i+1;
  }
  cout<<"PRINT:"<<endl;
  for(int i=0; i<pool.size(); ++i) cout<<*(pool.get(i))<<" ";
  cout<<endl;
  return 0;
}

错误原因

1. 指针转换逻辑错误(核心问题)

MemoryPool::get()函数的指针转换是未定义行为:

int* get(int index)
{
  return reinterpret_cast<int*>(&_data[index]);
}

这里直接将Chunk*类型的&_data[index]强制转换为int*,虽然Chunk仅包含unsigned char _data[sizeof(int)],但编译器可能为结构体添加内存填充字节以满足对齐要求,导致Chunk的实际大小大于sizeof(int)。此时对转换后的指针执行写操作(如*ptr=i+1)会越界覆盖相邻内存,可能破坏_vacant数组的内容,最终引发析构时的内存损坏错误。

2. 循环变量类型不匹配

find_vacant()中使用int类型遍历size_t类型的_capacity,当_capacity超过INT_MAX时会出现溢出,导致循环逻辑错误。

修复方案

  1. 修正指针转换逻辑:复用Chunk类的get()方法,确保指向正确的内存区域:
int* get(int index)
{
  return _data[index].get();
}
  1. 统一循环变量类型:将find_vacant()的循环变量改为size_t,避免溢出:
int find_vacant()
{
  int index=-1;
  for(size_t i=0; i<_capacity; ++i)
  {
    if(_vacant[i])
    {
      index=static_cast<int>(i);
      break;
    }
  }
  return index;
}
  1. 优化扩容时的数组复制:复制_vacant数组时直接复制整个旧数组,确保状态完全一致:
std::memcpy(new_vacant, _vacant, _capacity*sizeof(bool));

内容的提问来源于stack exchange,提问作者And

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:00:52