Ubuntu20.04下SFML调用window.close()触发栈粉碎终止问题
问题根因分析
你遇到的stack smashing detected报错是栈帧被非法改写触发的系统保护,结合复现条件和代码逻辑,优先排查以下几个常见触发点:
- SFML多版本隐式冲突
你描述仅安装了一个版本的SFML,但大概率存在手动编译安装的残留版本:apt安装的SFML路径在/usr/lib/下,而手动编译默认安装到/usr/local/lib/,编译时用了apt的头文件,链接时优先链接了/usr/local下的不同版本库,ABI不匹配就会出现这类奇怪的内存错误。 - 头文件守卫不符合规范
你用的__GAME__、__PECA__属于C++标准保留给编译器实现的标识符(双下划线开头),使用这类标识符会触发未定义行为,极端情况会影响内存布局。 - SFML资源析构顺序问题
SFML的图形资源(比如ConvexShape)依赖OpenGL上下文,而RenderWindow销毁时会连带销毁OpenGL上下文,如果图形资源的析构晚于RenderWindow,就会访问已释放的上下文内存,改写栈空间。
解决方案按优先级执行:
步骤1:排查删除残留SFML版本
执行以下命令检查程序链接的SFML库路径:
ldd ./jogo | grep sfml
如果输出中有路径前缀为/usr/local/lib/的SFML库,执行以下命令删除残留版本:
sudo rm -rf /usr/local/lib/libsfml* sudo rm -rf /usr/local/include/SFML
删除后重新编译项目运行测试,90%以上的同类问题都是这个原因导致。
步骤2:修正头文件守卫
把两个头文件的守卫改为标准格式:
Game.h改为:
#ifndef GAME_H #define GAME_H // 原有代码不变 #endif
Peca.h改为:
#ifndef PECA_H #define PECA_H // 原有代码不变 #endif
步骤3:确认成员析构顺序
Game类的成员声明顺序要保证图形资源在RenderWindow之后声明(C++类成员析构顺序和声明顺序相反,后声明的先析构,保证ConvexShape在RenderWindow销毁前先析构),你的原有顺序是对的,可确认没有被修改:
// Game.h 成员声明顺序保持不变 sf::RenderWindow window; Peca peca;
步骤4:临时关闭栈保护验证
如果以上步骤都无效,可在编译选项中加入-fno-stack-protector临时关闭栈保护,验证是否是编译器栈保护的误判:
修改Makefile的编译命令:
jogo.o: jogo.cpp g++ -c jogo.cpp -fno-stack-protector Game.o: Game.cpp g++ -c Game.cpp -fno-stack-protector Peca.o: Peca.cpp g++ -c Peca.cpp -fno-stack-protector
如果关闭后不再报错,说明是gcc 9在Ubuntu20.04下的偶发栈保护误判,可升级gcc版本解决。
内容的提问来源于stack exchange,提问作者Q.asker
相关产品推荐
相关产品推荐

