Skip to end of metadata
Go to start of metadata

The value of errno is initialized to zero at program startup, but it is never subsequently set to zero by any C standard library function. The value of errno may be set to nonzero by a C standard library function call whether or not there is an error, provided the use of errno is not documented in the description of the function. It is meaningful for a program to inspect the contents of errno only after an error might have occurred. More precisely, errno is meaningful only after a library function that sets errno on error has returned an error code.

According to Question 20.4 of C-FAQ [Summit 2005],

In general, you should detect errors by checking return values, and use errno only to distinguish among the various causes of an error, such as "File not found" or "Permission denied." (Typically, you use perror or strerror to print these discriminating error messages.) It's only necessary to detect errors with errno when a function does not have a unique, unambiguous, out-of-band error return (that is, because all of its possible return values are valid; one example is atoi [sic]). In these cases (and in these cases only; check the documentation to be sure whether a function allows this), you can detect errors by setting errno to 0, calling the function, and then testing errno. (Setting errno to 0 first is important, as no library function ever does that for you.)

Note that atoi() is not required to set the value of errno.

Library functions fall into the following categories:

Library Functions that Set errno and Return an Out-of-Band Error Indicator

The C Standard specifies that the functions listed in the following table set errno and return an out-of-band error indicator. That is, their return value on error can never be returned by a successful call.

A program may set and check errno for these library functions but is not required to do so. The program should not check the value of errno without first verifying that the function returned an error indicator. For example, errno should not be checked after calling signal() without first ensuring that signal() actually returned SIG_ERR.

Functions That Set errno and Return an Out-of-Band Error Indicator

Function Name

Return Value

errno Value

ftell()-1L Positive 

fgetpos(), fsetpos()

Nonzero

Positive

mbrtowc(), mbsrtowcs()

(size_t)(-1)

EILSEQ

signal()

SIG_ERR

Positive

wcrtomb(), wcsrtombs()

(size_t)(-1)

EILSEQ

mbrtoc16(), mbrtoc32()(size_t)(-1) EILSEQ
c16rtomb(), c32rtomb()(size_t)(-1) EILSEQ 

Library Functions that Set errno and Return an In-Band Error Indicator

The C Standard specifies that the functions listed in the following table set errno and return an in-band error indicator. That is, the return value when an error occurs is also a valid return value for successful calls. For example, the strtoul() function returns ULONG_MAX and sets errno to ERANGE if an error occurs. Because ULONG_MAX is a valid return value, errno must be used to check whether an error actually occurred. A program that uses errno for error checking must set it to 0 before calling one of these library functions and then inspect errno before a subsequent library function call.

The fgetwc() and fputwc() functions return WEOF in multiple cases, only one of which results in setting errno. The string conversion functions will return the maximum or minimum representable value and set errno to ERANGE if the converted value cannot be represented by the data type. However, if the conversion cannot happen because the input is invalid, the function will return 0, and the output pointer parameter will be assigned the value of the input pointer parameter, provided the output parameter is non-null.

Functions that Set errno and Return an In-Band Error Indicator

Function Name

Return Value

errno Value

fgetwc(), fputwc()

WEOF

EILSEQ

strtol(), wcstol()

LONG_MIN or LONG_MAX

ERANGE

strtoll(), wcstoll()

LLONG_MIN or LLONG_MAX

ERANGE

strtoul(), wcstoul()

ULONG_MAX

ERANGE

strtoull(), wcstoull()

ULLONG_MAX

ERANGE

strtoumax(), wcstoumax()

UINTMAX_MAX

ERANGE

strtod(), wcstod()

0 or ±HUGE_VAL

ERANGE

strtof(), wcstof()

0 or ±HUGE_VALF

ERANGE

strtold(), wcstold()

0 or ±HUGE_VALL

ERANGE

strtoimax(), wcstoimax()

INTMAX_MIN, INTMAX_MAX

ERANGE

Library Functions that Do Not Promise to Set errno

The C Standard fails to document the behavior of errno for some functions. For example, the setlocale() function normally returns a null pointer in the event of an error, but no guarantees are made about setting errno.

After calling one of these functions, a program should not rely solely on the value of errno to determine if an error occurred. The function might have altered errno, but this does not ensure that errno will properly indicate an error condition.

Library Functions with Differing Standards Documentation

Some functions behave differently regarding errno in various standards. The fopen() function is one such example. When fopen() encounters an error, it returns a null pointer. The C Standard makes no mention of errno when describing fopen(). However, POSIX.1 declares that when fopen() encounters an error, it returns a null pointer and sets errno to a value indicating the error [IEEE Std 1003.1-2013]. The implication is that a program conforming to C but not to POSIX (such as a Windows program) should not check errno after calling fopen(), but a POSIX program may check errno if fopen() returns a null pointer.

Library Functions and errno

The following uses of errno are documented in the C Standard:

  • Functions defined in <complex.h> may set errno but are not required to.
  • For numeric conversion functions in the strtod, strtol, wcstod, and wcstol families, if the correct result is outside the range of representable values, an appropriate minimum or maximum value is returned and the value ERANGE is stored in errno. For floating-point conversion functions in the strtod and wcstod families, if an underflow occurs, whether errno acquires the value ERANGE is implementation-defined. If the conversion fails, 0 is returned and errno is not set.
  • The numeric conversion function atof() and those in the atoi family "need not affect the value of" errno.
  • For mathematical functions in <math.h>, if the integer expression math_errhandling & MATH_ERRNO is nonzero, on a domain error, errno acquires the value EDOM; on an overflow with default rounding or if the mathematical result is an exact infinity from finite arguments, errno acquires the value ERANGE; and on an underflow, whether errno acquires the value ERANGE is implementation-defined.
  • If a request made by calling signal() cannot be honored, a value of SIG_ERR is returned and a positive value is stored in errno.
  • The byte I/O functions, wide-character I/O functions, and multibyte conversion functions store the value of the macro EILSEQ in errno if and only if an encoding error occurs.
  • On failure, fgetpos() and fsetpos() return nonzero and store an implementation-defined positive value in errno.
  • On failure, ftell() returns -1L and stores an implementation-defined positive value in errno.
  • The perror() function maps the error number in errno to a message and writes it to stderr.

The POSIX.1 standard defines the use of errno by many more functions (including the C standard library function). POSIX also has a small set of functions that are exceptions to the rule. These functions have no return value reserved to indicate an error, but they still set errno on error. To detect an error, an application must set errno to 0 before calling the function and check whether it is nonzero after the call. Affected functions include strcoll(), strxfrm(), strerror(), wcscoll(), wcsxfrm(), and fwide(). The C Standard allows these functions to set errno to a nonzero value on success. Consequently, this type of error checking should be performed only on POSIX systems.

Noncompliant Code Example (strtoul())

This noncompliant code example fails to set errno to 0 before invoking strtoul(). If an error occurs, strtoul() returns a valid value (ULONG_MAX), so errno is the only means of determining if strtoul() ran successfully.

#include <errno.h>
#include <limits.h>
#include <stdlib.h>
 
void func(const char *c_str) {
  unsigned long number;
  char *endptr;
  
  number = strtoul(c_str, &endptr, 0);
  if (endptr == c_str || (number == ULONG_MAX 
                         && errno == ERANGE)) {
    /* Handle error */
  } else {
    /* Computation succeeded */
  }
}

Any error detected in this manner may have occurred earlier in the program or may not represent an actual error.

Compliant Solution (strtoul())

This compliant solution sets errno to 0 before the call to strtoul() and inspects errno after the call:

#include <errno.h>
#include <limits.h>
#include <stdlib.h>
 
void func(const char *c_str) {
  unsigned long number;
  char *endptr;
 
  errno = 0;
  number = strtoul(c_str, &endptr, 0);
  if (endptr == c_str || (number == ULONG_MAX 
                         && errno == ERANGE)) {
    /* Handle error */
  } else {
    /* Computation succeeded */
  }
}

Noncompliant Code Example (fopen())

This noncompliant code example may fail to diagnose errors because fopen() might not set errno even if an error occurs:

#include <errno.h>
#include <stdio.h>
 
void func(const char *filename) {
  FILE *fileptr;

  errno = 0;
  fileptr = fopen(filename, "rb");
  if (errno != 0) {
    /* Handle error */
  }
}

Compliant Solution (fopen(), C)

The C Standard makes no mention of errno when describing fopen(). In this compliant solution, the results of the call to fopen() are used to determine failure and errno is not checked:

#include <stdio.h>
 
void func(const char *filename) {
  FILE *fileptr = fopen(filename, "rb");
  if (fileptr == NULL)  {
    /* An error occurred in fopen() */
  }
}

Compliant Solution (fopen(), POSIX)

In this compliant solution, errno is checked only after an error has already been detected by another means:

#include <errno.h>
#include <stdio.h>
 
void func(const char *filename) {
  FILE *fileptr;

  errno = 0;
  fileptr = fopen(filename, "rb");
  if (fileptr == NULL)  {
    /*
     * An error occurred in fopen(); now it's valid 
     * to examine errno.
     */
    perror(filename);
  }
}

Risk Assessment

The improper use of errno may result in failing to detect an error condition or in incorrectly identifying an error condition when none exists.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR30-C

Medium

Probable

Medium

P8

L2

Automated Detection

Tool

Version

Checker

Description

Astrée
18.10
errno-resetPartially checked
Axivion Bauhaus Suite

6.9.0

CertC-ERR30Fully implemented
Compass/ROSE

Could detect violations of this rule by ensuring that each library function is accompanied by the proper treatment of errno

Coverity
2017.07

MISRA C 2012 Rule 22.8

MISRA C 2012 Rule 22.9

MISRA C 2012 Rule 22.10

Implemented
LDRA tool suite
9.7.1

111 D, 121 D, 122 D, 132  D, 134 D

Fully implemented
Parasoft C/C++test
10.4.1

CERT_C-ERR30-a
CERT_C-ERR30-b

Properly use errno value
Provide error handling for file opening errors right next to the call to fopen

Polyspace Bug Finder

R2018a

Errno not reset

Misuse of errno

MISRA C:2012 Rule 22.8

MISRA C:2012 Rule 22.10

errno not reset before calling a function that sets errno

errno incorrectly checked for error conditions

The value of errno shall be set to zero prior to a call to an errno-setting-function

The value of errno shall only be tested when the last function to be called was an errno-setting function

 PRQA QA-C

9.5

2500, 2501, 2502, 2503 

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 StandardEXP12-C. Do not ignore values returned by functionsPrior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961:2013Incorrectly setting and using errno [inverrno]Prior to 2018-01-12: CERT: Unspecified Relationship
CWE 2.11CWE-456, Missing Initialization of a Variable2017-07-05: CERT: Rule subset of CWE

CERT-CWE Mapping Notes

Key here for mapping notes

CWE-456 and ERR30-C

CWE-456 = EXP33-C

CWE-456 = Union( ERR30-C, list) where list =


  • Reading potentially uninitialized variables besides errno


CWE-248 and ERR30-C

Intersection( CWE-248, ERR30-C) = Ø

CWE-248 is only for languages that support exceptions. It lists C++ and Java, but not C.

Bibliography

[Brainbell.com]Macros and Miscellaneous Pitfalls
[Horton 1990]Section 11, p. 168
Section 14, p. 254
[IEEE Std 1003.1-2013]XSH, System Interfaces, fopen
[Koenig 1989]Section 5.4, p. 73
[Summit 2005]





25 Comments

  1. This would be a good place to state that applications should not try to use errno to report their own error codes.

    1. I agree with the sentiment, which is sort of captured by this recommendation:

      DCL09-C. Declare functions that return errno with a return type of errno_t

      I'm having trouble figuring out how to incorporate it into this recommendation, because no interface is defined.

  2. The text describing the 2nd NCCE pair doesn't match the code. It warns that a C library function may set errno even if no error occurs...is this in the standard? And it doesn't illustrate what the NCCE & CCE seem to be illustrating, that you shouldn't rely on errno if the library function (fopen() in this case) provides an in-band error indicator (a NULL pointer).

    1. Fixed.

      What it said about functions setting errno even if no error occurs was just a less accurate repeat of what the second sentence at the top of the page says (which closely matches what C99 says).

  3. The new text describing a ROSE algorithm made me realise that part of this rule is too strict. It says

    A program that uses errno for error checking should set it to zero before a library function call and then inspect it before a subsequent library function call.

    However, it is only necessary to set errno to zero before the call if the value returned by the call as an error indication is also a valid return value, as in the strtoul() example with return value ULONG_MAX.

    Also the final statement in the ROSE algorithm is problematic:

    Furthermore, one can check that errno isn't set or tested near a function that doesn't set it, like fopen().

    because there are C99 functions for which C99 doesn't require errno to be set but POSIX does. ROSE would need to know whether the code is targeted at a pure C99 implementation or a POSIX implementation.

    1. Rewrote the ROSE section...since we are considering three types of functions (see the ROSE section for details). Perhaps these three types of functions should be described in the rule itself (and not just wrt ROSE).

      1. Yes, I think the rule should cover those three types of functions. (I tweaked their descriptions in the ROSE section).

        Also the rule name needs to change to something more general, e.g. "Handle errno appropriately for the error reporting characteristics of each function".

        1. ok this rule now discusses differing behavior of these functions
          especially fopen(), which sets errno in POSIX but doesn't in pure C99.

          1. I removed that part about functions that only indicate errors via errno from the main three function types, as I believe there are no such functions in C99, only POSIX. They are covered in the section about POSIX, where it says they are an exception to the rule.

            The choice of printf() as an example in "Library Functions that don't promise to set errno" is unfortunate, since it is one of the byte input/output functions and C99 requires those to set errno to EILSEQ when an encoding error occurs. (It is one of the bullet points under "Library Functions and errno".)

            The new rule name is better, but still doesn't match the details within the rule. E.g. it doesn't cover the part of the rule about not checking errno for "Library Functions that don't promise to set errno". I still think it should be changed to something more general like "Handle errno appropriately for the error reporting characteristics of each function".

            1. I removed that part about functions that only indicate errors via errno from the main three function types, as I believe there are no such functions in C99, only POSIX. They are covered in the section about POSIX, where it says they are an exception to the rule.

              Your changes are good, but it doesn't look to me like you removed any significant parts.

              The choice of printf() as an example in "Library Functions that don't promise to set errno" is unfortunate, since it is one of the byte input/output functions and C99 requires those to set errno to EILSEQ when an encoding error occurs. (It is one of the bullet points under "Library Functions and errno".)

              I see it in the bullet point, but I don't see anything in C99 about EILSEQ and printf/fprintf. Perhaps the standard links errno & printf elsewhere, but not in the printf section (7.19.6.1). Besides, while printf might set errno if an encoding error occurs, would it set errno if anything else happens (eg what if the stdout is closed?).

              I thought the atoi() family of functions was considered 'deprecated', in lieu of the strtoul() family...that's why I didn't want to use atoi() as an example function that doesn't set errno. I take it from your comment that there isn't a function (in C99) that doesn't use errno to indicate errors...is there a good POSIX function we can use in our NCCE/CCE pair instead of printf()?A

              The new rule name is better, but still doesn't match the details within the rule. E.g. it doesn't cover the part of the rule about not checking errno for "Library Functions that don't promise to set errno". I still think it should be changed to something more general like "Handle errno appropriately for the error reporting characteristics of each function".

              Title is shorter, and hopefully, more accurate.

      2. Right, unless we have a table/list of these, it's going to be hard to write the actual code...

  4. The sentence starting with "It might be more reasonable" under Automated Detection reads funny, and I'm not sure what it's trying to say, since it seems so similar to the previous sentence.

  5. about the sentence after the first NCCE(strtoul()),

    Any error detected in this manner may have occurred earlier in the program or may not represent an actual error.

    how about omitting the latter part ("or may not represent an actual error"), or changing the sentence to

    "Any error detected in this manner may have occurred earlier in the program and not represent an actual error."

    I want to confirm if I understand correctly the intention of this sentence...

    I guess there are only three situations possible here, as detected as error.

    • nothing's been converted, hence endptr == string
    • the string (or a part of the string) indicates too big value to represent in unsigned long
    • the string (or a part of the string) is converted successfully to ULONG_MAX, but errno was previously set to ERANGE

     

    1. See ERR34-C. Detect errors when converting a string to a number for a more comprehensive code example about the proper use of strtoul(). In particular, it is also possible for strtoul() to make a successful conversion but still leave garbage characters in the input string...this may or may not be an error depending on your circumstances.

      It is possible that errno is set by some older routine and so it indicates an error, but not one in strtoul(). It is also possible (though unlikely) that the routine set errno erroneously and so it does not actually indicate an error. So I still believe the sentence is most correct as it is currently written.

  6.  Affected functions include strcoll()strxfrm()strerror()wcscoll()wcsxfrm(), and fwide(). The C Standard allows these functions to set errno to a nonzero value on success.

    I have checked C90 and C11 standards and I could not find anything describing behavior of functions strcoll()strxfrm()wcscoll()wcsxfrm() with respect to errno. What have I missed?

    1. The POSIX standard specifies some of the behavior of these functions with errno.

  7. Could you please clarify, if it is required by the rule that every call to a function that returns an in-band error indicator is followed by an errno-check.

    1. These two sentences in the intro clarify things:

      It is meaningful for a program to inspect the contents of errno only after an error might have occurred. More precisely, errno is meaningful only after a library function that sets errno on error has returned an error code.

      In particular, if your function returns an in-band error indicator, then setting & checking errno is not required. It is only required that you check the return value for errors, because that indicates *if* an error occurs. Typically this function does not precisely indicate *which* error occurred, and if you want that information, then you set errno before the call and check it afterwards.

      1. Let me summarize my current understanding of the rule's requirements:

        For both classes of functions that return in-/out-of-band error indicators, if the value of errno is checked after the function call then the rule requires that

        • errno is set to 0 before the call
        • the returned value is checked against a corresponding error indicator value before the errno check

        The rule does not require that a possible error is detected (as this is the subject of ERR33-C).

        Is my understanding correct?

        1. Yes! This correctly describes how to handle in-band and out-of-band functions.

  8. In table Functions That Set errno and Return an Out-of-Band Error Indicator, the function name should be c32rtomb, not cr32rtomb

  9. In the two bullet items:

    should the words here 'and' actually be 'an'?