mscnvrsy mscnvrsy - 3 months ago 16
C Question

GCC Optimization: Error caused by fgets

I compiled code on my Mac with the GCC Optimization Flag

-O3
on to accelerate the execution time. This perfectly worked on my local machine and lead to a speed increase by 2/3.

However, I tried to compile the code on the Amazon EC2, since I am dealing with a large dataset. Using the
-O3
optimization flag causes the following warning


warning: call to ‘__fgets_chk_warn’ declared with attribute warning:
fgets called with bigger size than length of destination buffer


In the respective function, a text file is parsed line by line. However, I do not really understand why I end up with the warning. The code of the function reads as follows:

int loadPriceData(const char *filename, double *target) {
char line[40];
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL) {
return -1;
}
int i = 0;
while (fgets(line, 80, fp) != NULL) {
sscanf(line, "%lf\n", target + i);
i += 1;
}
fclose(fp);
return i; // Return number of elements
}


target
is a pointer to an array with
10000
elements by default. The number of entries is not known in advance, but returned by the function.

Answer

You are indeed calling fgets(line, 80, fp), but the destination array line is defined as an array of 40 char. The compiler on the Amazon EC2 is better configured or smarter than yours. This is a real bug if the file contains lines longer than 39 bytes.

Incidentally, the compiler invoked as gcc on the Mac is usually an instance of clang. Try gcc --version.

Note that your program does not check if too much data is read, nor if the sscanf() conversion succeeds. Both lead to undefined behavior.

Here is a safer version:

int loadPriceData(const char *filename, double *target, int nb_items) {
    char line[80];
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        return -1;
    }
    int i = 0;
    while (fgets(line, sizeof line, fp) != NULL) {
        if (i < nb_items) {
            if (sscanf(line, "%lf\n", target + i) != 1)
                target[i] = 0;
        }
        i += 1;
    }
    fclose(fp);
    return i; // Return number of elements
}