You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 48 Next »

Invoking getc() and putc() with stream arguments that have 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.

This does not apply to the character argument in putc(), which is guaranteed to be evaluated exactly once.

Noncompliant Code Example (getc)

This code calls the getc() function with an expression as the stream argument. If getc() is implemented as a macro, the file may be opened several times (see FIO31-C. Do not open a file that is already open).

char *file_name;
FILE *fptr;

/* Initialize file_name */

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

This noncompliant code example also violates FIO33-C. Detect and handle input output errors resulting in undefined behavior because the value returned by fopen() is not checked for errors.

Compliant Solution (getc)

In this compliant solution, getc() is no longer called with an expression as its argument and the value returned by fopen() is checked for errors.

int c;
char *file_name;
FILE *fptr;

/* Initialize file_name */

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

c = getc(fptr);
if (c == 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 expression can be evaluated several times within the macro expansion of putc() with unintended results.

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 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 EXP30-C. Do not depend on order of evaluation between sequence points.

Compliant Solution (putc)

In the compliant solution, the stream argument to putc() no longer has side effects.

char *file_name;

/* Initialize file_name */

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

int c = 'a';

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

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

This example shows only the side-effect issue. The output 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 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() or putc() can result in unexpected behavior and possibly abnormal program termination.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO41-C

low

unlikely

medium

P2

L3

Automated Detection

The LDRA tool suite V 7.6.0 can detect violations of this rule.

Related Vulnerabilities

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

Other Languages

This rule appears in the C++ Secure Coding Standard as FIO41-CPP. Do not call getc() or putc() with stream arguments that have side effects.

References

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


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

  • No labels