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
Thefread
function reads, into the array pointed to byptr
, up tonmemb
elements
whose size is specified bysize
, from the stream pointed to bystream
.
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.
Suppose we have a null-terminated character sequence in a file, and we need to extract a null-terminated byte string:
#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.
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.
#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; } |
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 | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO17-C | Low | Likely | Medium | P6 | L2 |
Tool | Version | Checker | Description |
---|---|---|---|
LDRA tool suite | 44 S | Enhanced enforcement |
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
SEI CERT C++ Coding Standard | VOID FIO20-CPP. Do not rely on an ending null character when using read() |
[ISO/IEC 9899:2011] | Subclause 7.21.8.1, "The fread Function" |