std::cout segmentation fault

今天测试功能,发现一个奇怪的问题,std::cout导致崩溃。调用过程如下图:

gdb调试coredump文件,堆栈信息如下图:

 定位具体崩溃日志,发现std::basic_ostream对象没有初始化,如图

 通过谷歌查资料,发现有一个报错跟我类似,根据答复,发现问题出在ios_base::Init没有初始化,

 

ios_base::Init用于构造此成员类型的对象,确保标准流对象(cin,cout,cerr,clog,cin,cout,cerr和clog)被构造和正确初始化。
根据答复,只需要include <iostream>便可以保证ios_base::Init初始化
在C++03中,std::ios_base::Init是未指定的,我们需要确保在输入main()时,标准流已初始化。
C++11修复这个问题,#include <iostream>的每个实例都跟着static std::ios_base::Init __unspecified_name__,这样可以自动保证流可以使用。
我检查程序,发现程序中已经#include <iostream>,应该不存在ios_base::Init没有初始化这种情况
怀疑是dlopen的操作机制影响了ios_base::Init的初始化

函数定义 void * dlopen(const char* pathName, int mode);
pathName 指的是db文件或listDB.so文件在实机环境中的位置, mode指的是打开数据库的模式
mode在linux下,按功能有以下几种
解析方式
RTLD_LAZY:
    暂缓决定,在dlopen返回前,对于动态库中的未定义的符号不执行解析,只对函数引用有效,对于变量引用总是立即解析。这种模式有一个优势,
例如动态库中的某些函数引用了其他第三方库,有些没有,那么调用没有引用第三方库的函数时,可以不用把第三方库的文件放在LD_LIBRARY_PATH下面 RTLD_NOW: 立即决定,在dlopen返回前,解析出所有未定义的符号,如果解析不出来,在dlopen会返回NULL,错误为 undefined symbol:XXX... 作用范围 RTLD_GLOBAL: 动态库中定义的符号可被其后打开的其他库重定位 RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其他库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,那么默认是RTLD_LOCAL。 作用方式 RTLD_NODELETE:在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量。这个flag不是POSIX
-2001标准。 RTLD_NOLOAD: 不加载库,可用于测试库是否已经加载(dlopen()返回NULL说明未加载,否则说明加载),也可用于改变已加载库的flag,
如:先前加载库的flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD
|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL.这个flag不是POSIX-2001标准 RTLD_DEEPBIND:在搜索全局符号前先搜索库内的符号,避免同名符号的冲突,这个flag不是POSIX-2001标准

当dlopen中使用RTLD_DEEPBIND特性,可能会屏蔽全局std::ios_base::Init变量,导致iostream对象没有初始化,

经过实验,在dlopen中取消RTLD_DEEPBIND,崩溃问题得到解决。

 

原文地址:https://www.cnblogs.com/zhanggaofeng/p/15750764.html