Strange SIGABRT in printf with const char*

709 Views Asked by At

Hello Stack Exchange community,

I have a function that reads a CSV file into a gsl_matrix and then returns a pointer to the matrix. The function executes without error, however the program exits with SIGABRT when executing printf with a constant string after the function returns. I've tried:

  • Changing the string that is printed
  • Abstracting the string to be a format followed by a char

Neither worked, however I discovered that placing a printf() before the call of the function prevents this error (commented out in main() below). I'm compiling with gcc 5.4.0 on Ubuntu 16.04. Calling malloc_stats() before this line shows that I'm using approximately 6kB of the heap. The LLDB output shown below illustrates exactly which line causes the error in 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

The code shown below is the main function, which resides in 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);
}

The following code is the function read_tuples_csv(), which resides in util.c. The function takes the path of the file to read and the size of the tuples to parse. I suspect that the problem is in this function, but no amount of proofreading or debugging has been able to reveal the error in my semantics thus far.

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;
  }
}
2

There are 2 best solutions below

0
On BEST ANSWER

Thanks to @SouravGhosh and @PaulOgilvie for providing the answer. The problem lay in my use of feof() as a switch for the while loop. This is poor practice, and in many cases (this one included) it caused undefined behavior. Why this would cause the line

printf("[");

To fail is beyond me. It appears to be a buffer overflow of stdout, but I tested this by calling fflush() on stdout before the failure, and the problem was not remedied. If anyone is able to identify the exact cause of the problem, I would appreciate it. Also thanks to @SouravGhosh for reminding me that I forgot to check the return value of calloc().

1
On

The problem could be due to:

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

Because you are trying to printf a double but your function is returning a gsl_matrix pointer.

Also it's considered better form to printf("%s", "[") or printf("%c", '[') rather than printf("[").