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

delete[]触发munmap_chunk(): invalid pointer错误的排查求助

问题

开发仅完成词法分析功能的汇编器时,程序可正常输出Token,但在结束阶段隐式调用~LexerTokenData()析构函数执行delete[] this->token_data时,触发munmap_chunk(): invalid pointer错误。程序输出所有Token后报错终止,错误出现在bits/new_allocator.h,此时__p为"interrupt_table",__n是异常大的数值。

原作者为C语言开发者,刚接触C++,代码带有C风格习惯。

相关代码如下:

主函数代码

int main() {
    std::cout << "\nzazz assembler\n" << std::endl;
    std::unique_ptr<LexerInstance> lexer = std::make_unique<LexerInstance>();
    // Test input
    std::string source = "-off 0xFFFC0000\n-entry start\n\nstart:\n\tmv mri, interrupt_table\n";
    lexer->loadSource(source);
    LexerTokenData tokens = lexer->retrieveTokens();
    if (tokens.token_data == nullptr) {
        std::cout << "Error: tokens: " << tokens.token_count << std::endl;
        return -1;
    }
    for (uint64_t i = 0; i < tokens.token_count; i++) {
        std::cout << "\tToken: " << tokens[i].value << std::endl;
    }
    return 0;
    // Seg fault on `delete[] this->token_data` in `~LexerTokenData()`
}

retrieveTokens()方法代码

LexerTokenData LexerInstance::retrieveTokens() {
    if (!this->tokens_loaded) {
        int status = this->generate_tokens();
        if (status < 0) {
            LexerTokenData token_return = LexerTokenData();
            token_return.token_data = nullptr;
            token_return.token_count = status;
            return token_return;
        }
    }
    LexerTokenData token_return = LexerTokenData();
    token_return.token_data = new LexerToken[this->tokens->size()];
    wmemcpy((wchar_t *)(token_return.token_data), (wchar_t *)(this->tokens->data()), (this->tokens->size() * sizeof(LexerToken)) / sizeof(wchar_t));
    token_return.token_count = this->tokens->size();
    return token_return;
}

析构函数代码

LexerTokenData::~LexerTokenData() {
    // The actual error arises in the line below
    delete[] this->token_data;
}

问题分析与解决

核心错误原因

错误根源是**wmemcpy的使用完全错误**:

  • wmemcpy是针对宽字符(wchar_t)的拷贝函数,第三个参数是宽字符的个数,而非字节数。
  • 当前计算的(this->tokens->size() * sizeof(LexerToken)) / sizeof(wchar_t)会导致拷贝的宽字符数量远超实际需要,直接越界覆盖了new[]分配内存头部的元数据(C++中new[]会在内存头部存储数组大小等信息,供delete[]释放时使用)。
  • 元数据被破坏后,delete[]会识别到无效指针,触发munmap_chunk()错误。

修复方案

方案1:修复拷贝函数(最小改动)

将错误的wmemcpy替换为针对字节拷贝的std::memcpy,直接按字节数拷贝数据:

LexerTokenData LexerInstance::retrieveTokens() {
    if (!this->tokens_loaded) {
        int status = this->generate_tokens();
        if (status < 0) {
            LexerTokenData token_return = LexerTokenData();
            token_return.token_data = nullptr;
            token_return.token_count = status;
            return token_return;
        }
    }
    LexerTokenData token_return = LexerTokenData();
    size_t token_num = this->tokens->size();
    token_return.token_data = new LexerToken[token_num];
    // 替换wmemcpy为memcpy,按字节数拷贝
    std::memcpy(token_return.token_data, this->tokens->data(), token_num * sizeof(LexerToken));
    token_return.token_count = token_num;
    return token_return;
}

方案2:改用std::vector(推荐的C++风格)

彻底抛弃手动内存管理,用std::vector<LexerToken>替代手动分配的数组,容器会自动处理内存分配与释放,从根源避免这类错误:

  1. 修改LexerTokenData结构:
struct LexerTokenData {
    std::vector<LexerToken> tokens;

    // 无需手动编写析构函数,vector会自动管理内存
    ~LexerTokenData() = default;

    // 保持原有的[]访问方式(可选)
    LexerToken& operator[](size_t idx) {
        return tokens[idx];
    }
    const LexerToken& operator[](size_t idx) const {
        return tokens[idx];
    }
};
  1. 修改retrieveTokens()方法:
LexerTokenData LexerInstance::retrieveTokens() {
    if (!this->tokens_loaded) {
        int status = this->generate_tokens();
        if (status < 0) {
            LexerTokenData token_return;
            // 可新增error_code成员传递错误状态,替代原token_count的错误用法
            return token_return;
        }
    }
    LexerTokenData token_return;
    // 直接拷贝vector内容,利用容器的拷贝语义
    token_return.tokens = *this->tokens;
    return token_return;
}
  1. 主函数中调整循环条件:
for (uint64_t i = 0; i < tokens.tokens.size(); i++) {
    std::cout << "\tToken: " << tokens[i].value << std::endl;
}

额外建议

  • 从C转C++时,尽量避免手动使用new/delete,优先使用标准库容器(std::vector、std::string等),它们会自动处理内存管理,大幅减少出错概率。
  • 拷贝数据时,优先使用C++标准算法(std::copy、std::move等)或容器自身的拷贝/移动语义,而非手动调用C风格内存拷贝函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:30:36