
...
The byte I/O functions fgetc()
, getc()
, and getchar()
all read a character from a stream and return it as an int.
(see See STR00-C. Represent characters using an appropriate type.) . If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF
. If a read error occurs, the error indicator for the stream is set and the function returns EOF
. If these functions succeed, they cast the character returned into an unsigned char
.
Because EOF
is negative, it should not match any unsigned character value. However, this is only true for implementations where the int
type is wider than char
. On an implementation where int
and char
have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as EOF
. This could occur, for example, if an attacker inserted a value that looked like EOF
into the file or data stream to alter the behavior of the program.
The C Standard requires only that the int
type be able to represent a maximum value of +32767 and that a char
type be no larger than an int
. Although uncommon, this situation can result in the integer constant expression EOF
being indistinguishable from a valid character; that is, (int)(unsigned char)65535 == -1
. Consequently, failing to use feof()
and ferror()
to detect end-of-file and file errors can result in incorrectly identifying the EOF
character on rare implementations where sizeof(int) == sizeof(char)
.
This problem is much more common when reading wide characters. The fgetwc()
, getwc()
, and getwchar()
functions return a value of type wint_t
. This value can represent the next wide character read, or it can represent WEOF
, which indicates end-of-file for wide character streams. On most implementations, the wchar_t
type has the same width as wint_t
, and so these functions can return a character indistinguishable from WEOF
.
...
This compliant solution uses feof()
and ferror()
to test for whether the EOF
was an actual character or a real EOF
because of end-of-file and ferror()
to test for or errors:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void func(void) { int c; do { c = getchar(); } while (c != EOF); || if (!feof(stdin)) { /* Handle end of file */ } else if (&& !ferror(stdin)) { /* Handle file error */ } else { /* Received a character that resembles EOF; handle error */ } } ); } |
Noncompliant Code Example (Nonportable)
...
Assuming that a char
is a signed 8-bit type and an int is a 32-bit type, if getchar()
returns the character character value '\xff
(decimal 255), it will be interpreted as EOF
because this value is sign-extended to 0xFFFFFFFF
(the value of EOF
) to perform the comparison. (see See STR34-C. Cast characters to unsigned char before converting to larger integer sizes.).
Compliant Solution (Nonportable)
...
This compliant solution declares c
wc
to be a wint_t
to match the integer type returned by getwc()
. Furthermore, it does not rely on WEOF
to determine end-of-file definitively.
...
Incorrectly assuming characters from a file cannot match EOF
or WEOF
has resulted in significant vulnerabilities, including command injection attacks. (see See the *CA-1996-22 advisory.).
Rule | Severity | Likelihood |
---|
Detectable | Repairable | Priority | Level |
---|---|---|---|
FIO34-C | High | Probable |
Yes | Yes |
P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| conversion_overflow essential-type-assign | Soundly supported | ||||||
Axivion Bauhaus Suite |
| CertC-FIO34 | |||||||
CodeSonar |
| LANG.CAST.COERCE | Coercion alters value | ||||||
Compass/ROSE |
Coverity |
|
|
CHAR_IO | Identifies defects when the return value of | ||||||||
Cppcheck Premium |
| premium-cert-fio34-c | |||||||
ECLAIR | 1.2 | CC2.FIO34 | Partially implemented |
5.0
Helix QAC |
| C2676, C2678 C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717 | |||||||
Klocwork |
| CWARN.CMPCHR.EOF |
LDRA tool suite |
| 662 S | Fully implemented | ||||||
Parasoft C/C++test |
| CERT_C-FIO34-a | The macro EOF should be compared with the unmodified return value from the Standard Library function | |||||||
| Checks for character values absorbed into EOF (rule partially covered) |
Splint | 3.1.1 |
RuleChecker |
| essential-type-assign | Supported |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
---|---|---|
CERT C Secure Coding Standard | STR00-C. Represent characters using an appropriate type | Prior to 2018-01-12: CERT: Unspecified Relationship |
CERT C Secure Coding Standard | INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data | Prior to 2018-01-12: CERT: Unspecified Relationship |
CERT Oracle Secure Coding Standard for Java | FIO08-J. Use an int to capture the return value of methods that read a character or byte | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TS 17961:2013 | Using character values that are indistinguishable from EOF [chreof] | Prior to 2018-01-12: CERT: Unspecified Relationship |
CWE 2.11 | CWE-197 | 2017-06-14: CERT: Rule subset of CWE |
CERT-CWE Mapping Notes
Key here for mapping notes
CWE-197 and FIO34-C
Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C)
Therefore: FIO34-C = Subset( CWE-197)
Bibliography
[Kettlewell 2002] | Section 1.2, "<stdio.h > and Character Types" |
[NIST 2006] | SAMATE Reference Dataset Test Case ID 000-000-088 |
[Summit 2005] | Question 12.2 |