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;
}
}
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
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().