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>替代手动分配的数组,容器会自动处理内存分配与释放,从根源避免这类错误:
- 修改
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]; } };
- 修改
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; }
- 主函数中调整循环条件:
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
相关产品推荐
相关产品推荐

