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

使用std::make_unique创建数组触发malloc(): corrupted top size错误排查

std::unique_ptr 创建方式引发内存错误的原因解析

在C++开发中,不同方式创建std::unique_ptr会导致两种结果:程序正常运行,或触发malloc(): corrupted top size堆损坏错误。下面分别解析两种错误写法的问题根源。

第一种错误写法(触发内存错误)

#include <tuple>
#include <string>
#include <memory>
#include <fstream>
#include <iostream>
#include <filesystem>

std::tuple<std::unique_ptr<uint8_t*>, size_t> getBinaryData( const std::filesystem::path &sourcePath )
{
    std::ifstream filestream ( sourcePath, std::ios::binary );

    const size_t filesize = std::filesystem::file_size(sourcePath);

    std::cout << "Input file size: " << filesize << " bytes\n";
    
    std::unique_ptr<uint8_t*> buffer = std::make_unique<uint8_t*>( new uint8_t[ filesize ] );
    if ( !filestream.read( ( char* )( buffer.get() ), filesize ) )
    {
        std::cout << "Reading from file " << sourcePath << " failed." << "\n";
    }
    
    filestream.close();

    return { std::move( buffer ), filesize };
}

int main()
{
    auto [memoryPtr, length] = getBinaryData( "myfile.bin" );
}

错误原因

  1. 读写地址完全错误:std::unique_ptr<uint8_t*>是指向uint8_t*类型的智能指针,buffer.get()返回的是uint8_t**(指针的指针)。将其强转为char*传给filestream.read()时,程序并未把文件数据写入new uint8_t[filesize]分配的数组内存,而是直接写入智能指针内部存储的指针变量的内存地址。若文件大小超过指针变量的字节数(通常为8字节),就会越界覆盖堆上的其他数据,直接破坏堆结构,触发malloc(): corrupted top size错误。
  2. 内存释放方式不匹配:unique_ptr销毁时会默认用delete释放它管理的uint8_t*指针,而非delete[]释放数组,这会导致数组内存泄漏,但更致命的是前面的越界写已经破坏了堆结构。

第三种错误写法(同样失效)

#include <tuple>
#include <string>
#include <memory>
#include <fstream>
#include <iostream>
#include <filesystem>

std::tuple<std::unique_ptr<uint8_t*>, size_t> getBinaryData( const std::filesystem::path &sourcePath )
{
    std::ifstream filestream ( sourcePath, std::ios::binary );

    const size_t filesize = std::filesystem::file_size(sourcePath);

    std::cout << "Input file size: " << filesize << " bytes\n";

    std::unique_ptr<uint8_t*> buffer( new uint8_t[ filesize ] );
    if ( !filestream.read( ( char* )( buffer.get() ), filesize ) )
    {
        std::cout << "Reading from file " << sourcePath << " failed." << "\n";
    }
    
    filestream.close();

    return { std::move( buffer ), filesize };
}

失效原因

  1. 类型不匹配导致读写错误:new uint8_t[filesize]返回uint8_t*类型,但std::unique_ptr<uint8_t*>的构造函数需要uint8_t**类型。即便某些编译器允许隐式转换,本质也是把数组首地址当成指向指针的指针存储。和第一种写法一样,buffer.get()返回uint8_t**,强转成char*后依然是把文件数据写入指针变量的内存地址,越界破坏堆结构。
  2. 释放方式不匹配:智能指针销毁时仍用delete释放单个指针,而非delete[]释放数组,进一步加剧堆损坏问题。

补充:正确写法的逻辑

第二种写法能正常运行,是因为std::unique_ptr<uint8_t, std::default_delete<uint8_t[]>>明确指定了数组版本的删除器,确保用delete[]释放数组;同时buffer.get()返回uint8_t*,强转成char*后指向数组首地址,文件数据会正确写入数组内存,不会越界。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:05:09