打开输出文件流触发STATUS_HEAP_CORRUPTION(错误码3221226356)排查
堆损坏(STATUS_HEAP_CORRUPTION)问题排查与修复
我做学校作业拓展项目,写了一个从程序运行目录开始,在每个子文件夹写入文件的程序,包含递归遍历和文件写入函数。非调试模式下,第一个子文件夹中创建ofstream(第二次写入文件时)触发"exited with code=3221226356"错误(对应STATUS_HEAP_CORRUPTION);移除递归调用后,主目录下文件能正常写入。除输入变量char*外无其他数组,请问是什么原因导致这个内存问题?
#include <dirent.h> #include <stdio.h> #include <iostream> #include <fstream> #include <sstream> #include <cstdlib> #include <time.h> #include <limits.h> const char * separator_char() { #ifdef _WIN32 return "\\"; #else return "/"; #endif } void createCopy(const char * path) { const char * separator = separator_char(); char * file_name_path = strdup(path); strcat(file_name_path, separator); printf("Writing Roberto.txt...\n"); strcat(file_name_path, "Roberto.txt"); std::ofstream dst(file_name_path, std::ios::binary | std::ofstream::trunc); // ERROR HERE dst << "test"; printf("Wrote %s\n", file_name_path); dst.close(); } void multiply(const char * path) { const char * separator = separator_char(); char * path_2 = strdup(path); strcat(path_2, separator); DIR * dir = opendir(path); struct dirent * entry = readdir(dir); while (entry != NULL) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && entry->d_type == DT_DIR) { char * path_3 = strdup(path_2); strcat(path_3, entry->d_name); printf("%s\n", path_3); createCopy(path_3); multiply(path_3); } entry = readdir(dir); } closedir(dir); } int main(int argc, char ** argv) { const char * PATH = "."; multiply(PATH); getchar(); return 0; }
问题原因
核心问题是手动内存管理时的缓冲区越界写入,直接破坏了堆结构:
strdup(path)仅分配刚好容纳path字符串(含末尾\0)的内存空间,没有预留后续追加内容的空间。- 后续调用
strcat追加分隔符和文件名时,会越界写入到堆内存的其他区域,破坏堆的元数据。 - 第一次写入主目录时,堆布局可能刚好未触发崩溃,但递归进入子文件夹后,多次堆分配/释放操作让越界写入的破坏暴露,最终触发STATUS_HEAP_CORRUPTION。
- 同样的越界问题也存在于
multiply函数中的path_2:strdup(path)后直接strcat追加分隔符,同样会超出内存范围。
另外代码未释放strdup分配的内存,会造成内存泄漏,但这不是触发堆损坏的直接原因。
修复方案
用C++的std::string替代手动char*内存管理,它会自动处理内存扩容,彻底避免越界问题。修改后的关键代码示例:
void createCopy(const std::string& path) { const char* separator = separator_char(); std::string file_name_path = path + separator + "Roberto.txt"; printf("Writing Roberto.txt...\n"); std::ofstream dst(file_name_path, std::ios::binary | std::ofstream::trunc); dst << "test"; printf("Wrote %s\n", file_name_path.c_str()); dst.close(); } void multiply(const std::string& path) { const char* separator = separator_char(); std::string path_2 = path + separator; DIR* dir = opendir(path.c_str()); struct dirent* entry = readdir(dir); while (entry != NULL) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && entry->d_type == DT_DIR) { std::string path_3 = path_2 + entry->d_name; printf("%s\n", path_3.c_str()); createCopy(path_3); multiply(path_3); } entry = readdir(dir); } closedir(dir); } int main(int argc, char** argv) { std::string PATH = "."; multiply(PATH); getchar(); return 0; }
内容的提问来源于stack exchange,提问作者SidusBrist
相关产品推荐
相关产品推荐

