如果我增加条目数,由 memmove 引起的分段错误

segmentation error caused by memmove if I increase number of entries

下午好,如果我将 nx、ny 和 nz 推到某个阈值(例如 100)以上,我会收到以下错误。

Primary job terminated normally, but 1 process returned a non-zero exit code. 
Per user-direction, the job has been aborted.
mpiexec noticed that process rank 0 with PID 0 on node debian exited on signal 11 (Segmentation fault).

如果我保持在阈值以下,一切正常。

产生错误的代码在以下函数中:

void dealiasing(int nx, int ny, int nz, int nxd, int nzd, FFT_SCALAR *U) {

int nz_left = 1+ (nz-1)/2 ;
int i, stride_y, stride_z, reader=0, last_index;
for ( stride_z = 0; stride_z < nz_left*ny*nxd*2; stride_z = stride_z + ny*nxd*2) {
    for ( stride_y = 0; stride_y < ny*nxd*2; stride_y = stride_y + nxd*2) {
        for ( i = 0; i < (nx)*2; i++) {
            U[reader] = U[stride_z + stride_y+i];
            reader++;
        }
    }
    last_index = stride_z + stride_y;
}

for ( stride_z = (nzd - nz_left+1)*nxd*ny*2; stride_z < nzd*ny*nxd*2; stride_z = stride_z + ny*nxd*2) {
    for ( stride_y = 0; stride_y < ny*nxd*2; stride_y = stride_y + nxd*2) { 
        for ( i = 0; i < (nx)*2; i++) {
            U[reader] = U[stride_z + stride_y+i];
            reader++;
        }
    }
    last_index = stride_z + stride_y;
}


//Save positive modes
double U_pos[2*nx*ny*(1+(nz-1)/2)];
memmove(U_pos, U, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2)); 
memmove(U, &U[2*nx*ny*(1+(nz-1)/2)], sizeof(FFT_SCALAR)*2*nx*ny*((nz-1)/2));
memmove(&U[2*nx*ny*((nz-1)/2)], U_pos, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2));

特别是如果我关闭该函数的最后 4 行代码也适用于高于 100 的 nx、ny、nz。 这些行的目的是移动 U 条目,使结束值块重新映射为起始值块,反之亦然。 FFT_SCALAR 就像双倍。

函数在一系列MPI_Gatherv和MPI_Barrier之后被调用,包含在块

// Alloc memory for the global output
nfast=nxd;  nmid=ny; nslow=nzd;
FFT_SCALAR *UU, *UV, *VV, *VW, *WW, *UW;
UU = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
UV = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
VV = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
VW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
WW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
UW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));

// Gather all data on rank 0
MPI_Gatherv( u, receive[rank], MPI_DOUBLE, U, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")

MPI_Gatherv( uu, receive[rank], MPI_DOUBLE, UU, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( uv, receive[rank], MPI_DOUBLE, UV, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( vv, receive[rank], MPI_DOUBLE, VV, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( vw, receive[rank], MPI_DOUBLE, VW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( ww, receive[rank], MPI_DOUBLE, WW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( uw, receive[rank], MPI_DOUBLE, UW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")


 /**************************************** Dealias and Transpose dataset ****************************************/
 if (rank == 0) {
  dealiasing( nx, ny, nz, nxd, nzd, U);

  dealiasing( nx, ny, nz, nxd, nzd, UU);
  dealiasing( nx, ny, nz, nxd, nzd, UV);
  dealiasing( nx, ny, nz, nxd, nzd, VV);
  dealiasing( nx, ny, nz, nxd, nzd, VW);
  dealiasing( nx, ny, nz, nxd, nzd, WW);
  dealiasing( nx, ny, nz, nxd, nzd, UW);
}

如果我将这些重写为行:

double U_pos[2*nx*ny*(1+(nz-1)/2)];
memmove(U_pos, U, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2)); 

#define SOME_SIZE (2*nx*ny*(1+(nz-1)/2))

double U_pos[SOME_SIZE];
memmove(U_pos, U, sizeof(FFT_SCALAR)*SOME_SIZE);

您似乎覆盖了内存 - 除非 sizeof(FFT_SCALAR) 为 1 - 因为您将更多字节移入 U_pos,超出了它的容量。

另一个问题可能是 U_pos 是一个 VLA,(在大多数实现中)将分配在堆栈上。随着 nxnynz 变大,U_pos 数组变得非常大,您可能会出现堆栈溢出。