Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: REM Cost Reform

Invoking getcDo not invoke getc() or putc() or their wide-character analogues getwc() and putcputwc() 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 rule FIO31 FIO24-C. Do not open a file that is already open.)

Code Block
bgColor#ffcccc
langc
#include <stdio.h>
 
void func(const char *file_name;) {
  FILE *fptr;

/* Initialize file_name */

int c = getc(fptr = fopen(file_name, "r"));
  if (c(feof(fptr) || ferror(fptr)) {
    /* Handle error */
  }

  if (fclose(fptr) == EOF) {
    /* Handle error */
  }
}

This noncompliant code example also violates rule FIO33ERR33-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 and the value returned by fopen() called before getc() and its return value is checked for errors.:

Code Block
bgColor#ccccff
langc

int c;
#include <stdio.h>
 
void func(const char *file_name) {
  int c;
  FILE *fptr;

/* Initialize file_name */

fptr = fopen(file_name, "r");
  if (fptr == NULL) {
    /* Handle error */
  }

  c = getc(fptr);
  if (c == EOF) {
    /* Handle error */
  }

  if (fclose(fptr) == EOF) {
    /* Handle error */
  }
}

Noncompliant Code Example (putc())

In this noncompliant example, putc() is called with an expression as the stream argument. If putc() is implemented as a macro, the this expression can might be evaluated several times within the macro expansion of putc() with unintended resultsmultiple times.

Code Block
bgColor#ffcccc
langc
#include <stdio.h>
 
void func(const char *file_name;) {
  FILE *fptr = NULL;

/* Initialize file_name */

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 evaluates its stream argument multiple times, this might still seem safe, as the ternary conditional expression ostensibly prevents multiple calls to fopen(). However, there is no guarantee that these would happen in distinct sequence points. Consequently, this code also violates rule 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
bgColor#ccccff
langc
#include <stdio.h>
 
void func(const char *file_name;

/* Initialize file_name */

) {
  int c = 'a'; 
  FILE *fptr = fopen(file_name, "w");
 
  if (fptr == NULL) {
    /* Handle error */
  }

int c = 'a';

while (c <= 'z') {
    if (putc(c++, fptr) == EOF) {
      /* Handle error */
    }
  }

  if (fclose(fptr) == EOF) {
    /* Handle error */
  }
}

The expression c++ is perfectly safe because putc() guarantees to evaluate its character argument exactly once.

This example shows only the side-effect issue. NOTE: The output of this compliant solution differs depending on the character set. Consequently, it is important to not make assumptions about the order of the letters. For example, when run on a machine using an ASCII-derived code set such as ISO-8859 or Unicode, this code sample solution will print out the 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

Remediation Cost

Detectable

Repairable

Priority

Level

FIO41-C

Low

low

Unlikely

unlikely

Yes

medium

Yes

P2

P3

L3

Automated Detection

Tool

Version

Checker

Description

section

Astrée
Include Page
Astrée_V
Astrée_V
stream-argument-with-side-effectsFully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-FIO41
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-fio41-c
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5036

C++3225, C++3229


LDRA tool suite
Include Page
LDRA_V
LDRA_V
Section

9 S

Section Fully Implemented

35 D, 1 Q, 9 S,
30 S, 134 S

Fully implemented

Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-FIO41-a
CERT_C-FIO41-b

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

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule FIO41-CChecks for stream arguments with possibly unintended side effects (rule fully covered)
RuleChecker

Include Page
RuleChecker_V
RuleChecker_V

stream-argument-with-side-effectsFully checked

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

...

...

...

...

...

open a file that is already openPrior to 2018-01-12: CERT: Unspecified Relationship
CERT C Secure Coding StandardEXP30-C. Do not depend on the order of evaluation for side effectsPrior to 2018-01-12: CERT: Unspecified Relationship


...

Image Added Image Added Image Added

ISO/IEC 9899:1999 Section 7.19.7.5, "The getc function," and Section 7.19.7.8, "The putc function"

Bibliography

FIO40-C. Reset strings on fgets() failure      09. Input Output (FIO)      FIO42-C. Ensure files are properly closed when they are no longer needed