c++ - 段错误 'gsl_spmatrix_add'

标签 c++ segmentation-fault gsl

编辑: 我已将问题更改为产生相同错误的新代码,并且这样做更可靠。

一段时间以来,我一直在努力寻找代码中的段错误,并将其归结为以下代码:

#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 文件编译并运行 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然后运行时,不会生成核心文件。我尝试研究这个,但我似乎找不到它在任何地方生成,我不知道为什么。

最佳答案

看起来像是 GSL 中的一个错误。请报告:-)

线路

gsl_spmatrix *total_matrix = gsl_spmatrix_alloc_nzmax(size, size, nzmax, GSL_SPMATRIX_CRS);

是 GSL 稀疏矩阵的有效分配器。然而,它的初始化是“智能”的,因为它的一些内存缓冲区被malloc分配,但没有初始化。这是指成员pinit_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_matrixtotal_copy 有 5 行,但实际上没有。然而,到目前为止,代码没有错误,因为将垃圾复制到垃圾上并没有错误。

代码中的下一步:

gsl_spmatrix_add(total_matrix, total_copy, thread_matrices[i]);

调用与成员p相关的代码:

      for (j = 0; j < outer_size; ++j)
        {
          Cp[j] = nz;

这会打开一个循环,在您的情况下将执行 5 次。这里CpC->p的简写。因此,迄今为止初始化的 p 成员的唯一元素是 C = A + BC 的第 j 个元素。接下来,在这个循环中我们可以看到:

          /* 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 矩阵的“kosher”方式(第 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,但不是零填充的源代码。

希望这有帮助。

PS。 您可以删除这个完全不必要的调用 gsl_spmatrix_memcpy(total_copy,total_matrix);

关于c++ - 段错误 'gsl_spmatrix_add',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71385975/

相关文章:

c++ - 将 char 类型转换为 int 以用作 vector C++ 的索引

c - strcpy 从一个 struct char* 到另一个 struct char* - 段错误

c++ - 常量内存符号作为类的静态属性

c++ - 获取R数据帧的内存地址

C 段错误 11

c++ - 简单 wxWidgets 应用程序退出时出现段错误(每当使用文本控件时)

python - 在 Windows、OSX 和 LINUX 中安装 GSL

c++ - 在 Ubuntu 上使用 Eclipse C++ 时的 makefile 问题

c - Julia:调用 GSL 函数

c++ - 图的邻接列表表示不正确