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

不使用memcpy实现realloc报无效指针错误,求代码排查及拷贝方案

故障原因

  • 头部指针计算错误:内存块头部存储在返回给用户的指针ptr的低地址方向(即ptr - WORD_SIZE位置),你在计算新块头部时用了UNSCALED_POINTER_ADD(newPtr, WORD_SIZE),相当于跑到了新块payload区域的高地址,操作的根本不是合法的头部结构,后续对newBlockInfo->next的访问直接越界。
  • 拷贝长度逻辑错误:你重新将ptrSize赋值为新块的大小,正确逻辑应该是取旧块有效大小、新申请size的较小值作为拷贝长度,否则旧块小于新块时会读到旧块以外的非法内存。
  • 拷贝逻辑完全错位:你循环中一直在拷贝块管理结构体的sizeAndTags字段,还不断修改新旧块的next指针,完全没有拷贝用户实际的payload数据;且next是内存池管理用的链表指针,直接拷贝会彻底破坏新块的管理结构,必然触发指针异常。
  • 缺malloc返回值校验:调用malloc(size)后没有判断返回值是否为NULL,内存分配失败时后续操作全是空指针访问。

无原生拷贝函数的payload传输实现

不需要调用memcpy等原生函数,直接将两个payload指针转换为unsigned char *类型,逐字节循环拷贝即可,逻辑和memcpy底层实现一致。

修正后的完整实现代码

void* realloc(void* ptr, size_t size) {
  BlockInfo * oldBlockInfo;
  size_t oldSize;
  void* newPtr;
  size_t copySize;
  unsigned char *src, *dst;

  if(ptr == NULL){
    return malloc(size);
  }
  if(size == 0){
    free(ptr);
    return NULL;
  }

  // 取旧块信息
  oldBlockInfo = (BlockInfo*) UNSCALED_POINTER_SUB(ptr, WORD_SIZE);
  oldSize = SIZE(oldBlockInfo->sizeAndTags);
  
  // 旧块足够大直接返回
  if (oldSize >= size){
    return ptr;
  }

  // 申请新块,加空指针校验
  newPtr = malloc(size);
  if(newPtr == NULL){
    return NULL;
  }

  // 计算实际要拷贝的大小
  copySize = oldSize < size ? oldSize : size;
  // 逐字节拷贝payload,不需要调用任何原生拷贝函数
  src = (unsigned char *)ptr;
  dst = (unsigned char *)newPtr;
  for(size_t i = 0; i < copySize; i++){
    dst[i] = src[i];
  }

  // 释放旧块返回新指针
  free(ptr);
  return newPtr;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:36:00