分段错误 'gsl_spmatrix_add'
segmentation fault 'gsl_spmatrix_add'
编辑:
我已将问题更改为产生相同错误的新代码,并且这样做更可靠。
一段时间以来,我一直在努力寻找代码中的分段错误,并将其归结为以下代码:
#include <gsl/gsl_spmatrix.h>
#include <iostream>
using namespace std;
void test_gsl() {
size_t size = 5;
size_t nzmax = 5 * 5;
constexpr size_t threads = 5;
// allocate
gsl_spmatrix* thread_matrices[threads];
for (size_t thread = 0; thread < threads; thread++) {
thread_matrices[thread] = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_TRIPLET);
}
// set
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix_set(thread_matrices[i], 0, 0, 1.0);
}
// crs
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix* temp = thread_matrices[i];
thread_matrices[i] = gsl_spmatrix_crs(thread_matrices[i]);
gsl_spmatrix_free(temp);
}
// add to total
gsl_spmatrix* total_matrix = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
gsl_spmatrix* total_copy = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix_memcpy(total_copy, total_matrix); // this is required to avoid another segfault
gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]); // unknown segfault!
}
gsl_spmatrix_free(total_matrix);
gsl_spmatrix_free(total_copy);
}
int main(int argc, char* argv[]) {
test_gsl();
printf("end\n");
return 0;
}
当我 运行 时,我始终得到以下输出:
Segmentation fault (core dumped)
分段错误在 gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]);
线上。
我正在使用 cmake 编译此代码:
cmake_minimum_required(VERSION 3.22.1)
project(diskmodel)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
add_subdirectory("src")
project(galaxy)
find_package(GSL REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}" SUFFIX ".exe")
target_link_libraries(${PROJECT_NAME} GSL::gsl GSL::gslcblas )
是什么导致了这个段错误?
编辑:
编译后:
g++ 'gsl-config --libs' main.cpp -fsanitize=undefined -g
我得到了和以前一样的输出。使用 address
编译时,我得到:
=================================================================
==31330==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 400 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64a06 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:153
#1 0x7efd449d393e in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f893e)
Indirect leak of 240 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d3b6c in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f8b6c)
Indirect leak of 200 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d3b88 in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f8b88)
Indirect leak of 40 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d39ac in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f89ac)
Indirect leak of 40 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d397d in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f897d)
当使用我的 cmake 文件和 运行ning gdb galaxy.exe
编译时,我得到以下回溯:
#0 0x00007ffff7f2c185 in gsl_spblas_scatter () from /lib/x86_64-linux-gnu/libgsl.so.23
#1 0x00007ffff7f2b364 in gsl_spmatrix_add () from /lib/x86_64-linux-gnu/libgsl.so.23
#2 0x00005555555553d2 in test_gsl () at .../src/main.cpp:35
#3 0x0000555555555420 in main (argc=1, argv=0x7fffffffdaf8) at .../src/main.cpp:44
并且在使用 -p
时没有历史记录。
当使用 ulimit -c unlimited
然后 运行ning 时,不会生成核心文件。我试着调查了一下,但我似乎无法在任何地方找到它生成,我也不知道为什么。
看起来像是 GSL 中的错误。请报告:-)
行
gsl_spmatrix *total_matrix = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
是 GSL 稀疏矩阵的有效分配器。然而,它的初始化是“智能”的,因为它的一些内存缓冲区是 malloc
ed,但没有初始化。这是指成员p
。
init_source.c
的第 130 行(来自 GSL 源,子模块(目录)spmatrix
):
m->p = malloc((n1 + 1) * sizeof(int));
您的代码接下来要做的是
gsl_spmatrix_memcpy(total_copy, total_matrix); // this is required to avoid another segfault
嗯,评论有点耐人寻味,但让我们看一下代码(copy_source.c
的第 93-96 行):
for (n = 0; n < src->size1 + 1; ++n)
{
dest->p[n] = src->p[n];
}
这里,size1
好像是矩阵的行数,声明为5。所以,代码用垃圾替换(通过复制)垃圾。这告诉我们,如果声明为具有 5 行的矩阵具有少于 5 个非零行,则 GSL 似乎无法正常工作。我相信这是您问题的解决方案。您声明了一些矩阵,例如total_matrix
和 total_copy
有 5 行,但它们实际上有 none。然而,到目前为止代码没有错误,因为将垃圾复制到垃圾上是没有错误的。
代码中的下一步:
gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]);
调用与成员相关的代码p
:
for (j = 0; j < outer_size; ++j)
{
Cp[j] = nz;
这将打开一个循环,在您的例子中将执行 5 次。这里 Cp
是 C->p
的 shorthand。到目前为止,p
成员中唯一被初始化的元素是 C = A + B
中 C
的 j-th 之一。接下来,在这个循环中我们可以看到:
/* CSC: x += A(:,j); CSR: x += A(j,:) */
nz = FUNCTION (spmatrix, scatter) (a, j, w, x, (int) (j + 1), c, nz);
注意 j
作为第二个参数传递,并且未完全初始化 a
作为第一个参数。这会通过宏调用第 538 行中定义的 spmatrix_scatter
。
static size_t
FUNCTION (spmatrix, scatter) (const TYPE (gsl_spmatrix) * A, const size_t j, int * w,
ATOMIC * x, const int mark, TYPE (gsl_spmatrix) * C, size_t nz)
{
int p;
int * Ai = A->i;
int * Ap = A->p;
ATOMIC * Ad = A->data;
int * Ci = C->i;
for (p = Ap[j]; p < Ap[j + 1]; ++p)
{
现在,可以看出,GSL 访问了 Ap[j]
和 Ap[j + 1]
的未初始化值。这会在几条指令后立即导致段错误。
现在,如何避免这种情况?
让我们看看创建 CSR 矩阵的“犹太洁食”方法(第 152-156 行,compress_source.c
):
Cp = dest->p;
/* initialize row pointers to 0 */
for (n = 0; n < dest->size1 + 1; ++n)
Cp[n] = 0;
万岁!这是 p
成员的正确初始化。顺带一提,后面几行说明了CRS表示中的p
成员是用来存储每一行元素的个数的。这似乎是 gsl_spmatrix_alloc_nzmax
中缺少的代码。
结论:不要依赖 gsl_spmatrix_alloc_nzmax
返回的矩阵。它们应该可以用作“目标矩阵”,例如作为 C = A + B
中的 C
,但不是 zero-filled 来源。
希望对您有所帮助。
PS。
您可以删除完全不必要的 gsl_spmatrix_memcpy(total_copy, total_matrix);
调用
编辑: 我已将问题更改为产生相同错误的新代码,并且这样做更可靠。
一段时间以来,我一直在努力寻找代码中的分段错误,并将其归结为以下代码:
#include <gsl/gsl_spmatrix.h>
#include <iostream>
using namespace std;
void test_gsl() {
size_t size = 5;
size_t nzmax = 5 * 5;
constexpr size_t threads = 5;
// allocate
gsl_spmatrix* thread_matrices[threads];
for (size_t thread = 0; thread < threads; thread++) {
thread_matrices[thread] = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_TRIPLET);
}
// set
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix_set(thread_matrices[i], 0, 0, 1.0);
}
// crs
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix* temp = thread_matrices[i];
thread_matrices[i] = gsl_spmatrix_crs(thread_matrices[i]);
gsl_spmatrix_free(temp);
}
// add to total
gsl_spmatrix* total_matrix = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
gsl_spmatrix* total_copy = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
for (size_t i = 0; i < threads; i++) {
gsl_spmatrix_memcpy(total_copy, total_matrix); // this is required to avoid another segfault
gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]); // unknown segfault!
}
gsl_spmatrix_free(total_matrix);
gsl_spmatrix_free(total_copy);
}
int main(int argc, char* argv[]) {
test_gsl();
printf("end\n");
return 0;
}
当我 运行 时,我始终得到以下输出:
Segmentation fault (core dumped)
分段错误在 gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]);
线上。
我正在使用 cmake 编译此代码:
cmake_minimum_required(VERSION 3.22.1)
project(diskmodel)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
add_subdirectory("src")
project(galaxy)
find_package(GSL REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}" SUFFIX ".exe")
target_link_libraries(${PROJECT_NAME} GSL::gsl GSL::gslcblas )
是什么导致了这个段错误?
编辑:
编译后:
g++ 'gsl-config --libs' main.cpp -fsanitize=undefined -g
我得到了和以前一样的输出。使用 address
编译时,我得到:
=================================================================
==31330==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 400 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64a06 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:153
#1 0x7efd449d393e in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f893e)
Indirect leak of 240 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d3b6c in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f8b6c)
Indirect leak of 200 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d3b88 in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f8b88)
Indirect leak of 40 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d39ac in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f89ac)
Indirect leak of 40 byte(s) in 5 object(s) allocated from:
#0 0x7efd44b64808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7efd449d397d in gsl_spmatrix_alloc_nzmax (/lib/x86_64-linux-gnu/libgsl.so.23+0x1f897d)
当使用我的 cmake 文件和 运行ning gdb galaxy.exe
编译时,我得到以下回溯:
#0 0x00007ffff7f2c185 in gsl_spblas_scatter () from /lib/x86_64-linux-gnu/libgsl.so.23
#1 0x00007ffff7f2b364 in gsl_spmatrix_add () from /lib/x86_64-linux-gnu/libgsl.so.23
#2 0x00005555555553d2 in test_gsl () at .../src/main.cpp:35
#3 0x0000555555555420 in main (argc=1, argv=0x7fffffffdaf8) at .../src/main.cpp:44
并且在使用 -p
时没有历史记录。
当使用 ulimit -c unlimited
然后 运行ning 时,不会生成核心文件。我试着调查了一下,但我似乎无法在任何地方找到它生成,我也不知道为什么。
看起来像是 GSL 中的错误。请报告:-)
行
gsl_spmatrix *total_matrix = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);
是 GSL 稀疏矩阵的有效分配器。然而,它的初始化是“智能”的,因为它的一些内存缓冲区是 malloc
ed,但没有初始化。这是指成员p
。
init_source.c
的第 130 行(来自 GSL 源,子模块(目录)spmatrix
):
m->p = malloc((n1 + 1) * sizeof(int));
您的代码接下来要做的是
gsl_spmatrix_memcpy(total_copy, total_matrix); // this is required to avoid another segfault
嗯,评论有点耐人寻味,但让我们看一下代码(copy_source.c
的第 93-96 行):
for (n = 0; n < src->size1 + 1; ++n)
{
dest->p[n] = src->p[n];
}
这里,size1
好像是矩阵的行数,声明为5。所以,代码用垃圾替换(通过复制)垃圾。这告诉我们,如果声明为具有 5 行的矩阵具有少于 5 个非零行,则 GSL 似乎无法正常工作。我相信这是您问题的解决方案。您声明了一些矩阵,例如total_matrix
和 total_copy
有 5 行,但它们实际上有 none。然而,到目前为止代码没有错误,因为将垃圾复制到垃圾上是没有错误的。
代码中的下一步:
gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]);
调用与成员相关的代码p
:
for (j = 0; j < outer_size; ++j)
{
Cp[j] = nz;
这将打开一个循环,在您的例子中将执行 5 次。这里 Cp
是 C->p
的 shorthand。到目前为止,p
成员中唯一被初始化的元素是 C = A + B
中 C
的 j-th 之一。接下来,在这个循环中我们可以看到:
/* CSC: x += A(:,j); CSR: x += A(j,:) */
nz = FUNCTION (spmatrix, scatter) (a, j, w, x, (int) (j + 1), c, nz);
注意 j
作为第二个参数传递,并且未完全初始化 a
作为第一个参数。这会通过宏调用第 538 行中定义的 spmatrix_scatter
。
static size_t
FUNCTION (spmatrix, scatter) (const TYPE (gsl_spmatrix) * A, const size_t j, int * w,
ATOMIC * x, const int mark, TYPE (gsl_spmatrix) * C, size_t nz)
{
int p;
int * Ai = A->i;
int * Ap = A->p;
ATOMIC * Ad = A->data;
int * Ci = C->i;
for (p = Ap[j]; p < Ap[j + 1]; ++p)
{
现在,可以看出,GSL 访问了 Ap[j]
和 Ap[j + 1]
的未初始化值。这会在几条指令后立即导致段错误。
现在,如何避免这种情况?
让我们看看创建 CSR 矩阵的“犹太洁食”方法(第 152-156 行,compress_source.c
):
Cp = dest->p;
/* initialize row pointers to 0 */
for (n = 0; n < dest->size1 + 1; ++n)
Cp[n] = 0;
万岁!这是 p
成员的正确初始化。顺带一提,后面几行说明了CRS表示中的p
成员是用来存储每一行元素的个数的。这似乎是 gsl_spmatrix_alloc_nzmax
中缺少的代码。
结论:不要依赖 gsl_spmatrix_alloc_nzmax
返回的矩阵。它们应该可以用作“目标矩阵”,例如作为 C = A + B
中的 C
,但不是 zero-filled 来源。
希望对您有所帮助。
PS。
您可以删除完全不必要的 gsl_spmatrix_memcpy(total_copy, total_matrix);