Skip to main content
GitHub

FIO17-C. Do not rely on an ending null character when using fread()

The fread() function, as defined in the C Standard, subclause 7.21.8.1 [ ISO/IEC 9899:2011 ], does not explicitly null-terminate the read character sequence.

Synopsis
size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream)

Description
The fread function reads, into the array pointed to by ptr , up to nmemb elements
whose size is specified by size , from the stream pointed to by stream .

Although the content of a file has a properly null-terminated character sequence, if nmemb is less than the total length of the characters, the fread() function will not read after nmemb characters. fread() will not append a null character to the end of the string being read to.

Noncompliant Code Example

Suppose we have a null-terminated character sequence in a file, and we need to extract a null-terminated byte string:

Non-compliant code
#include <stdio.h>
#include <stdlib.h>

int main (void) {

    FILE *fp;
    size_t size;
    long length;
    char *buffer;

    fp = fopen("file.txt", "rb");

    if (fp == NULL) {
      /* Handle file open error */
    }

    /* Obtain file size */
    if (fseek(fp, 0, SEEK_END) != 0) {
      /* Handle repositioning error */
    }

    length = ftell(fp);

    if (fseek(fp, 0L, SEEK_SET) != 0) {
      /* Handle repositioning error */
    }

    /* Allocate memory to contain whole file */
    buffer = (char*) malloc(length);
    if (buffer == NULL) {
      /* Handle memory allocation error */
    }
    
    /* size assigned here in some other code */

    if (fread(buffer, 1, size, fp) < size) {
      /* Handle file read error */
    }
    fclose(fp);

    return 0;
}

When size is less than the total length of the file ( file.txt ), buffer is not properly null-terminated.

Compliant Solution

To correct this example, the size of buffer must be compared with the total length of the file to identify the erroneous case where size differs from length . At this point, it is up to the programmer to handle this case.

Compliant code
#include <stdio.h>
#include <stdlib.h>

int main (void) {

    FILE *fp;
    size_t size;
    long length;
    char *buffer;

    fp = fopen("file.txt", "rb");

    if (fp == NULL) {
      /* Handle file open error */
    }

    /* Obtain file size */
    if (fseek(fp, 0, SEEK_END) != 0) {
      /* Handle repositioning error */
    }
    length = ftell(fp);

    if (fseek(fp, 0L, SEEK_SET) != 0) {
      /* Handle repositioning error */
    }

    /* Allocate memory to contain whole file */
    buffer = (char*) malloc(length);
    if (buffer == NULL) {
      /* Handle memory allocation error */
    }

    /* ... Assign size here ... */
    if (length != size) {
      /* Handle case when size isn't the length of file */
    }
    /* ... Other code ... */

    if (fread(buffer, 1, size, fp) < size) {
      /* Handle file read error */
    }

    fclose(fp);

    return 0;
}

Risk Assessment

When reading an input stream, the read character sequence is not explicitly null-terminated by the fread() function. Operations on the read-to buffer could result in overruns, causing abnormal program termination .

Rule Severity Likelihood Detectable Repairable Priority Level
FIO17-C Low Likely No Yes P6 L2

Automated Detection

ToolVersionCheckerDescription
LDRA tool suite
9.7.1
44 SEnhanced enforcement

Search for vulnerabilities resulting from the violation of this guideline on the CERT website .

Bibliography

[ ISO/IEC 9899:2011 ]Subclause 7.21.8.1, "The fread Function"