Invoking getc() and putcDo not invoke getc() or putc() or their wide-character analogues getwc() and putwc() with a stream arguments argument that have has side effects may cause unexpected results because these functions may be implemented as macros and the stream arguments to these macros may be evaluated more than once.. The stream argument passed to these macros may be evaluated more than once if these functions are implemented as unsafe macros. (See PRE31-C. Avoid side effects in arguments to unsafe macros for more information.)
This rule This does not apply to the character argument in putc() or the wide-character argument in putwc(), which is guaranteed to be evaluated exactly once.
...
Noncompliant Code Example
...
(getc())
This noncompliant code example calls the getc() function with an expression as the stream argument. If getc() is implemented as a macro, the file may be opened several multiple times. (see FIO31See FIO24-C. Do not simultaneously open the same file multiple times).a file that is already open.)
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *file_name) { FILE *fptr; int c = getc(fptr = fopen(file_name, "r")); if (feof(fptr) || ferror(fptr)) { /* Handle error */ } if (fclose(fptr) == EOF) { /* Handle error */ } } |
This noncompliant code example also violates ERR33This non-compliant code example also violaties FIO33-C. Detect and handle input output errors resulting in undefined behaviorstandard library errors because the value returned by fopen() is not checked for errors.
Compliant Solution
...
(getc())
In this compliant solution, getcfopen() is no longer called with an expression as its argument.called before getc() and its return value is checked for errors:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *file_name) { int c; FILE *fptr; fptr = fopen(file_name, "r"); if (fptr == NULL) { /* Handle Errorerror */ } int c = getc(fptr); if (c == EOF) { /* Handle error */ } if (fclose(fptr) == EOF) { /* Handle error */ } } |
...
Noncompliant Code Example
...
(putc())
In this non-compliant noncompliant example, putc() is called with an expression as the stream argument. If putc() is implemented as a macro, the this expression could might be evaluated several times within the macro expansion of putc() with unintended resultsmultiple times.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *file_name) { FILE *fptr = NULL; int c = 'a'; while (c <= 'z') { if (putc(c++, fptr ? fptr : (fptr = fopen(file_name, "w"))) == EOF) { /* Handle error */ } } if (fclose(fptr)); } == EOF) { /* Handle error */ } } |
This noncompliant code example might appear safe even if If the putc() macro does evaluate evaluates its stream argument 2 or more multiple times, this might still seem safe, as the ?: operator ternary conditional expression ostensibly prevents multiple calls to fopen(). However, there is no guarantee that these would happen in distinct sequence points. So this coode might also violate the assignment to fptr and the evaluation of fptr as the controlling expression of the ternary conditional expression can take place between the same sequence points, resulting in undefined behavior 34 (a violation of EXP30-C. Do not depend on the order of evaluation between sequence pointsfor side effects). This code also violates ERR33-C. Detect and handle standard library errors because it fails to check the return value from fopen().
Compliant Solution
...
(putc())
In the this compliant solution, the stream argument to putc() no longer has side effects.:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *file_name) { int c = 'a'; FILE *fptr = fopen(file_name, "w"); if (fptr == NULL) { /* Handle Errorerror */ } int c = 'a'; while (c <= 'z') { if (putc(c++, fptr); } == EOF) { /* Handle error */ } } if (fclose(fptr) == EOF) { /* Handle error */ } } |
The expression The c++ is perfectly safe , since because putc() guarantees to evaluate its character argument exactly once.
This example only illustrates the side-effect issue. The output will differ depending on the character setNOTE: The output of this compliant solution differs depending on the character set. For example, when run on a machine using an ASCII-derived code set such as ISO-8859 or Unicode, this solution will print out the 26 lowercase letters of the English alphabet. However, if run with an EBCDIC-based code set, such as Codepage 037 or Codepage 285, punctuation marks or symbols may be output between the letters.
Risk Assessment
Using an expression that has side effects as the stream argument to getc(), putc(), or putcgetwc() can result in unexpected behavior and possibly abnormal program termination.
Rule | Severity | Likelihood |
|---|
Detectable | Repairable | Priority | Level | |||
|---|---|---|---|---|---|---|
FIO41-C | Low | Unlikely | Yes | Yes | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée |
| stream-argument-with-side-effects | Fully checked | ||||||
| Axivion Bauhaus Suite |
| CertC-FIO41 | |||||||
| Cppcheck Premium |
| premium-cert-fio41-c | |||||||
| Helix QAC |
| C5036 C++3225, C++3229 | |||||||
| LDRA tool suite |
| 35 D, 1 |
1 (unlikely)
2 (medium)
P2
L3
Automated Detection
...
Q, 9 S, | Fully implemented | ||||||||
| Parasoft C/C++test |
| CERT_C-FIO41-a | Do not call 'getc()', 'putc()', 'getwc()', or 'putwc()' with a stream argument containing assignments, increment or decrement operators Do not call 'getc()', 'putc()', 'getwc()', or 'putwc()' with a stream argument containing function calls or function-like macro calls | ||||||
| CERT C: Rule FIO41-C | Checks for stream arguments with possibly unintended side effects (rule fully covered) | |||||||
| RuleChecker |
| stream-argument-with-side-effects | Fully checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
| Wiki Markup |
|---|
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.19.7.5, "The {{getc}} function," and Section 7.19.7.8, "The {{putc}} function" |
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C Secure Coding Standard | FIO24-C. Do not open a file that is already open | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CERT C Secure Coding Standard | EXP30-C. Do not depend on the order of evaluation for side effects | Prior to 2018-01-12: CERT: Unspecified Relationship |
...
FIO40-C. Reset strings on fgets() failure 09. Input Output (FIO) FIO42-C. Ensure files are properly closed when they are no longer needed