奇怪的Clang行为
Strange Clang behaviour
看一下这段代码:
#include <iostream>
#include <string>
void foo(int(*f)()) {
std::cout << f() << std::endl;
}
void foo(std::string(*f)()) {
std::string s = f();
std::cout << s << std::endl;
}
int main() {
auto bar = [] () -> std::string {
return std::string("bla");
};
foo(bar);
return 0;
}
用
编译g++ -o test test.cpp -std=c++11
导致:
bla
就像它应该做的那样。用
编译它clang++ -o test test.cpp -std=c++11 -stdlib=libc++
导致:
zsh: illegal hardware instruction ./test
和用
编译clang++ -o test test.cpp -std=c++11 -stdlib=stdlibc++
也导致:
zsh: illegal hardware instruction ./test
叮当声/GCC版本:
clang version 3.2 (tags/RELEASE_32/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
gcc version 4.7.2 (Gentoo 4.7.2-r1 p1.5, pie-0.5.5)
有谁能告诉我出了什么问题吗?
提前感谢!
是的,这是clang++中的一个bug。我可以在i386-pc-linux-gnu中使用CLang 3.2复制它。
现在是一些随机分析…
我发现这个错误是在从labmda到指针到函数的转换中:编译器创建了一种具有适当签名的thunk,它调用lambda,但它的指令是ud2
而不是ret
。
指令ud2
,你可能都知道,是一个显式引发"无效操作码"异常的指令。也就是说,一条指令故意没有定义。
看一下反汇编:这是一个笨重的函数:
main::$_0::__invoke():
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
movl %ecx, 4(%esp)
calll main::$_0::operator()() const ; this calls to the real lambda
subl $4, %esp
ud2 ; <<<-- What the...!!!
所以这个错误的一个最小的例子将是简单的:
int main() {
std::string(*f)() = [] () -> std::string {
return "bla";
};
f();
return 0;
}
奇怪的是,如果返回类型是简单类型,例如int
,则不会发生该错误。那么生成的为:
main::$_0::__invoke():
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl %eax, (%esp)
calll main::$_0::operator()() const
addl $8, %esp
popl %ebp
ret
我怀疑问题在返回值的转发上。如果它适合寄存器,如eax
,一切顺利。但是如果它是一个大结构体,比如std::string
,它在堆栈中返回,编译器会感到困惑,并在绝望中发出ud2
。
这很可能是clang 3.2中的一个bug。我不能用clang trunk重现崩溃
相关文章:
- 嵌套类中 g++ 和 clang++ 之间的不同行为
- 启用优化的 g++ 和 clang++ 的奇怪行为
- 带有 gcc 和 clang 的可变参数宏扩展的奇怪行为
- G++ 和 CLang++ 在模板类中定义了朋友模板函数的不同行为
- 继承 C++14 中的模板化运算符 =:g++ 和 clang++ 的不同行为
- Visual Studio 和 Clang 不同的行为模板元编程
- Clang格式对齐连续声明奇怪的行为
- 原始数组和 std::array 在 clang++ 和 VC++ 上的不同迭代器行为
- MSVC 和 clang for if constexpr 分支的不同行为
- G 和Clang 不同的行为,指向Variadic模板功能的指针
- const成员初始化之前的用法是GCC和Clang的这种预期行为
- g++和clang++在结构/类专门化中具有非类型参数的不同行为
- Clang 无法检测到未定义的行为
- Clang如何设法将其用未定义的行为编译到此计算机代码中
- GCC 和 Clang 在 constexpr 构造函数上的不同行为
- 使用C 11的clang分类具有模棱两可的编译器行为
- __has_trivial_copy在clang和gcc中的行为不同.谁'是吗
- GCC和clang(SFINAE)之间的过载解决行为差异
- g++和clang++在SFINAE和SFINAE失效时的不同行为
- 构造函数、初始化器列表以及g++和clang中的不同行为