GCC vs Clang 中的堆栈粉碎(可能是由于金丝雀)
Stack Smashing in GCC vs Clang (Possibly due to canaries)
我试图了解 GCC 中"stack smashing"
错误的可能来源,但不是 Clang。
具体来说,当我只用调试符号编译一段代码时
set(CMAKE_CXX_FLAGS_DEBUG "-g")
并使用 GCC C++编译器 (GNU 5.4.0),应用程序崩溃
*** stack smashing detected ***: ./testprogram terminated
Aborted (core dumped)
但是,当我使用 Clang 3.8.0 时,程序完成没有错误。
我的第一个想法是,也许海湾合作委员会的金丝雀正在捕捉到一个缓冲区溢出,而Clang没有。所以我添加了额外的调试标志
set(CMAKE_CXX_FLAGS_DEBUG "-g -fstack-protector-all")
但是Clang仍然编译了一个运行没有错误的程序。对我来说,这表明问题可能不是缓冲区溢出(正如您经常看到的堆栈粉碎错误),而是分配问题。
无论如何,当我添加 ASAN 标志时:
set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address")
两个编译器都会生成一个程序,该程序因相同的错误而崩溃。具体说来
海湾合作委员会 5.4.0:
==1143==ERROR: AddressSanitizer failed to allocate 0xdfff0001000 (15392894357504) bytes at address 2008fff7000 (errno: 12)
==1143==ReserveShadowMemoryRange failed while trying to map 0xdfff0001000 bytes. Perhaps you're using ulimit -v
Aborted (core dumped)
叮当 3.8.0:
==1387==ERROR: AddressSanitizer failed to allocate 0xdfff0001000 (15392894357504) bytes at address 2008fff7000 (errno: 12)
==1387==ReserveShadowMemoryRange failed while trying to map 0xdfff0001000 bytes. Perhaps you're using ulimit -v
Aborted (core dumped)
有人可以给我一些关于此错误可能来源的提示吗?我很难追踪发生这种情况的行,因为它在一个非常大的代码库中。
编辑
此问题尚未解决,但已隔离到以下功能:
void get_sparsity(Data & data) {
T x[n_vars] = {};
T g[n_constraints] = {};
for (Index j = 0; j < n_vars; j++) {
const T x_j = x[j];
x[j] = NAN;
eval_g(n_vars, x, TRUE, n_constraints, g, &data);
x[j] = x_j;
std::vector<Index> nonzero_entries;
for (Index i = 0; i < n_constraints; i++) {
if (isnan(g[i])) {
data.flattened_nonzero_rows.push_back(i);
data.flattened_nonzero_cols.push_back(j);
nonzero_entries.push_back(i);
}
}
data.nonzeros.push_back(nonzero_entries);
}
int internal_debug_point = 5;
}
叫这样称呼:
get_sparsity(data);
int external_debug_point= 6;
但是,当我在get_sparsity
函数的最后一行internal_debug_point = 5
上放置调试点时,它会毫无问题地到达该行。但是,当退出函数时,在它到达外部调试点之前external_debug_point = 6
,它会崩溃并显示错误
received signal SIGABRT, Aborted.
0x00007ffffe315428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
我的猜测是GCC仅在退出该函数时检查金丝雀,因此错误实际上发生在函数内部。这听起来合理吗?如果是这样,那么有没有办法让 GCC 或 clang 进行更频繁的金丝雀检查?
我怀疑 ASan 内存不足。
我不认为 ASan 错误意味着您的程序正在尝试分配该内存,而是意味着 ASan 正在尝试为自己分配该内存(它说"影子内存",这是 ASan 用来跟踪您的程序分配的内存)。
如果迭代次数(和数组大小)n_vars
很大,则该函数将在每个循环中使用额外的内存用于新std::vector
,从而迫使 ASan 跟踪越来越多的内存。
您可以尝试将局部向量移出循环(无论如何,这可能会提高函数的性能):
std::vector<Index> nonzero_entries;
for (Index j = 0; j < n_vars; j++) {
// ...
for (Index i = 0; i < n_constraints; i++) {
if (isnan(g[i])) {
data.flattened_nonzero_rows.push_back(i);
data.flattened_nonzero_cols.push_back(j);
nonzero_entries.push_back(i);
}
}
data.nonzeros.push_back(nonzero_entries);
nonzero_entries.clear();
}
这将重用相同的内存进行nonzero_entries
,而不是每次迭代都为新向量分配和去涂层内存。
试图找出堆栈问题的根源一无所获。所以我尝试了另一种方法。通过调试,我缩小了上述函数的范围,get_sparsity
是罪魁祸首。调试器没有给我任何提示问题的确切位置,但它在该函数中的某个地方。有了这些信息,我将该函数中仅有的两个堆栈变量切换为堆变量x
和g
,以便 valgrind 可以帮助我找到错误(sgcheck 显示为空)。具体来说,我将上面的代码修改为
void get_sparsity(Data & data) {
std::vector<T> x(n_vars, 0);
std::vector<T> g(n_constraints, 0);
/* However, for our purposes, it is easier to make an std::vector of Eigen
* vectors, where the ith entry of "nonzero_entries" contains a vector of
* indices in g for which g(indices) are nonzero when perturbing x(i).
* If that sounds complicated, just look at the code and compare to
* the code where we use the sparsity structure.
*/
for (Index j = 0; j < n_vars; j++) {
const T x_j = x[j];
x[j] = NAN;
Bool val = eval_g(n_vars, x.data(), TRUE, n_constraints, g.data(), &data);
x[j] = x_j;
std::vector<Index> nonzero_entries;
for (Index i = 0; i < n_constraints; i++) {
if (isnan(g[i])) {
data.flattened_nonzero_rows.push_back(i);
data.flattened_nonzero_cols.push_back(j);
nonzero_entries.push_back(i);
}
}
data.nonzeros.push_back(nonzero_entries);
}
int bob = 5;
return;
}
然后valgrind
编辑它以找到违规行。现在我知道问题发生在哪里,我可以解决问题了。
- 奇怪的结构&GCC&clang(void*返回类型)
- 数据成员SFINAE的C++17测试:gcc vs clang
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- Clang bug?使用指针作为模板参数
- clang整洁10忽略了我的NOLINT命令
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在clang++预处理器中确定gcc工具链版本
- 为什么 Clang 不允许"and"作为函数名称?
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- clang格式:宏的缩进
- CLANG 编译器 说:变量"PTR"可能未初始化
- clang格式:禁用排序包含
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 循环展开 - G++ 与 Clang++
- 如何使用Clang/GCC在Mac上为C/C++设置VSCode
- 一位朋友将模板函数缩写为clang和gcc
- GCC vs Clang 中的堆栈粉碎(可能是由于金丝雀)