繁体   English   中英

是什么导致我的数组地址在传递给函数时被破坏(更改)?

[英]What causes my array address to be corrupted (change) when passed to function?

我正在执行压缩稀疏原始矩阵向量乘法(CSR SPMV):这涉及将数组A分成多个,然后通过引用函数传递这个块,但是只有数组的第一部分( A[0]第一个块开始数组的开头)被修改。 然而,从第二个循环A[0 + chunkIndex] 开始,当函数读取子数组时,它会跳转并读取超出总数组地址范围的不同地址,尽管索引是正确的。

以供参考:

在此处输入图片说明


SPMV内核是:

void serial_matvec(size_t TS,  double *A, int *JA, int *IA,  double *X, double *Y)
{
    double sum;
    for (int i = 0; i < TS; ++i)
    {   
        sum = 0.0;
        for (int j = IA[i]; j < IA[i + 1]; ++j)
        {
                sum += A[j] * X[JA[j]]; // the error is here , the function reads diffrent 
                                        // address of A,  and JA, so the access 
                                       // will be out-of-bound
            }
            Y[i] = sum;
        }
    }

它被称为这样:

int chunkIndex = 0;
for(size_t k = 0; k < rows/TS; ++k)
{
    chunkIndex = IA[k * TS];
    serial_matvec(TS, &A[chunkIndex], &JA[chunkIndex], &IA[k*TS], &X[0], &Y[k*TS]);
}

假设我处理(8x8) Matrix ,并且每个块处理2 行,因此循环k将是Rows /TS = 4 loops ,传递给函数的chunkIndex和数组将如下所示:

chunkIndex: 0 --> 循环 k = 0, &A[0], &JA[0]

chunkIndex: --> loop k = 1, &A[16], &JA[16] //[此处出错,函数读取不同地址]

chunkIndex: --> loop k = 2, &A[32], &JA[32] //[此处出错,函数读取不同地址]

chunkIndex: --> loop k = 3, &A[48], &JA[48] //[此处出错,函数读取不同地址]

当我运行代码时,只有第一个块正确执行,其他 3 个块内存已损坏,数组指针跳入超出数组大小的边界。

我已经手动检查了所有参数的所有索引,它们都是正确的,但是当我打印地址时,它们不一样。 (现在调试这个 3 天)

我使用了valgrind ,它报告了:

大小 8 的无效读取使用大小 8的未初始化值总和 += A[j] * X[JA[j]]; 线

我用-g -fsanitize=address编译它,我得到了

堆缓冲区溢出

我试图在函数之外手动访问这些块,它们是正确的,那么什么会导致堆内存像这样损坏呢?

代码在这里,这是我能做的最低限度。

问题是我在索引传递给函数的数组部分chunk时使用了全局索引(main 内的索引 ,因此出现了越界问题。

解决方案是在每次函数调用时从0开始索引子数组,但我遇到了另一个问题。 在每次函数调用时,我处理TS行,每一行都有不同数量的非零。

举个例子,看图片, chunk 1 ,抱歉我的笔迹不好,这样更容易。 如您所见,我们将需要3 indices ,一个用于每个块i处理的TS行,另一个是因为每行具有不同数量的非零j ,第三个用于索引传递的子数组l ,这是原来的问题。 在此处输入图片说明

并且serial_matvec函数将如下所示:

void serial_matvec(size_t TS, const double *A, const int *JA, const int *IA,
                   const double *X, double *Y) {
  int  l = 0;
  for (int i = 0; i < TS; ++i) {
    for (int j = 0; j < (IA[i + 1] - IA[i]); ++j) {
      Y[i] += A[l] * X[JA[l]];
      l++;
    }    
  }
}

带有测试的完整代码在这里如果有人有更优雅的解决方案,我们非常欢迎您。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM