- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
以下程序崩溃:
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::path p1 = "/usr/lib/sendmail.cf";
std::cout << "p1 = " << p1 << '\n';
}
汇编:
$ g++ -std=c++17 pathExistsTest.cpp
$ ./a.out
p1 = "/usr/lib/sendmail.cf"
[1] 35688 segmentation fault (core dumped) ./a.out
在 Ubuntu 20.04 上测试,编译器为 GCC 8.4.0。
==30078== by 0x4AE5034: QAbstractButton::mouseReleaseEvent(QMouseEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5.12.8)
==30078== by 0x4A312B5: QWidget::event(QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5.12.8)
==30078== Address 0x2b is not stack'd, malloc'd or (recently) free'd
==30078==
==30078==
==30078== Process terminating with default action of signal 11 (SIGSEGV)
==30078== Access not within mapped region at address 0x2B
==30078== at 0x13AD9B: std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector() (in /home/(me)/src/tomato/build-src-Desktop-Release/TomatoLauncher)
Full Output
path
变量,否
vector<path>
.
最佳答案
TL;博士
您正在使用 GCC 8.4.0 进行编译,因此您需要明确链接 -lstdc++fs
.
由于您使用的是 GCC 8.4.0,因此您使用的是 GCC 8.4.0 版的 GNU C++ 标准库,即 libstdc++ header 。但是你的系统(Ubuntu 20.04)只包含 libstdc++.so.6.0.28
来自 GCC 9。如果你没有明确链接到 -lstdc++fs
,那么你不小心吃了一个 std::filesystem
符号来自 GCC 9(通过 libstdc++.so
)而不是来自 GCC 8(通过 libstdc++fs.a
)。
GCC 8 和 GCC 9 不兼容 std::filesystem
类型。更具体地说,它们的二进制布局是不同的。这基本上是一个非常隐蔽的 ODR 违规。您的对象是为 GCC 8 布局分配的,但使用 GCC 9 布局构造。当您尝试销毁它时,析构函数使用 GCC 8 布局并崩溃,因为数据不是它所期望的。
有两段代码使用了 path
的不同且不兼容的布局。类型。
第一段代码来自 libstdc++.so.6.0.28
: 它包含 path::_M_split_cmpts()
的定义,通过内联构造函数调用 path::path(string_type&&, format)
.由于构造函数是内联的,构造函数本身的代码会生成到您的可执行文件中。因此,您的可执行文件包含对 path::_M_split_cmpts
的调用。 .
第二段代码在您自己的可执行文件中:它为内联(默认)析构函数生成指令 path::~path()
,以及它调用的内联函数;一直到std::filesystem::__cxx11::path::path<char [21], std::filesystem::__cxx11::path>(char const (&) [21], std::filesystem::__cxx11::path::path>(char const (&) [21], std::filesystem::__cxx11::path::format)
.
我们怎样才能找到这个?
使用调试器:
逐步检查 ctor 中的可疑函数会发现:
0x5569716498ed <std::filesystem::__cxx11::path::path<char [21], std::filesystem::__cxx11::path>(char const (&) [21], std::filesystem::__cxx11::path::path>(char const (&) [21], std::filesystem::__cxx11::path::format)+112> callq 0x5569716491e0 <_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv@plt>
这是通过 PLT 的调用(因此,可能来自共享对象,并且绝对不是内联的)。我们进入它并:
(gdb) bt
#0 0x00007f102c60f260 in std::filesystem::__cxx11::path::_M_split_cmpts() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00005569716498ed in std::filesystem::__cxx11::path::path<char [21], std::filesystem::__cxx11::path> (this=0x7ffe1a07ad60, __source=...)
at /usr/include/c++/8/bits/fs_path.h:185
#2 0x00005569716493fd in main () at blub.cpp:6
所以,我们可以看到它确实来自
/lib/x86_64-linux-gnu/libstdc++.so.6
,这是到
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
的符号链接(symbolic link).
==30078== Invalid read of size 8
==30078== at 0x13AD9B: std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector() (in /home/(me)/src/tomato/build-src-Desktop-Release/TomatoLauncher)
它是内联的,因此在可执行文件中。
path
的内联函数的头文件和
path::_M_split_cmpts
函数来自 GNU C++ 标准库 (libstdc++)。
libstdc++.so
?我们正在运行
libstdc++.so.6.0.28
根据
ldd
和调试器。根据
libstdc++ ABI Policy and Guidelines , 那是
海湾合作委员会 >= 9.3 .
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
的定义:
$ objdump -T /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 | grep _ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
000000000016a260 g DF .text 00000000000005f3 GLIBCXX_3.4.26 _ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
根据 ABI 文档,这是
GCC 9.1.0: GLIBCXX_3.4.26, CXXABI_1.3.12
-v
编译,我们看到链接器调用:
COLLECT_GCC_OPTIONS='-v' '-std=c++17' '-g' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/8/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper -plugin-opt=-fresolution=/tmp/cceJgWPt.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/8/../../.. /tmp/ccTNph3u.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/8/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-v' '-std=c++17' '-g' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
在那里,我们有
-L/usr/lib/gcc/x86_64-linux-gnu/8
和其他查找标准库的路径。在那里,我们找到
libstdc++.so -> ../../../x86_64-linux-gnu/libstdc++.so.6
,最后指向
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
(!!!)。
libstdc++.so
, 并且它不会从编译器 (*) 接收有关符号的任何版本信息。编译器只知道源代码,在这种情况下,源代码不包含符号版本(GCC 8.4.0 的文件系统头文件)。然而,符号版本存在于 ELF 二进制文件中
libstdc++.so
.链接器看到
GLIBCXX_3.4.26
对于编译器请求的符号
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
并对此感到满意。让你想知道是否有一个链接器开关来告诉链接器“如果我请求一个未版本化的符号,不要使用一个版本化的符号”。
filesystem
根本没有做.
libstdc++.so
。 ,然后包含旧版本和新版本。
libstdc++.so
编译的二进制文件指定它想要的符号版本,动态加载器根据匹配名称和版本的符号正确解析 undefined symbol 。请注意,动态链接器不知道要搜索哪个共享库(在 Windows/PE 上,这是不同的)。任何“符号请求”都只是一个 undefined symbol ,并且有一个完全独立的所需库列表来提供那些 undefined symbol 。但是二进制文件中没有映射哪个符号应该来自哪个库。
libstdc++.so
对于多个版本的编译器。这就是为什么你会看到到处都是符号链接(symbolic link),导致所有文件都指向同一个文件。后缀
.6.0.28
是另一种允许向后的正交版本控制方案-
不兼容 更改:您的二进制文件可以指定它需要
libstdc++.so.6
你可以添加一个不兼容的
libstdc++.so.7
对于其他二进制文件。
libstdc++.so
的纯 GCC 8 版本链接起来,你会看到
a linker error .链接共享库对二进制文件没有太大作用;然而,它确实修复了未解析符号的符号版本,并且可以在查看所有库后检查是否没有留下未解析的符号。我们可以看到你的二进制文件实际上请求了
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv@GLIBCXX_3.4.26
当您将其链接到
libstdc++.so.6.0.28
时.
libstdc++.so
的纯 GCC 8 版本运行您的库,您会收到动态链接器错误,因为它找不到
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv@GLIBCXX_3.4.26
.
libstdc++fs.a
.它还提供了
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
的定义,它不是符号链接(symbolic link),而是特定于此 GCC 版本:
/usr/lib/gcc/x86_64-linux-gnu/8/libstdc++fs.a
.
-lstdc++fs
,您可以将其符号直接包含在可执行文件中(因为它是一个静态库)。可执行文件中的符号优先于共享对象中的符号。因此,
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
来自
libstdc++fs.a
用来。
path
中的布局不兼容实际上是什么? ?
clang++ -cc1 -fdump-record-layouts
,我们可以看到左侧的偏移量,右侧的成员和类型名称:
0 | class std::filesystem::__cxx11::path
0 | class std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> > _M_pathname
0 | struct std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::_Alloc_hider _M_dataplus
0 | class std::allocator<char> (base) (empty)
0 | class __gnu_cxx::new_allocator<char> (base) (empty)
0 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::pointer _M_p
8 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::size_type _M_string_length
16 | union std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::(anonymous at /usr/include/c++/8/bits/basic_string.h:160:7)
16 | char [16] _M_local_buf
16 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::size_type _M_allocated_capacity
32 | class std::vector<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> > _M_cmpts
32 | struct std::_Vector_base<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> > (base)
32 | struct std::_Vector_base<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> >::_Vector_impl _M_impl
32 | class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> (base) (empty)
32 | class __gnu_cxx::new_allocator<struct std::filesystem::__cxx11::path::_Cmpt> (base) (empty)
32 | std::_Vector_base<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> >::pointer _M_start
40 | std::_Vector_base<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> >::pointer _M_finish
48 | std::_Vector_base<struct std::filesystem::__cxx11::path::_Cmpt, class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt> >::pointer _M_end_of_storage
56 | enum std::filesystem::__cxx11::path::_Type _M_type
| [sizeof=64, dsize=57, align=8,
| nvsize=57, nvalign=8]
海湾合作委员会 9.3.0:
0 | class std::filesystem::__cxx11::path
0 | class std::__cxx11::basic_string<char> _M_pathname
0 | struct std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::_Alloc_hider _M_dataplus
0 | class std::allocator<char> (base) (empty)
0 | class __gnu_cxx::new_allocator<char> (base) (empty)
0 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::pointer _M_p
8 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::size_type _M_string_length
16 | union std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::(anonymous at /usr/include/c++/9/bits/basic_string.h:171:7)
16 | char [16] _M_local_buf
16 | std::__cxx11::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >::size_type _M_allocated_capacity
32 | struct std::filesystem::__cxx11::path::_List _M_cmpts
32 | class std::unique_ptr<struct std::filesystem::__cxx11::path::_List::_Impl, struct std::filesystem::__cxx11::path::_List::_Impl_deleter> _M_impl
32 | class std::__uniq_ptr_impl<struct std::filesystem::__cxx11::path::_List::_Impl, struct std::filesystem::__cxx11::path::_List::_Impl_deleter> _M_t
32 | class std::tuple<struct std::filesystem::__cxx11::path::_List::_Impl *, struct std::filesystem::__cxx11::path::_List::_Impl_deleter> _M_t
32 | struct std::_Tuple_impl<0, struct std::filesystem::__cxx11::path::_List::_Impl *, struct std::filesystem::__cxx11::path::_List::_Impl_deleter> (base)
32 | struct std::_Tuple_impl<1, struct std::filesystem::__cxx11::path::_List::_Impl_deleter> (base) (empty)
32 | struct std::_Head_base<1, struct std::filesystem::__cxx11::path::_List::_Impl_deleter, true> (base) (empty)
32 | struct std::filesystem::__cxx11::path::_List::_Impl_deleter (base) (empty)
32 | struct std::_Head_base<0, struct std::filesystem::__cxx11::path::_List::_Impl *, false> (base)
32 | struct std::filesystem::__cxx11::path::_List::_Impl * _M_head_impl
| [sizeof=40, dsize=40, align=8,
| nvsize=40, nvalign=8]
区别在于
path::_M_cmpts
:
// GCC 8
class std::vector<
struct std::filesystem::__cxx11::path::_Cmpt,
class std::allocator<struct std::filesystem::__cxx11::path::_Cmpt>
> _M_cmpts
// GCC 9
struct std::filesystem::__cxx11::path::_List _M_cmpts
你也可以看到
path::_List
的结构在上面的记录转储中。它与 GCC 8 非常不兼容
vector
.
path::_M_split_cmpts
通过来自 GCC 9 的 libstdc++.so,我们在
vector
中崩溃了这个的析构函数
_M_cmpts
数据成员。
vector
更改的提交至
_List
:
commit 4f87bb8d6e8dec21a07f1fba641a78a127281349
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu Dec 13 20:33:55 2018 +0000
PR libstdc++/71044 optimize std::filesystem::path construction
This new implementation has a smaller footprint than the previous
implementation, due to replacing std::vector<_Cmpt> with a custom pimpl
type that only needs a single pointer. The _M_type enumeration is also
combined with the pimpl type, by using a tagged pointer, reducing
sizeof(path) further still.
Construction and modification of paths is now done more efficiently, by
splitting the input into a stack-based buffer of string_view objects
instead of a dynamically-allocated vector containing strings. Once the
final size is known only a single allocation is needed to reserve space
for it. The append and concat operations no longer require constructing
temporary path objects, nor re-parsing the entire native pathname.
This results in algorithmic improvements to path construction, and
working with large paths is much faster.
关于c++ - 当 filesystem::path 被破坏时程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63902528/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!