_GLIBCXX_USE_CXX11_ABI 定义不一致带来的宕机问题
文章目录
- ABI 是什么
- _GLIBCXX_USE_CXX11_ABI 是什么
- 一段示例
- 踩坑
- -- 情形1
- -- 情形2
- 结论
- -- 怎么发现的
- -- 情形1
- -- 情形2
- -- 总结
- 环境
- 引用
很久没有写文章了记录点什么了,这次问题还算印象深刻
ABI 是什么
我们看看wiki定义: 应用二进制接口(英语:application binary interface,缩写为ABI)是指两程序模块间的接口,一个ABI定义了机器代码如何访问数据结构与运算程序,此处所定义的界面相当低端并且相依于硬件。而类似概念的API则在源代码定义这些,则较为高端,并不直接相依于硬件,通常会是人类可阅读的代码。一个ABI常见的样貌即是调用约定:资料怎么成为计算程序的输入或者从中得到输出;x86的调用约定即是一个ABI的例子
_GLIBCXX_USE_CXX11_ABI 是什么
一个宏定义.
In the GCC 5.1 release libstdc++ introduced a new library ABI that includes new implementations of std::string and std::list. These changes were necessary to conform to the 2011 C++ standard which forbids Copy-On-Write strings and requires lists to keep track of their size.
完整文章
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
大意是c++ 11 的新提案修改了 std::string 和 std::list 的 ABI接口,但是直到 GCC 5.1才发布.
截取 gcc-9.3.0/include/c++/9.3.0/x86_64-pc-linux-gnu/bits/c++config.h
中的一段代码
#if _GLIBCXX_USE_CXX11_ABI
namespace std
{inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
namespace __gnu_cxx
{inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
# define _GLIBCXX_NAMESPACE_CXX11 __cxx11::
# define _GLIBCXX_BEGIN_NAMESPACE_CXX11 namespace __cxx11 {# define _GLIBCXX_END_NAMESPACE_CXX11 }
# define _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_ABI_TAG_CXX11
#else
# define _GLIBCXX_NAMESPACE_CXX11
# define _GLIBCXX_BEGIN_NAMESPACE_CXX11
# define _GLIBCXX_END_NAMESPACE_CXX11
# define _GLIBCXX_DEFAULT_ABI_TAG
#endif
string 和 list 简化一下实现大概应该是这个样子
#if _GLIBCXX_USE_CXX11_ABI
namespace std {inline namespace __cxx11 {class string {};class list {};};
};
#else
namespace std {class string {};class list {};
}
#endif
命名空间前加 inline 关键字是c++11 的新特性 “内联命名空间”,有兴趣的自己去了解一下,这个不是今天讨论的重点
使用 GCC 5.1+ 的编译器,默认 _GLIBCXX_USE_CXX11_ABI =1
也就是默认使用新版ABI的string 和 list,如果要禁用c++11新版ABI, 只需要在Makefile中定义 -D _GLIBCXX_USE_CXX11_ABI=0
就可继续使用旧版本ABI顺利编译通过
一段示例
典型的使用了老版ABI库的错误提示
tLogger.cpp:55: undefined reference to `log4cxx::WriterAppender::getEncoding[abi:cxx11]() const'
tLogger.cpp:58: undefined reference to `log4cxx::Level::toString[abi:cxx11]() const' objs/bin/tLogger.o: In function `libtse::tLogger::createDailyRollingLogger(libtse::tLoggerAttribute const&)':
tLogger.cpp:117: undefined reference to `log4cxx::Logger::getLogger(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:122: undefined reference to `log4cxx::WriterAppender::setEncoding(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:123: undefined reference to `log4cxx::Level::toLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:138: undefined reference to `log4cxx::DailyRollingFileAppender::setDatePattern(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:141: undefined reference to `log4cxx::PatternLayout::setConversionPattern(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:154: undefined reference to `log4cxx::WriterAppender::setEncoding(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
tLogger.cpp:155: undefined reference to `log4cxx::Level::toLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' objs/bin/tLogger.o: In function `libtse::tLogger::setlevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
tLogger.cpp:180: undefined reference to `log4cxx::Level::toLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' objs/bin/tLogger.o: In function `libtse::tLogger::trace(char const*, ...)':
tLogger.cpp:192: undefined reference to `log4cxx::Logger::trace(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const' objs/bin/tLogger.o: In function `libtse::tLogger::debug(char const*, ...)':
tLogger.cpp:204: undefined reference to `log4cxx::Logger::debug(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const' objs/bin/tLogger.o: In function `libtse::tLogger::info(char const*, ...)':
tLogger.cpp:216: undefined reference to `log4cxx::Logger::info(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const' objs/bin/tLogger.o: In function `libtse::tLogger::warn(char const*, ...)':
tLogger.cpp:228: undefined reference to `log4cxx::Logger::warn(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const' objs/bin/tLogger.o: In function `libtse::tLogger::error(char const*, ...)':
tLogger.cpp:240: undefined reference to `log4cxx::Logger::error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const' objs/bin/tLogger.o: In function `libtse::tLogger::fatal(char const*, ...)':
tLogger.cpp:252: undefined reference to `log4cxx::Logger::fatal(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const'
collect2: error: ld returned 1 exit status
踩坑
– 情形1
情形描述
- 库LibA 指定采用旧版ABI编译( _GLIBCXX_USE_CXX11_ABI = 0)
- 库LibB 采用默认编译选项 (_GLIBCXX_USE_CXX11_ABI = 1)
- 库LibB 引用了 LibA
- 程序C依赖LibA和LibB,采用默认编译选项 (_GLIBCXX_USE_CXX11_ABI = 1)
Boom! 程序会莫名奇妙的宕机
疑问:为什么LibA使用旧版本ABI,而程序使用新版ABI却可以编译通过?
解答:程序C中没有引用到LibA内有关string 和 list的接口
– 情形2
情形描述
- 库LibA 采用默认编译选项 _GLIBCXX_USE_CXX11_ABI = 1
- 库LibB 指定采用旧版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 0)
- 库LibB 引用了 LibA
- 程序C依赖LibA和LibB,由于LIbB使用了旧版ABI,需要指定 _GLIBCXX_USE_CXX11_ABI = 0才行
Boom! 程序任然会莫名奇妙的宕机。
宕机的位置
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3730==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x7f5edb0c60d5 bp 0x7fffc90c5240 sp 0x7fffc90c5228 T0)
==3730==The signal is caused by a READ memory access.
==3730==Hint: address points to the zero page.#0 0x7f5edb0c60d4 in __pthread_cond_signal (/lib64/libpthread.so.0+0xc0d4)AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib64/libpthread.so.0+0xc0d4) in __pthread_cond_signal
结论
– 怎么发现的
- 最近升级了gcc9高版本,修改了Makefile
- 这问题断断续续我查了好几天时间,主要是花在啃代码上调试上,觉得代码是不是有什么隐藏bug,完全没有想到是ABI定义不一致问题造成的
- 由于我还有一台云主机,上面也有工程代码,在这上面编译运行却一切正常
接下来验证一下自己的猜想
– 情形1
- 库LibA 指定采用旧版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 0)
- 库LIbB 指定采用旧版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 0)
- 程序C 指定采用旧版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 0)
运行正常
– 情形2
- 库LibA 指定采用新版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 1)
- 库LIbB 指定采用新版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 1)
- 程序C 指定采用新版ABI编译 (_GLIBCXX_USE_CXX11_ABI = 1)
运行正常
– 总结
- 首先一个观点,在实际项目中使用老版ABI的库是再正常不过的事情,如果升级了gcc 5.1+ 并且引用了库中string或者list相关接口,势必需要指定 (_GLIBCXX_USE_CXX11_ABI = 0)
- 将引用到的老版本ABI库使用新gcc重新编译,如果没有源码或者编译三方库非常麻烦,确保引用的库中间不要混合使用新版ABI和旧版ABI
环境
系统环境
CentOS Linux release 7.7.1908 (Core)
编译器环境
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/gcc-9.3.0/libexec/gcc/x86_64-pc-linux-gnu/9.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-9.3.0/configure --prefix=/usr/local/gcc-9.3.0/ --enable-checking=release --enable-languages=c,c++ --disable-multilib
Thread model: posix
gcc version 9.3.0 (GCC)
引用
- https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
_GLIBCXX_USE_CXX11_ABI 定义不一致带来的宕机问题相关推荐
- 服务器宕机是什么原因
随着如今互联网,计算行业的快速发展,数据和信息安全的重要性也越发重要,选择一款稳定的服务器固然重要. 但再好的服务器也难免在使用过程中出现这样或那样的问题,其中服务器宕机就是最为常见的.那么,通常造成 ...
- AOF日志:宕机了,Redis如何避免数据丢失?
你会把 Redis 用在什么业务场景下? 我想你大概率会说: "我会把它当作缓存使用,因为它把后端数据库中的数据存储在内存中,然后直接从内存中读取数据,响应速度会非常快. "没错, ...
- Redis的KEYS命令引起宕机事件
摘要: 使用 Redis 的开发者必看,吸取教训啊! 原文:Redis 的 KEYS 命令引起 RDS 数据库雪崩,RDS 发生两次宕机,造成几百万的资金损失 作者:陈浩翔 Fundebug经授权转载 ...
- 2018年十大云宕机事故盘点:主流无一幸免!
根据IDC今年7月份发布的<中国公有云服务市场半年度跟踪报告>显示,阿里云的市场占有率已过45%,腾讯云达到10%.在全球市场,根据Gartner最新数据显示,亚马逊AWS占全球份额的51 ...
- 如何降低数据中心宕机事件的影响
大多数人在生活或工作领域中都不希望出现连接中断的情况,尤其是在以数字生活方式为主的今天,所以数据中心基础设施变得越来越重要.对于许多消费者来说,他们希望自己的数字产品和服务能保持正常工作,所以当发生宕 ...
- 由中行IBM大型机宕机谈银行系统运维
12月15日中行IBM大型机宕机,系统没有第一时间切换到热备或者异地容灾上,直接影响中行的信用卡支付相关业务,直到4小时之后才恢复服务.由于银行业务的特殊性,对于系统的可用性要求极高,就此事件,我们采 ...
- 第七十六期:3000台服务器不宕机,微博广告系统全景运维大法
微博现在日活达到了 2 亿,微博广告是微博最重要且稳定的收入来源,没有之一,所以微博广告系统的稳定性是我们广告运维所有工作中的重中之重. 作者:孙燕来源 微博现在日活达到了 2 亿,微博广告是微博最重 ...
- 谷歌、Facebook 大规模宕机!“裸奔时代”程序员该怎么办?
运行不稳定,宕机两行泪. 作者 | 阿木 责编 | 郭芮 3月13日,大量用户反馈Google云服务器出现异常,此次异常波及大量知名产品,如Gmail.YouTube.Google Drive等,普通 ...
- Redis的KEYS命令引起RDS数据库雪崩,RDS发生两次宕机,造成几百万的资金损失
文章目录 第一次宕机 事故影响 原因分析 改进方案 第二次宕机 原因分析 改进方案 总结 Redis开发建议 1.冷热数据分离,不要将所有数据全部都放到Redis中 2.不同的业务数据要分开存储 3. ...
- Kubernetes实战指南:零宕机无缝迁移Spring Cloud至k8s
1. 项目迁移背景 1.1 为什么要在"太岁"上动土? 目前公司的测试环境.UAT环境.生产环境均已经使用k8s进行维护管理,大部分项目均已完成容器化,并且已经在线上平稳运行许久. ...
最新文章
- 太棒啦!PyCharm与Jupyter完美融合,Jupytext来啦!
- MFC动态创建控件并响应事件代码实现过程
- mysql为什么要编译安装_Mysql编译安装
- node.js 函数定义和调用
- WinSock重叠I/O模型
- IDEA启动Tomcat AJP连接器配置secretRequired=“true“,但是属性secret确实空或者空字符串,这样的组合是无效的解决办法
- 真正的mybatis_redis二级缓存
- 三类MySQL_Mysql中的三类锁,你知道吗?
- Codeforces Beta Round #71 C【KMP+DP】
- 我的MYSQL学习心得(十三) 权限管理
- JavaScript 02
- 华为星环大数据_华为和星环大数据平台关键能力对比(附报告)
- java线程的生命周期(图解)
- 一步精准获取京东商品评论数据
- 第5章第16节:案例:制作一份漂亮的翻页动画 [PowerPoint精美幻灯片实战教程]
- 移动端 touch 手机拖动 css停止问题
- Vue.js+ECharts:切换图表类型(图表工具栏)
- 硬件行业知识体系概要
- 【Linux脚本-sed命令在文本首行和尾行插入空行】
- java中JAO,Java
热门文章
- 干货 | 云智慧透视宝Java代码性能监控实现原理
- 快捷方式查看系统的配置信息 使用dxdiag
- 按头安利 好看又实用的SolidEdge 3d模型素材看这里
- 买卖二手3C成了“拆盲盒”,究竟是谁之责?
- centos漏洞系列(三):Google Android libnl权限提升漏洞
- 计算机研究生个人简历,美国计算机研究生申请个人简历这样填比模板更出众!...
- 数学三次危机(二)毕达哥拉斯学派的数学思想
- 热议:CSS为什么这么难学?一定是你的方法不对
- Fastjson小于1.2.67 UnSerializable RCE分析研究
- 全球-专线香港-大陆快速包税清关