【发布时间】:2018-03-06 09:58:35
【问题描述】:
我试图了解 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 时,程序完成时没有错误。
我的第一个想法是,也许 GCC 的金丝雀正在捕获 Clang 没有的缓冲区溢出。所以我添加了额外的调试标志
set(CMAKE_CXX_FLAGS_DEBUG "-g -fstack-protector-all")
但是 Clang 仍然编译了一个运行没有错误的程序。对我来说,这表明问题可能不是缓冲区溢出(正如您通常看到的堆栈粉碎错误),而是分配问题。
无论如何,当我添加 ASAN 标志时:
set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address")
两个编译器都会生成一个程序,该程序会因相同的错误而崩溃。具体来说,
GCC 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)
Clang 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,clang 不会产生错误,但 GCC 会产生错误
-
你为什么要分配
15,392,894,357,504字节? (除非您期望“非常大的矩阵”为 15Tb。)当您在 gdb 下运行 asan 版本时,什么请求分配?