带有 const char* 的 printf 中的奇怪 SIGABRT

Strange SIGABRT in printf with const char*

你好 Stack Exchange 社区,

我有一个函数可以将 CSV 文件读入 gsl_matrix,然后 returns 指向矩阵的指针。该函数执行时没有错误,但是当在函数 returns 之后使用常量字符串执行 printf 时,程序以 SIGABRT 退出。我试过:

都没有用,但是我发现在函数调用之前放置一个 printf() 可以防止这个错误(在下面的 main() 中注释掉)。我正在 Ubuntu 16.04 上使用 gcc 5.4.0 进行编译。在此行之前调用 malloc_stats() 表明我正在使用大约 6kB 的堆。下面显示的 LLDB 输出准确说明了哪一行导致 print_matrix().

中的错误
Process 10955 stopped
* thread #1: tid = 10955, 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88, name = 'main', stop reason = step over
    frame #0: 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88
   85   static void print_matrix(gsl_matrix * matrix)
   86   {
   87     for (int i = 0; i < matrix->size1; i++) {
-> 88       printf("[");
   89       for (int j = 0; j < matrix->size2; j++) {
   90         printf("%g, ", gsl_matrix_get(matrix, i, j));
   91       }
(lldb) 
Process 10955 stopped
* thread #1: tid = 10955, 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54, name = 'main', stop reason = signal SIGABRT
    frame #0: 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54

下面显示的代码是主函数,它位于main.c:

int main(int argc, char * argv[]) {
  /* printf("This is the fix.\n"); */
  gsl_matrix * matrix2 = read_tuples_csv("data/12AX7-Data.csv", 3);
  print_matrix(matrix2);
}

以下代码是 read_tuples_csv() 函数,它位于 util.c 中。该函数采用要读取的文件路径和要解析的元组的大小。我怀疑问题出在这个函数中,但到目前为止,没有多少校对或调试能够揭示我语义中的错误。

gsl_matrix * read_tuples_csv(const char * filename, size_t n)
{
  FILE * file;
  if ((file = fopen(filename, "r")) == NULL || n <= 0)
    return NULL;

  List * list = malloc(sizeof(List));
  list_init(list, free);

  double * arr;
  while (!feof(file)) {
    arr = calloc(n, sizeof(double));
    char *line = NULL, *scratch;
    size_t n = 0;
    if (getline(&line, &n, file) == -1) goto error_exit;
    line = strtok_r(line, ",", &scratch);

    int i = 0;
    do {
      int ret = sscanf(line, "%lf", &arr[i]);
      if (ret <= 0) fprintf(stderr, "Something happened:\nline:\t%s", line);
      i++;
    } while ((line = strtok_r(NULL, ",", &scratch)) != NULL && i < n);

    free(line);
    line = NULL;
    if (list_insnxt(list, list_tail(list), arr) != 0)
      goto error_exit;
  }
  fclose(file);
  file = NULL;

  gsl_matrix * matrix = gsl_matrix_alloc(list_size(list), n);
  int i = 0;
  while (list_size(list) > 0) {
    double * vector;
    list_remnxt(list, NULL, (void **)&vector);
    for (int j = 0; j < n; j++) {
      gsl_matrix_set(matrix, i, j, vector[j]);
    }
    i++;
  }

  list_dest(list);
  free(list);

  return matrix;

 error_exit: {
    if (file != NULL) fclose(file);
    list_dest(list);
    free(arr);
    free(list);
    return NULL;
  }
}

问题可能是由于:

printf("%g, ", gsl_matrix_get(matrix, i, j));

因为您正在尝试打印一个双精度值,但您的函数返回一个 gsl_matrix 指针。

此外,printf("%s", "[")printf("%c", '[')printf("[" 更好。

感谢@SouravGhosh 和@PaulOgilvie 提供答案。问题在于我使用 feof() 作为 while 循环的开关。这是一种糟糕的做法,并且在许多情况下(包括这个)它会导致未定义的行为。为什么这会导致行

printf("[");

失败是我无法接受的。貌似是stdout的buffer overflow,但是我在失败前在stdout上调用fflush()进行了测试,并没有解决问题。如果有人能够确定问题的确切原因,我将不胜感激。还要感谢@SouravGhosh 提醒我忘记检查 calloc() 的 return 值。