Fedora39下GCC编译C++代码出现Segmentation fault的原因排查
C++代码出现Segmentation fault的原因分析
我在Fedora 39系统上使用gnu编译器g++ (GCC) 13.2.1 20231205 (Red Hat 13.2.1-6)运行以下C++代码时,出现了Segmentation fault (core dumped)错误:
#include <iostream> #include <fstream> #include <string> using namespace std; int main (int argc, char** argv) { string stri = ""; cout << "Enter some characters: "; getline(cin, stri); cout << "You entered: " << stri << endl; clog << "This is the output to a terminal \"clog\"! " << stri << endl; ofstream out ("clog.txt"); if (out) { clog.rdbuf(out.rdbuf()); } else { cerr << "This is the output to a terminal \"cerr\"" << stri << endl; } clog << "This is the output to a file \"clog\"! " << stri << endl; return 0; }
运行输出:
Enter some characters: re
You entered: re
This is the output to a terminal "clog"! re
Segmentation fault (core dumped)
但仅添加一个未使用的string变量stri1后,代码即可正常运行:
#include <iostream> #include <fstream> #include <string> using namespace std; int main (int argc, char** argv) { string stri = ""; string stri1 = ""; // 仅添加此未使用变量就不再报错 cout << "Enter some characters: "; getline(cin, stri); cout << "You entered: " << stri << endl; clog << "This is the output to a terminal \"clog\"! " << stri << endl; ofstream out ("clog.txt"); if (out) { clog.rdbuf(out.rdbuf()); } else { cerr << "This is the output to a terminal \"cerr\"" << stri << endl; } clog << "This is the output to a file \"clog\"! " << stri << endl; return 0; }
运行输出:
Enter some characters: re
You entered: re
This is the output to a terminal "clog"! re
两种情况均能正确将信息写入clog.txt文件,以下是问题原因分析:
问题根源
核心问题是**clog的缓冲区生命周期与局部变量out的生命周期冲突**:
std::clog默认使用全局标准错误流的缓冲区(和std::cerr共享)。当调用clog.rdbuf(out.rdbuf())时,clog会接管out的文件缓冲区,但未保存原缓冲区指针。- 函数
main执行完毕时,局部变量out会被销毁,其内部的文件缓冲区内存也会被释放。但此时std::clog仍然指向这块已被释放的内存。 - 程序退出阶段,C++标准库会尝试刷新并销毁
std::clog的缓冲区,访问已释放内存直接触发Segmentation fault。
为什么添加stri1能"解决"问题?
这是栈内存布局变化导致的巧合,属于C++未定义行为的表现:
- 添加
stri1后,栈上的内存布局被改变。当out销毁时,其原缓冲区所在的内存可能未被立即覆盖或回收,程序退出时的内存检查恰好没触发错误。 - 这不是真正的解决方案,只是错误被暂时隐藏,换个环境或输入仍可能复现崩溃。
正确的修复方式
要避免问题,需在替换缓冲区时保存原指针,并在out销毁前恢复clog的原缓冲区:
#include <iostream> #include <fstream> #include <string> using namespace std; int main(int argc, char** argv) { string stri = ""; cout << "Enter some characters: "; getline(cin, stri); cout << "You entered: " << stri << endl; clog << "This is the output to a terminal \"clog\"! " << stri << endl; ofstream out("clog.txt"); if (out) { // 保存clog的原缓冲区指针 streambuf* original_buf = clog.rdbuf(out.rdbuf()); clog << "This is the output to a file \"clog\"! " << stri << endl; // 恢复clog的原缓冲区 clog.rdbuf(original_buf); } else { cerr << "This is the output to a terminal \"cerr\"" << stri << endl; } return 0; }
这样clog在out销毁前就恢复了原缓冲区,程序退出时不会访问已释放的内存。
内容的提问来源于stack exchange,提问作者questioner
相关产品推荐
相关产品推荐

