01.07.2016 Views

SEI CERT C Coding Standard

tqcylJ

tqcylJ

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>SEI</strong> <strong>CERT</strong><br />

C <strong>Coding</strong> <strong>Standard</strong><br />

Rules for Developing Safe, Reliable, and Secure Systems<br />

2016 Edition


Copyright 2016 Carnegie Mellon University<br />

This material is based upon work funded and supported by the Department of Defense under Contract No.<br />

FA8721-05-C-0003 with Carnegie Mellon University for the operation of the Software Engineering Institute, a<br />

federally funded research and development center.<br />

Any opinions, findings and conclusions or recommendations expressed in this material are those of the author(s)<br />

and do not necessarily reflect the views of the United States Department of Defense.<br />

This report was prepared for the<br />

<strong>SEI</strong> Administrative Agent<br />

AFLCMC/PZM<br />

20 Schilling Circle, Bldg. 1305, 3rd floor<br />

Hanscom AFB, MA 01731-2125<br />

NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING INSTITUTE<br />

MATERIAL IS FURNISHED ON AN “AS-IS” BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO<br />

WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT<br />

NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR<br />

RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT<br />

MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK,<br />

OR COPYRIGHT INFRINGEMENT.<br />

[Distribution Statement A] This material has been approved for public release and unlimited distribution.<br />

Please see Copyright notice for non-US Government use and distribution.<br />

Internal use:* Permission to reproduce this material and to prepare derivative works from this material for internal<br />

use is granted, provided the copyright and “No Warranty” statements are included with all reproductions<br />

and derivative works.<br />

External use:* This material may be reproduced in its entirety, without modification, and freely distributed in<br />

written or electronic form without requesting formal permission. Permission is required for any other external<br />

and/or commercial use. Requests for permission should be directed to the Software Engineering Institute at<br />

permission@sei.cmu.edu.<br />

* These restrictions do not apply to U.S. government entities.<br />

Carnegie Mellon® and <strong>CERT</strong>® are registered marks of Carnegie Mellon University.<br />

DM-0003560<br />

v2016-06-29-1140


Table of Contents<br />

1 Introduction 1<br />

1.1 Scope 2<br />

1.2 Audience 3<br />

1.3 History 4<br />

1.4 ISO/IEC TS 17961 C Secure <strong>Coding</strong> Rules 5<br />

1.5 Tool Selection and Validation 7<br />

1.6 Taint Analysis 9<br />

1.7 Rules Versus Recommendations 10<br />

1.8 Conformance Testing 11<br />

1.9 Development Process 12<br />

1.10 Usage 13<br />

1.11 System Qualities 13<br />

1.12 Vulnerability Metric 13<br />

1.13 How This <strong>Coding</strong> <strong>Standard</strong> Is Organized 14<br />

1.14 Automatically Generated Code 18<br />

1.15 Government Regulations 19<br />

1.16 Acknowledgments 20<br />

2 Preprocessor (PRE) 23<br />

2.1 PRE30-C. Do not create a universal character name through concatenation 23<br />

2.2 PRE31-C. Avoid side effects in arguments to unsafe macros 25<br />

2.3 PRE32-C. Do not use preprocessor directives in invocations of function-like macros 30<br />

3 Declarations and Initialization (DCL) 32<br />

3.1 DCL30-C. Declare objects with appropriate storage durations 32<br />

3.2 DCL31-C. Declare identifiers before using them 36<br />

3.3 DCL36-C. Do not declare an identifier with conflicting linkage classifications 40<br />

3.4 DCL37-C. Do not declare or define a reserved identifier 43<br />

3.5 DCL38-C. Use the correct syntax when declaring a flexible array member 50<br />

3.6 DCL39-C. Avoid information leakage when passing a structure across a trust boundary 53<br />

3.7 DCL40-C. Do not create incompatible declarations of the same function or object 60<br />

3.8 DCL41-C. Do not declare variables inside a switch statement before the first case label 66<br />

4 Expressions (EXP) 68<br />

4.1 EXP30-C. Do not depend on the order of evaluation for side effects 68<br />

4.2 EXP32-C. Do not access a volatile object through a nonvolatile reference 74<br />

4.3 EXP33-C. Do not read uninitialized memory 76<br />

4.4 EXP34-C. Do not dereference null pointers 85<br />

4.5 EXP35-C. Do not modify objects with temporary lifetime 90<br />

4.6 EXP36-C. Do not cast pointers into more strictly aligned pointer types 93<br />

4.7 EXP37-C. Call functions with the correct number and type of arguments 98<br />

4.8 EXP39-C. Do not access a variable through a pointer of an incompatible type 103<br />

4.9 EXP40-C. Do not modify constant objects 109<br />

4.10 EXP42-C. Do not compare padding data 111<br />

4.11 EXP43-C. Avoid undefined behavior when using restrict-qualified pointers 114<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.<br />

i


4.12 EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic 122<br />

4.13 EXP45-C. Do not perform assignments in selection statements 126<br />

4.14 EXP46-C. Do not use a bitwise operator with a Boolean-like operand 131<br />

5 Integers (INT) 132<br />

5.1 INT30-C. Ensure that unsigned integer operations do not wrap 132<br />

5.2 INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data 138<br />

5.3 INT32-C. Ensure that operations on signed integers do not result in overflow 147<br />

5.4 INT33-C. Ensure that division and remainder operations do not result in divide-by-zero<br />

errors 157<br />

5.5 INT34-C. Do not shift an expression by a negative number of bits or by greater than or<br />

equal to the number of bits that exist in the operand 160<br />

5.6 INT35-C. Use correct integer precisions 166<br />

5.7 INT36-C. Converting a pointer to integer or integer to pointer 169<br />

6 Floating Point (FLP) 173<br />

6.1 FLP30-C. Do not use floating-point variables as loop counters 173<br />

6.2 FLP32-C. Prevent or detect domain and range errors in math functions 176<br />

6.3 FLP34-C. Ensure that floating-point conversions are within range of the new type 185<br />

6.4 FLP36-C. Preserve precision when converting integral values to floating-point type 189<br />

6.5 FLP37-C. Do not use object representations to compare floating-point values 191<br />

7 Array (ARR) 193<br />

7.1 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts 193<br />

7.2 ARR32-C. Ensure size arguments for variable length arrays are in a valid range 203<br />

7.3 ARR36-C. Do not subtract or compare two pointers that do not refer to the same array 207<br />

7.4 ARR37-C. Do not add or subtract an integer to a pointer to a non-array object 209<br />

7.5 ARR38-C. Guarantee that library functions do not form invalid pointers 212<br />

7.6 ARR39-C. Do not add or subtract a scaled integer to a pointer 222<br />

8 Characters and Strings (STR) 226<br />

8.1 STR30-C. Do not attempt to modify string literals 226<br />

8.2 STR31-C. Guarantee that storage for strings has sufficient space for character<br />

data and the null terminator 230<br />

8.3 STR32-C. Do not pass a non-null-terminated character sequence to a library function<br />

that expects a string 242<br />

8.4 STR34-C. Cast characters to unsigned char before converting to larger integer sizes 247<br />

8.5 STR37-C. Arguments to character-handling functions must be representable as an<br />

unsigned char 251<br />

8.6 STR38-C. Do not confuse narrow and wide character strings and functions 253<br />

9 Memory Management (MEM) 256<br />

9.1 MEM30-C. Do not access freed memory 256<br />

9.2 MEM31-C. Free dynamically allocated memory when no longer needed 262<br />

9.3 MEM33-C. Allocate and copy structures containing a flexible array member<br />

dynamically 264<br />

9.4 MEM34-C. Only free memory allocated dynamically 269<br />

9.5 MEM35-C. Allocate sufficient memory for an object 273<br />

9.6 MEM36-C. Do not modify the alignment of objects by calling realloc() 277<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.<br />

ii


10 Input/Output (FIO) 281<br />

10.1 FIO30-C. Exclude user input from format strings 281<br />

10.2 FIO32-C. Do not perform operations on devices that are only appropriate for files 285<br />

10.3 FIO34-C. Distinguish between characters read from a file and EOF or WEOF 291<br />

10.4 FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when<br />

successful 296<br />

10.5 FIO38-C. Do not copy a FILE object 299<br />

10.6 FIO39-C. Do not alternately input and output from a stream without an intervening<br />

flush or positioning call 301<br />

10.7 FIO40-C. Reset strings on fgets() or fgetws() failure 304<br />

10.8 FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream argument that<br />

has side effects 306<br />

10.9 FIO42-C. Close files when they are no longer needed 309<br />

10.10 FIO44-C. Only use values for fsetpos() that are returned from fgetpos() 313<br />

10.11 FIO45-C. Avoid TOCTOU race conditions while accessing files 315<br />

10.12 FIO46-C. Do not access a closed file 319<br />

10.13 FIO47-C. Use valid format strings 321<br />

11 Environment (ENV) 326<br />

11.1 ENV30-C. Do not modify the object referenced by the return value of certain functions 326<br />

11.2 ENV31-C. Do not rely on an environment pointer following an operation that may<br />

invalidate it 331<br />

11.3 ENV32-C. All exit handlers must return normally 336<br />

11.4 ENV33-C. Do not call system() 340<br />

11.5 ENV34-C. Do not store pointers returned by certain functions 347<br />

12 Signals (SIG) 353<br />

12.1 SIG30-C. Call only asynchronous-safe functions within signal handlers 353<br />

12.2 SIG31-C. Do not access shared objects in signal handlers 363<br />

12.3 SIG34-C. Do not call signal() from within interruptible signal handlers 367<br />

12.4 SIG35-C. Do not return from a computational exception signal handler 371<br />

13 Error Handling (ERR) 374<br />

13.1 ERR30-C. Set errno to zero before calling a library function known to set errno,<br />

and check errno only after the function returns a value indicating failure 374<br />

13.2 ERR32-C. Do not rely on indeterminate values of errno 381<br />

13.3 ERR33-C. Detect and handle standard library errors 386<br />

14 Concurrency (CON) 403<br />

14.1 CON30-C. Clean up thread-specific storage 403<br />

14.2 CON31-C. Do not destroy a mutex while it is locked 407<br />

14.3 CON32-C. Prevent data races when accessing bit-fields from multiple threads 410<br />

14.4 CON33-C. Avoid race conditions when using library functions 414<br />

14.5 CON34-C. Declare objects shared between threads with appropriate storage durations 418<br />

14.6 CON35-C. Avoid deadlock by locking in a predefined order 426<br />

14.7 CON36-C. Wrap functions that can spuriously wake up in a loop 431<br />

14.8 CON37-C. Do not call signal() in a multithreaded program 435<br />

14.9 CON38-C. Preserve thread safety and liveness when using condition variables 437<br />

14.10 CON39-C. Do not join or detach a thread that was previously joined or detached 445<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.<br />

iii


14.11 CON40-C. Do not refer to an atomic variable twice in an expression 447<br />

14.12 CON41-C. Wrap functions that can fail spuriously in a loop 451<br />

15 Miscellaneous (MSC) 455<br />

15.1 MSC30-C. Do not use the rand() function for generating pseudorandom numbers 455<br />

15.2 MSC32-C. Properly seed pseudorandom number generators 459<br />

15.3 MSC33-C. Do not pass invalid data to the asctime() function 463<br />

15.4 MSC37-C. Ensure that control never reaches the end of a non-void function 466<br />

15.5 MSC38-C. Do not treat a predefined identifier as an object if it might only<br />

be implemented as a macro 470<br />

15.6 MSC39-C. Do not call va_arg() on a va_list that has an indeterminate value 473<br />

15.7 MSC40-C. Do not violate constraints 476<br />

Appendix A: Bibliography 481<br />

Appendix B: Definitions 501<br />

Appendix C: Undefined Behavior 510<br />

Appendix D: Unspecified Behavior 525<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.<br />

iv


Introduction - Scope<br />

1 Introduction<br />

The <strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>, 2016 Edition provides rules for secure coding in the C programming<br />

language. The goal of these rules and recommendations is to develop safe, reliable, and<br />

secure systems, for example by eliminating undefined behaviors that can lead to undefined program<br />

behaviors and exploitable vulnerabilities. Conformance to the coding rules defined in this<br />

standard are necessary (but not sufficient) to ensure the safety, reliability, and security of software<br />

systems developed in the C programming language. It is also necessary, for example, to have a<br />

safe and secure design. Safety-critical systems typically have stricter requirements than are imposed<br />

by this coding standard, for example requiring that all memory be statically allocated. However,<br />

the application of this coding standard will result in high-quality systems that are reliable,<br />

robust, and resistant to attack.<br />

Each rule consists of a title, a description, and noncompliant code examples and compliant solutions.<br />

The title is a concise, but sometimes imprecise, description of the rule. The description<br />

specifies the normative requirements of the rule. The noncompliant code examples are examples<br />

of code that would constitute a violation of the rule. The accompanying compliant solutions<br />

demonstrate equivalent code that does not violate the rule or any other rules in this coding standard.<br />

A well-documented and enforceable coding standard is an essential element of coding in the C<br />

programming language. <strong>Coding</strong> standards encourage programmers to follow a uniform set of rules<br />

determined by the requirements of the project and organization rather than by the programmer’s<br />

familiarity. Once established, these standards can be used as a metric to evaluate source code (using<br />

manual or automated processes).<br />

<strong>CERT</strong>’s coding standards are being widely adopted by industry. Cisco Systems, Inc. announced<br />

its adoption of the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> as a baseline programming standard in its<br />

product development in October 2011 at Cisco’s annual SecCon conference. Recently, Oracle has<br />

integrated all of <strong>CERT</strong>’s secure coding standards into its existing secure coding standards. This<br />

adoption is the most recent step of a long collaboration: <strong>CERT</strong> and Oracle previously worked together<br />

in authoring The <strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java (Addison-Wesley, 2011).<br />

This standard is based on the C rules available on the <strong>CERT</strong> Secure <strong>Coding</strong> wiki as of 30 March<br />

2016. The wiki contains ongoing updates of the standard between official published releases. If<br />

you are interested in contributing to the rules, create an account on the wiki and then request contributor<br />

privileges by sending email to info@sei.cmu.edu.<br />

The Secure <strong>Coding</strong> eNewsletter contains news from the <strong>CERT</strong> Secure <strong>Coding</strong> Initiative as well as<br />

summaries of recent updates to the standard rules. If you are interested in receiving updates directly,<br />

subscribe to the eNewsletter through our website or send a request to info@sei.cmu.edu.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 1<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Scope<br />

1.1 Scope<br />

The <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> was developed specifically for versions of the C programming<br />

language defined by<br />

• ISO/IEC 9899:2011 ISO/IEC, Programming Languages—C, 3rd ed. [ISO/IEC 9899:2011]<br />

• ISO/IEC 9899:2011/Cor.1:2012, Technical Corrigendum 1<br />

Although the guidelines for this standard were developed for C11, they can also be applied to earlier<br />

versions of the C programming language, including C99. Variations between versions of the<br />

C <strong>Standard</strong> that would affect the proper application of these guidelines are noted where applicable.<br />

Most guidelines have a noncompliant code example that is a C11-conforming program to ensure<br />

that the problem identified by the guideline is within the scope of the standard. However, the best<br />

solutions to secure coding problems are often platform specific. In many cases, this standard provides<br />

appropriate compliant solutions for both POSIX and Windows operating systems. Language<br />

and library extensions that have been published as ISO/IEC technical reports or technical specifications<br />

are frequently given precedence, such has those described by ISO/IEC TR 24731-2, Extensions<br />

to the C Library—Part II: Dynamic Allocation Functions [ISO/IEC TR 24731-2:2010].<br />

In many cases, compliant solutions are also provided for specific platforms such as Linux or<br />

OpenBSD. Occasionally, interesting or illustrative implementation-specific behaviors are described.<br />

1.1.1 Rationale<br />

A coding standard for the C programming language can create the highest value for the longest<br />

period of time by focusing on the C <strong>Standard</strong> (C11) and the relevant post-C11 technical reports.<br />

The C <strong>Standard</strong> documents existing practice where possible. That is, most features must be tested<br />

in an implementation before being included in the standard. The <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong> has a<br />

different purpose: to establish a set of best practices, which sometimes requires introducing new<br />

practices that may not be widely known or used when existing practices are inadequate. To put it<br />

a different way, the <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong> attempts to drive change rather than just document<br />

it.<br />

For example, the optional but normative Annex K, “Bounds-Checking Interfaces,” introduced in<br />

C11, is gaining support but at present is implemented by only a few vendors. It introduces functions<br />

such as memcpy_s(), which serve the purpose of security by adding the destination buffer<br />

size to the API. A forward-looking document could not reasonably ignore these functions simply<br />

because they are not yet widely implemented. The base C <strong>Standard</strong> is more widely implemented<br />

than Annex K, but even if it were not, it is the direction in which the industry is moving. Developers<br />

of new C code, especially, need guidance that is usable, on and makes the best use of, the<br />

compilers and tools that are now being developed and are being supported into the future.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 2<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Audience<br />

Some vendors have extensions to C, and some also have implemented only part of the C <strong>Standard</strong><br />

before stopping development. Consequently, it is not possible to back up and discuss only C95,<br />

C90, or C99. The vendor support equation is too complicated to draw a line and say that a certain<br />

compiler supports exactly a certain standard. Whatever demarcation point is selected, different<br />

vendors are on opposite sides of it for different parts of the language. Supporting all possibilities<br />

would require testing the cross-product of each compiler with each language feature. Consequently,<br />

we have selected a demarcation point that is the most recent in time so that the rules and<br />

recommendations defined by the standard will be applicable for as long as possible. As a result of<br />

the variations in support, source-code portability is enhanced when the programmer uses only the<br />

features specified by C99. This is one of many trade-offs between security and portability inherent<br />

to C language programming.<br />

The value of forward-looking information increases with time before it starts to decrease. The<br />

value of backward-looking information starts to decrease immediately.<br />

For all of these reasons, the priority of this standard is to support new code development using<br />

C11 and the post-C11 technical reports that have not been incorporated into the C <strong>Standard</strong>. A<br />

close-second priority is supporting remediation of old code using C99 and the technical reports.<br />

This coding standard does make contributions to support older compilers when these contributions<br />

can be significant and doing so does not compromise other priorities. The intent is not to<br />

capture all deviations from the standard but to capture only a few important ones.<br />

1.1.2 Issues Not Addressed<br />

A number of issues are not addressed by this secure coding standard.<br />

1.1.2.1 <strong>Coding</strong> Style<br />

<strong>Coding</strong> style issues are subjective, and it has proven impossible to develop a consensus on appropriate<br />

style guidelines. Consequently, the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> does not require the<br />

enforcement of any particular coding style but only suggests that development organizations define<br />

or adopt style guidelines and apply these guidelines consistently. The easiest way to apply a<br />

coding style consistently is to use a code-formatting tool. Many interactive development environments<br />

(IDEs) provide such capabilities.<br />

1.1.2.2 Controversial Rules<br />

In general, the <strong>CERT</strong> coding standards try to avoid the inclusion of controversial rules that lack a<br />

broad consensus.<br />

1.2 Audience<br />

The <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> is primarily intended for developers of C language programs<br />

but may also be used by software acquirers to define the requirements for software. The<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 3<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - History<br />

standard is of particular interest to developers who are building high-quality systems that are reliable,<br />

robust, and resistant to attack.<br />

While not intended for C++ programmers, the standard may also be of some value to these developers<br />

because the vast majority of issues identified for C language programs are also issues in<br />

C++ programs, although in many cases the solutions are different.<br />

1.3 History<br />

The idea of a <strong>CERT</strong> secure coding standard arose at the Spring 2006 meeting of the C <strong>Standard</strong>s<br />

Committee (more formally, ISO/IEC JTC1/SC22/WG14) in Berlin, Germany [Seacord 2013a].<br />

The C <strong>Standard</strong> is an authoritative document, but its audience is primarily compiler implementers,<br />

and, as noted by many, its language is obscure and often impenetrable. A secure coding standard<br />

would be targeted primarily toward C language programmers and would provide actionable guidance<br />

on how to code securely in the language.<br />

The <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> was developed on the <strong>CERT</strong> Secure <strong>Coding</strong> wiki following<br />

a community-based development process. Experts from the community, including members of the<br />

WG14 C <strong>Standard</strong>s Committee, were invited to contribute and were provided with edit privileges<br />

on the wiki. Members of the community can register for a free account on the wiki to comment on<br />

the coding standards and individual rules. Reviewers who provide high-quality comments are frequently<br />

extended edit privileges so they can directly contribute to the development and evolution<br />

of the coding standard. Today, the <strong>CERT</strong> Secure <strong>Coding</strong> wiki has 2,502 registered users.<br />

This wiki-based community development process has many advantages. Most important, it engages<br />

a broad group of experts to form a consensus opinion on the content of the rules. The main<br />

disadvantage of developing a secure coding standard on a wiki is that the content is constantly<br />

evolving. This instability may be acceptable if you want the latest information and are willing to<br />

entertain the possibility that a recent change has not yet been fully vetted. However, many software<br />

development organizations require a static set of rules and recommendations that they can<br />

adopt as requirements for their software development process.<br />

Toward this end, a stable snapshot of the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> was produced after<br />

two and a half years of community development and published as The <strong>CERT</strong> C Secure <strong>Coding</strong><br />

<strong>Standard</strong>. With the production of the manuscript for the book in June 2008, version 1.0 (the book)<br />

and the wiki versions of the secure coding standard began to diverge. A second snapshot was<br />

taken in December 2013 and was published in April 2014 as The <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>, second<br />

edition. The wiki had become so comprehensive by this time that only the rules were included<br />

in the second edition of the book. A third snapshot was taken in March 2016 and published in<br />

June 2016 as <strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>, 2016 edition, as a downloadable PDF document.<br />

The <strong>CERT</strong> C secure coding guidelines were first reviewed by WG14 at the London meeting in<br />

April 2007 and again at the Kona, Hawaii, meeting in August 2007.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 4<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - ISO/IEC TS 17961 C Secure <strong>Coding</strong> Rules<br />

The topic of whether INCITS PL22.11 should submit the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> to<br />

WG14 as a candidate for publication as a type 2 or type 3 technical report was discussed at the<br />

J11/U.S. TAG Meeting, April 15, 2008, as reported in the minutes. J11 is now Task Group<br />

PL22.11, Programming Language C, and this technical committee is the U.S. Technical Advisory<br />

Group to ISO/IEC JTC 1 SC22/WG14.<br />

A straw poll was taken on the question, “Who has time to work on this project?” for which the<br />

vote was 4 (has time) to 12 (has no time). Some of the feedback we received afterwards was that<br />

although the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> was a strong set of guidelines that had been developed<br />

with input from many of the technical experts at WG14 and had been reviewed by WG14 on<br />

several occasions, WG14 was not normally in the business of “blessing” guidance to developers.<br />

However, WG14 was certainly in the business of defining normative requirements for tools such<br />

as compilers.<br />

Armed with this knowledge, we proposed that WG14 establish a study group to consider the problem<br />

of producing analyzable secure coding guidelines for the C language. The study group first<br />

met on October 27, 2009. <strong>CERT</strong> contributed an automatically enforceable subset of the C secure<br />

coding rules to ISO/IEC for use in the standardization process.<br />

Participants in the study group included analyzer vendors such as Coverity, Fortify, GammaTech,<br />

Gimpel, Klocwork, and LDRA; security experts; language experts; and consumers. A new work<br />

item to develop and publish ISO/IEC TS 17961, C Secure <strong>Coding</strong> Rules, was approved for WG14<br />

in March 2012, and the study group concluded. Roberto Bagnara, the Italian National Body representative<br />

to WG 14, later joined the WG14 editorial committee. ISO/IEC TS 17961:2013(E), Information<br />

Technology—Programming Languages, Their Environments and System Software Interfaces—C<br />

Secure <strong>Coding</strong> Rules [ISO/IEC TS 17961:2013] was officially published in<br />

November 2013 and is available for purchase at the ISO store.<br />

The <strong>CERT</strong> Secure <strong>Coding</strong> wiki contains ongoing updates of the standard between official published<br />

releases. If you are interested in contributing to the rules, create an account on the wiki and<br />

then request contributor privileges by sending a request to info@sei.cmu.edu.<br />

The Secure <strong>Coding</strong> eNewsletter contains news from the <strong>CERT</strong> Secure <strong>Coding</strong> Initiative as well as<br />

summaries of recent updates to the standard rules. If you are interested in getting updates, subscribe<br />

to the eNewsletter through our website or by sending a request to info@sei.cmu.edu.<br />

1.4 ISO/IEC TS 17961 C Secure <strong>Coding</strong> Rules<br />

The purpose of ISO/IEC TS 17961 [ISO/IEC TS 17961:2013] is to establish a baseline set of requirements<br />

for analyzers, including static analysis tools and C language compilers, to be applied<br />

by vendors that wish to diagnose insecure code beyond the requirements of the language standard.<br />

All rules are meant to be enforceable by static analysis. The criterion for selecting these rules is<br />

that analyzers that implement these rules must be able to effectively discover secure coding errors<br />

without generating excessive false positives.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 5<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - ISO/IEC TS 17961 C Secure <strong>Coding</strong> Rules<br />

To date, the application of static analysis to security has been performed in an ad-hoc manner by<br />

different vendors, resulting in non-uniform coverage of significant security issues. ISO/IEC TS<br />

17961 enumerates secure coding rules and requires analysis engines to diagnose violations of<br />

these rules as a matter of conformance to the specification [ISO/IEC TS 17961:2013]. These rules<br />

may be extended in an implementation-dependent manner, which provides a minimum coverage<br />

guarantee to customers of any and all conforming static analysis implementations.<br />

ISO/IEC TS 17961 specifies rules for secure coding in the C programming language and includes<br />

code examples for each rule. Noncompliant code examples demonstrate language constructs that<br />

have weaknesses with potentially exploitable security implications; such examples are expected to<br />

elicit a diagnostic from a conforming analyzer for the affected language construct. Compliant examples<br />

are expected not to elicit a diagnostic. ISO/IEC TS 17961 does not specify the mechanism<br />

by which these rules are enforced or any particular coding style to be enforced [ISO/IEC TS<br />

17961:2013].<br />

The following table shows how ISO/IEC TS 17961 relates to other standards and guidelines. Of<br />

the publications listed, ISO/IEC TS 17961 is the only one for which the immediate audience is analyzers<br />

and not developers.<br />

ISO/IEC TS 17961 Compared with Other <strong>Standard</strong>s<br />

<strong>Coding</strong><br />

<strong>Standard</strong><br />

C <strong>Standard</strong><br />

Security<br />

<strong>Standard</strong><br />

Safety<br />

<strong>Standard</strong><br />

International<br />

<strong>Standard</strong><br />

CWE None/all Yes No No N/A<br />

MISRA C2 C89 No Yes No No<br />

MISRA C3 C99 No Yes No No<br />

<strong>CERT</strong> C99 C99 Yes No No Yes<br />

<strong>CERT</strong> C11 C11 Yes Yes No Yes<br />

ISO/IEC TS<br />

17961<br />

C11 Yes No Yes Yes<br />

Whole<br />

Language<br />

A conforming analyzer must be capable of producing a diagnostic for each distinct rule in the<br />

technical specification upon detecting a violation of that rule in isolation. If the same program text<br />

violates multiple rules simultaneously, a conforming analyzer may aggregate diagnostics but must<br />

produce at least one diagnostic. The diagnostic message might be of the form<br />

Accessing freed memory in function abc, file xyz.c, line nnn.<br />

ISO/IEC TS 17961 does not require an analyzer to produce a diagnostic message for any violation<br />

of any syntax rule or constraint specified by the C <strong>Standard</strong> [ISO/IEC TS 17961:2013]. Conformance<br />

is defined only with respect to source code that is visible to the analyzer. Binary-only libraries,<br />

and calls to them, are outside the scope of these rules.<br />

An interesting aspect of the technical specification is the portability assumptions, known within<br />

the group as the “San Francisco rule” because the assumptions evolved at a meeting hosted by<br />

Coverity at its headquarters. The San Francisco rule states that a conforming analyzer must be<br />

able to diagnose violations of guidelines for at least one C implementation but does not need to<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 6<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Tool Selection and Validation<br />

diagnose a rule violation if the result is documented for the target implementation and does not<br />

cause a security flaw. Variations in quality of implementation permit an analyzer to produce diagnostics<br />

concerning portability issues. For example, the following program fragment can produce a<br />

diagnostic, such as the mismatch between %d and long int:<br />

long i; printf ("i = %d", i);<br />

This mismatch might not be a problem for all target implementations, but it is a portability problem<br />

because not all implementations have the same representation for int and long.<br />

In addition to other goals already stated, the <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong> has been updated for consistency<br />

with ISO/IEC TS 17961. Although the documents serve different audiences, consistency<br />

between the documents should improve the ability of developers to use ISO/IEC TS 17961–conforming<br />

analyzers to find violations of rules from this coding standard. The Secure <strong>Coding</strong> Validation<br />

Suite is a set of tests developed by <strong>CERT</strong> to validate the rules defined in ISO/IEC TS<br />

17961. These tests are based on the examples in this technical specification and are distributed<br />

with a BSD-style license.<br />

1.5 Tool Selection and Validation<br />

Although rule checking can be performed manually, with increasing program size and complexity,<br />

it rapidly becomes infeasible. For this reason, the use of static analysis tools is recommended.<br />

When choosing a compiler (which should be understood to include the linker), a C-compliant<br />

compiler should be used whenever possible. A conforming implementation will produce at least<br />

one diagnostic message if a preprocessing translation unit or translation unit contains a violation<br />

of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or<br />

implementation-defined. It is also likely that any analyzers you may use assume a C-compliant<br />

compiler.<br />

When choosing a source code analysis tool, it is clearly desirable that the tool be able to enforce<br />

as many of the guidelines on the wiki as possible. Not all recommendations are enforceable; some<br />

are strictly meant to be informative.<br />

Although <strong>CERT</strong> recommends the use of an ISO/IEC TS 17961–conforming analyzer, the Software<br />

Engineering Institute, as a federally funded research and development center (FFRDC), is<br />

not in a position to endorse any particular vendor or tool. Vendors are encouraged to develop conforming<br />

analyzers, and users of this coding standard are free to evaluate and select whichever analyzers<br />

best suit their purposes.<br />

1.5.1 Completeness and Soundness<br />

It should be recognized that, in general, determining conformance to coding rules and recommendations<br />

is computationally undecidable. The precision of static analysis has practical limitations.<br />

For example, the halting theorem of computer science states that programs exist in which exact<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 7<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Tool Selection and Validation<br />

control flow cannot be determined statically. Consequently, any property dependent on control<br />

flow—such as halting—may be indeterminate for some programs. A consequence of undecidability<br />

is that it may be impossible for any tool to determine statically whether a given guideline is<br />

satisfied in specific circumstances. The widespread presence of such code may also lead to unexpected<br />

results from an analysis tool.<br />

Regardless of how checking is performed, the analysis may generate<br />

• False negatives: Failure to report a real flaw in the code is usually regarded as the most serious<br />

analysis error, as it may leave the user with a false sense of security. Most tools err on the<br />

side of caution and consequently generate false positives. However, in some cases, it may be<br />

deemed better to report some high-risk flaws and miss others than to overwhelm the user with<br />

false positives.<br />

• False positives: The tool reports a flaw when one does not exist. False positives may occur<br />

because the code is too complex for the tool to perform a complete analysis. The use of features<br />

such as function pointers and libraries may make false positives more likely.<br />

To the greatest extent feasible, an analyzer should be both complete and sound with respect to enforceable<br />

guidelines. An analyzer is considered sound with respect to a specific guideline if it cannot<br />

give a false-negative result, meaning it finds all violations of the guideline within the entire<br />

program. An analyzer is considered complete if it cannot issue false-positive results, or false<br />

alarms. The possibilities for a given guideline are outlined in the following figure.<br />

False Positives<br />

Y<br />

N<br />

False Negatives<br />

N<br />

Y<br />

Complete<br />

with False<br />

Positives<br />

Incomplete<br />

with False<br />

Positives<br />

Complete<br />

and Sound<br />

Incomplete<br />

Compilers and source code analysis tools are trusted processes, meaning that a degree of reliance<br />

is placed on the output of the tools. Accordingly, developers must ensure that this trust is not misplaced.<br />

Ideally, trust should be achieved by the tool supplier running appropriate validation tests<br />

such as the Secure <strong>Coding</strong> Validation Suite.<br />

1.5.2 False Positives<br />

Although many guidelines list common exceptions, it is difficult if not impossible to develop a<br />

complete list of exceptions for each guideline. Consequently, it is important that source code complies<br />

with the intent of each guideline and that tools, to the greatest extent possible, minimize<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 8<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Taint Analysis<br />

false positives that do not violate the intent of the guideline. The degree to which tools minimize<br />

false-positive diagnostics is a quality-of-implementation issue.<br />

1.6 Taint Analysis<br />

1.6.1 Taint and Tainted Sources<br />

Certain operations and functions have a domain that is a subset of the type domain of their operands<br />

or parameters. When the actual values are outside of the defined domain, the result might be<br />

undefined or at least unexpected. If the value of an operand or argument may be outside the domain<br />

of an operation or function that consumes that value, and the value is derived from any external<br />

input to the program (such as a command-line argument, data returned from a system call,<br />

or data in shared memory), that value is tainted, and its origin is known as a tainted source. A<br />

tainted value is not necessarily known to be out of the domain; rather, it is not known to be in the<br />

domain. Only values, and not the operands or arguments, can be tainted; in some cases, the same<br />

operand or argument can hold tainted or untainted values along different paths. In this regard,<br />

taint is an attribute of a value that is assigned to any value originating from a tainted source.<br />

1.6.2 Restricted Sinks<br />

Operands and arguments whose domain is a subset of the domain described by their types are<br />

called restricted sinks. Any integer operand used in a pointer arithmetic operation is a restricted<br />

sink for that operand. Certain parameters of certain library functions are restricted sinks because<br />

these functions perform address arithmetic with these parameters, or control the allocation of a resource,<br />

or pass these parameters on to another restricted sink. All string input parameters to library<br />

functions are restricted sinks because it is possible to pass in a character sequence that is not<br />

null terminated. The exceptions are input parameters to strncpy() and strncpy_s(), which<br />

explicitly allow the source character sequence not to be null terminated.<br />

1.6.3 Propagation<br />

Taint is propagated through operations from operands to results unless the operation itself imposes<br />

constraints on the value of its result that subsume the constraints imposed by restricted<br />

sinks. In addition to operations that propagate the same sort of taint, there are operations that<br />

propagate taint of one sort of an operand to taint of a different sort for their results, the most notable<br />

example of which is strlen() propagating the taint of its argument with respect to string<br />

length to the taint of its return value with respect to range. Although the exit condition of a loop is<br />

not normally considered to be a restricted sink, a loop whose exit condition depends on a tainted<br />

value propagates taint to any numeric or pointer variables that are increased or decreased by<br />

amounts proportional to the number of iterations of the loop.<br />

1.6.4 Sanitization<br />

To remove the taint from a value, the value must be sanitized to ensure that it is in the defined domain<br />

of any restricted sink into which it flows. Sanitization is performed by replacement or termination.<br />

In replacement, out-of-domain values are replaced by in-domain values, and processing<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 9<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Rules Versus Recommendations<br />

continues using an in-domain value in place of the original. In termination, the program logic terminates<br />

the path of execution when an out-of-domain value is detected, often simply by branching<br />

around whatever code would have used the value.<br />

In general, sanitization cannot be recognized exactly using static analysis. Analyzers that perform<br />

taint analysis usually provide some extralinguistic mechanism to identify sanitizing functions that<br />

sanitize an argument (passed by address) in place, return a sanitized version of an argument, or<br />

return a status code indicating whether the argument is in the required domain. Because such extralinguistic<br />

mechanisms are outside the scope of this coding standard, we use a set of rudimentary<br />

definitions of sanitization that is likely to recognize real sanitization but might cause nonsanitizing<br />

or ineffectively sanitizing code to be misconstrued as sanitizing.<br />

The following definition of sanitization presupposes that the analysis is in some way maintaining<br />

a set of constraints on each value encountered as the simulated execution progresses: a given path<br />

through the code sanitizes a value with respect to a given restricted sink if it restricts the range of<br />

that value to a subset of the defined domain of the restricted sink type. For example, sanitization<br />

of signed integers with respect to an array index operation must restrict the range of that integer<br />

value to numbers between zero and the size of the array minus one.<br />

This description is suitable for numeric values, but sanitization of strings with respect to content is<br />

more difficult to recognize in a general way.<br />

1.7 Rules Versus Recommendations<br />

This coding standard contains 99 coding rules. The <strong>CERT</strong> <strong>Coding</strong> <strong>Standard</strong>s wiki also has 185<br />

recommendations at the time of this writing. Rules are meant to provide normative requirements<br />

for code; recommendations are meant to provide guidance that, when followed, should improve<br />

the safety, reliability, and security of software systems. However, a violation of a recommendation<br />

does not necessarily indicate the presence of a defect in the code. Rules and recommendations<br />

are collectively referred to as guidelines.<br />

The wiki also contains two platform-specific annexes at the time of this writing; one annex is for<br />

POSIX and the other one is for Windows. These annexes have been omitted from this standard<br />

because they are not part of the core standard.<br />

This standard is based on the C rules available on the <strong>CERT</strong> Secure <strong>Coding</strong> wiki as of 30 March<br />

2016.<br />

1.7.1 Rules<br />

Rules must meet the following criteria:<br />

1. Violation of the guideline is likely to result in a defect that may adversely affect the safety,<br />

reliability, or security of a system, for example, by introducing a security flaw that may result<br />

in an exploitable vulnerability.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 10<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Conformance Testing<br />

2. The guideline does not rely on source code annotations or assumptions.<br />

3. Conformance to the guideline can be determined through automated analysis (either static or<br />

dynamic), formal methods, or manual inspection techniques.<br />

1.7.2 Recommendations<br />

Recommendations are suggestions for improving code quality. Guidelines are defined to be recommendations<br />

when all of the following conditions are met:<br />

1. Application of a guideline is likely to improve the safety, reliability, or security of software<br />

systems.<br />

2. One or more of the requirements necessary for a guideline to be considered a rule cannot be<br />

met.<br />

The set of recommendations that a particular development effort adopts depends on the requirements<br />

of the final software product. Projects with stricter requirements may decide to dedicate<br />

more resources to ensuring the safety, reliability, and security of a system and consequently are<br />

likely to adopt a broader set of recommendations.<br />

1.8 Conformance Testing<br />

To ensure that the source code conforms to this coding standard, it is necessary to have measures<br />

in place that check for rule violations. The most effective means of achieving this goal is to use<br />

one or more ISO/IEC TS 17961–conforming analyzers. Where a guideline cannot be checked by a<br />

tool, a manual review is required.<br />

The Source Code Analysis Laboratory (SCALe) provides a means for evaluating the conformance<br />

of software systems against this and other coding standards. <strong>CERT</strong> coding standards provide a<br />

normative set of rules against which software systems can be evaluated. Conforming software<br />

systems should demonstrate improvements in the safety, reliability, and security over nonconforming<br />

systems.<br />

The SCALe team at <strong>CERT</strong> analyzes a developer’s source code and provides a detailed report of<br />

findings to guide the code’s repair. After the developer has addressed these findings and the<br />

SCALe team determines that the product version conforms to the standard, <strong>CERT</strong> issues the developer<br />

a certificate and lists the system in a registry of conforming systems.<br />

1.8.1 Conformance<br />

Conformance to the <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong> requires that the code not contain any violations of<br />

the rules specified in this standard. If an exceptional condition is claimed, the exception must correspond<br />

to a predefined exceptional condition, and the application of this exception must be documented<br />

in the source code. Conformance with the recommendations on the wiki is not necessary<br />

to claim conformance with the <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>. Conformance to the recommendations<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 11<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Development Process<br />

will, in many cases, make it easier to conform to the rules, eliminating many potential sources of<br />

defects.<br />

1.8.2 Levels<br />

Rules and recommendations in this standard are classified into three levels (see How this <strong>Coding</strong><br />

<strong>Standard</strong> is Organized). Emphasis should be placed on conformance Level 1 (L1) rules. Software<br />

systems that have been validated as complying with all Level 1 rules are considered to be L1 conforming.<br />

Software systems can be assessed as L1, L2, or fully conforming, depending on the set<br />

of rules to which the system has been validated.<br />

1.8.3 Deviation Procedure<br />

Strict adherence to all rules is unlikely and, consequently, deviations associated with specific rule<br />

violations are necessary. Deviations can be used in cases where a true-positive finding is uncontested<br />

as a rule violation but the code is nonetheless determined to be correct. An uncontested<br />

true-positive finding may be the result of a design or architecture feature of the software or may<br />

occur for a valid reason that was unanticipated by the coding standard. In this respect, the deviation<br />

procedure allows for the possibility that coding rules are overly strict [Seacord 2013].<br />

Deviations are not granted for reasons of performance or usability. A software system that successfully<br />

passes conformance testing must not contain defects or exploitable vulnerabilities. Deviation<br />

requests are evaluated by the lead assessor, and if the developer can provide sufficient evidence<br />

that the deviation will not result in a vulnerability, the deviation request is accepted.<br />

Deviations are used infrequently because it is almost always easier to fix a coding error than it is<br />

to provide an argument that the coding error does not result in a vulnerability.<br />

1.9 Development Process<br />

The development of a coding standard for any programming language is a difficult undertaking<br />

that requires significant community involvement. The following development process has been<br />

used to create this standard:<br />

1. Rules and recommendations for a coding standard are solicited from the communities involved<br />

in the development and application of each programming language, including the formal<br />

or de facto standards bodies responsible for the documented standard.<br />

2. These rules and recommendations are edited by members of the <strong>CERT</strong> technical staff for<br />

content and style and placed on the <strong>CERT</strong> Secure <strong>Coding</strong> <strong>Standard</strong>s website for comment<br />

and review.<br />

3. The user community may then comment on the publicly posted content using threaded discussions<br />

and other communication tools. Once a consensus develops that the rule or recommendation<br />

is appropriate and correct, the final rule is incorporated into an officially released<br />

version of the secure coding standard.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 12<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Usage<br />

Early drafts of the <strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong> have been reviewed by the ISO/IEC<br />

JTC1/SC22/WG14 international standardization working group for the C programming language<br />

and by other industry groups as appropriate.<br />

1.10 Usage<br />

The rules in this standard may be extended with organization-specific rules. However, the rules in<br />

the standard must be obeyed to claim conformance with the standard.<br />

Training may be developed to educate software professionals regarding the appropriate application<br />

of coding standards. After passing an examination, these trained programmers may also be<br />

certified as coding professionals. For example, the Software Developer Certification (SDC) is a<br />

credentialing program developed at Carnegie Mellon University. The SDC uses authentic examination<br />

to<br />

1. Identify job candidates with specific programming skills<br />

2. Demonstrate the presence of a well-trained software workforce<br />

3. Provide guidance to educational and training institutions<br />

Once a coding standard has been established, tools and processes can be developed or modified to<br />

determine conformance with the standard.<br />

1.11 System Qualities<br />

The goal of this coding standard is to produce safe, reliable, and secure systems. Additional requirements<br />

might exist for safety-critical systems, such as the absence of dynamic memory allocation.<br />

Other software quality attributes of interest include portability, usability, availability, maintainability,<br />

readability, and performance.<br />

Many of these attributes are interrelated in interesting ways. For example, readability is an attribute<br />

of maintainability; both are important for limiting the introduction of defects during maintenance<br />

that can result in security flaws or reliability issues. In addition, readability aids code inspection<br />

by safety officers. Reliability and availability require proper resource management,<br />

which also contributes to the safety and security of the system. System attributes such as performance<br />

and security are often in conflict, requiring trade-offs to be considered.<br />

1.12 Vulnerability Metric<br />

The <strong>CERT</strong> vulnerability metric value is a number between 0 and 180 that assigns an approximate<br />

severity to the vulnerability. This number considers several factors:<br />

• Is information about the vulnerability widely available or known?<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 13<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - How This <strong>Coding</strong> <strong>Standard</strong> Is Organized<br />

• Is the vulnerability being exploited in incidents reported to <strong>CERT</strong> or other incident response<br />

teams?<br />

• Is the Internet infrastructure (for example, routers, name servers, critical Internet protocols) at<br />

risk because of this vulnerability?<br />

• How many systems on the Internet are at risk from this vulnerability?<br />

• What is the impact of exploiting the vulnerability?<br />

• How easy is it to exploit the vulnerability?<br />

• What are the preconditions required to exploit the vulnerability?<br />

Because the questions are answered with approximate values based on our own judgments and<br />

may differ significantly from one site to another, readers should not rely too heavily on the metric<br />

for prioritizing their response to vulnerabilities. Rather, this metric may be useful for separating<br />

the serious vulnerabilities from the larger number of less severe vulnerabilities described in the<br />

database. Because the questions are not all weighted equally, the resulting score is not linear; that<br />

is, a vulnerability with a metric of 40 is not twice as severe as one with a metric of 20.<br />

An alternative vulnerability severity metric is the Common Vulnerability Scoring System<br />

(CVSS).<br />

1.13 How This <strong>Coding</strong> <strong>Standard</strong> Is Organized<br />

This coding standard is organized into 15 chapters containing rules in specific topic areas followed<br />

by four appendices. Appendix A contains the bibliography. Appendix B lists the definitions<br />

of terms used throughout the standard. Appendix C lists the undefined behaviors from the C<br />

<strong>Standard</strong>, Annex J, J.2 [ISO/IEC 9899:2011], numbered and classified for easy reference. These<br />

numbered undefined behaviors are referenced frequently from the rules. Appendix D lists unspecified<br />

behaviors from the C <strong>Standard</strong>, Annex J, J.2 [ISO/IEC 9899:2011]. These unspecified behaviors<br />

are occasionally referenced from the rules as well.<br />

Most rules have a consistent structure. Each rule in this standard has a unique identifier, which is<br />

included in the title. The title and the introductory paragraphs define the rule and are typically followed<br />

by one or more pairs of noncompliant code examples and compliant solutions. Each rule<br />

also includes a risk assessment, related guidelines, and a bibliography (where applicable). Rules<br />

may also include a table of related vulnerabilities. The recommendations on the <strong>CERT</strong> <strong>Coding</strong><br />

<strong>Standard</strong>s wiki are organized in a similar fashion.<br />

1.13.1 Identifiers<br />

Each rule and recommendation is given a unique identifier. These identifiers consist of three<br />

parts:<br />

• A three-letter mnemonic representing the section of the standard<br />

• A two-digit numeric value in the range of 00 to 99<br />

• The letter C indicating that this is a C language guideline<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 14<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - How This <strong>Coding</strong> <strong>Standard</strong> Is Organized<br />

The three-letter mnemonic can be used to group similar coding practices and to indicate which<br />

category a coding practice belongs to.<br />

The numeric value is used to give each coding practice a unique identifier. Numeric values in the<br />

range of 00 to 29 are reserved for recommendations, and values in the range of 30 to 99 are reserved<br />

for rules. Rules and recommendations are frequently referenced from the rules in this<br />

standard by their identifier and title. Rules can be found in this standard’s table of contents,<br />

whereas recommendations can be found only on the wiki.<br />

1.13.2 Noncompliant Code Examples and Compliant Solutions<br />

Noncompliant code examples illustrate code that violates the guideline under discussion. It is important<br />

to note that these are only examples, and eliminating all occurrences of the example does<br />

not necessarily mean that the code being analyzed is now compliant with the guideline.<br />

Noncompliant code examples are typically followed by compliant solutions, which show how the<br />

noncompliant code example can be recoded in a secure, compliant manner. Except where noted,<br />

noncompliant code examples should contain violations only of the guideline under discussion.<br />

Compliant solutions should comply with all of the secure coding rules but may on occasion fail to<br />

comply with a recommendation.<br />

1.13.3 Exceptions<br />

Any rule or recommendation may specify a small set of exceptions detailing the circumstances<br />

under which the guideline is not necessary to ensure the safety, reliability, or security of software.<br />

Exceptions are informative only and are not required to be followed.<br />

1.13.4 Risk Assessment<br />

Each guideline in the <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong> contains a risk assessment section that attempts to<br />

provide software developers with an indication of the potential consequences of not addressing a<br />

particular rule or recommendation in their code (along with some indication of expected remediation<br />

costs). This information may be used to prioritize the repair of rule violations by a development<br />

team. The metric is designed primarily for remediation projects. It is generally assumed that<br />

new code will be developed to be compliant with the entire coding standard and applicable recommendations.<br />

Each rule and recommendation has an assigned priority. Priorities are assigned using a metric<br />

based on Failure Mode, Effects, and Criticality Analysis (FMECA) [IEC 60812]. Three values are<br />

assigned for each rule on a scale of 1 to 3 for severity, likelihood, and remediation cost.<br />

Severity—How serious are the consequences of the rule being ignored?<br />

Value Meaning Examples of Vulnerability<br />

1 Low Denial-of-service attack, abnormal<br />

termination<br />

2 Medium Data integrity violation, unintentional<br />

information disclosure<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 15<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - How This <strong>Coding</strong> <strong>Standard</strong> Is Organized<br />

3 High Run arbitrary code<br />

Likelihood—How likely is it that a flaw introduced by ignoring the rule can lead to an exploitable<br />

vulnerability?<br />

Value<br />

Meaning<br />

1 Unlikely<br />

2 Probable<br />

3 Likely<br />

Remediation Cost—How expensive is it to comply with the rule?<br />

Value Meaning Detection Correction<br />

1 High Manual Manual<br />

2 Medium Automatic Manual<br />

3 Low Automatic Automatic<br />

The three values are then multiplied together for each rule. This product provides a measure that<br />

can be used in prioritizing the application of the rules. The products range from 1 to 27, although<br />

only the following 10 distinct values are possible: 1, 2, 3, 4, 6, 8, 9, 12, 18, and 27. Rules and recommendations<br />

with a priority in the range of 1 to 4 are Level 3 rules, 6 to 9 are Level 2, and 12 to<br />

27 are Level 1. The following are possible interpretations of the priorities and levels.<br />

Priorities and Levels<br />

Level Priorities Possible Interpretation<br />

L1 12, 18, 27 High severity, likely, inexpensive<br />

to repair<br />

L2 6, 8, 9 Medium severity, probable, medium<br />

cost to repair<br />

L3 1, 2, 3, 4 Low severity, unlikely, expensive<br />

to repair<br />

Specific projects may begin remediation by implementing all rules at a particular level before proceeding<br />

to the lower priority rules, as shown in the following illustration.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 16<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - How This <strong>Coding</strong> <strong>Standard</strong> Is Organized<br />

Recommendations are not compulsory and are provided for information purposes only.<br />

1.13.5 Automated Detection<br />

On the wiki, both rules and recommendations frequently have sections that describe automated<br />

detection. These sections provide additional information on analyzers that can automatically diagnose<br />

violations of coding guidelines. Most automated analyses for the C programming language<br />

are neither sound nor complete, so the inclusion of a tool in this section typically means that the<br />

tool can diagnose some violations of this particular rule. Although the Secure <strong>Coding</strong> Validation<br />

Suite can be used to test the ability of analyzers to diagnose violations of rules from ISO/IEC TS<br />

19761, no currently available conformance test suite can assess the ability of analyzers to diagnose<br />

violations of the rules in this standard. Consequently, the information in automated detection<br />

sections on the wiki may be<br />

• Provided by the vendors<br />

• Determined by <strong>CERT</strong> by informally evaluating the analyzer<br />

• Determined by <strong>CERT</strong> by reviewing the vendor documentation<br />

Where possible, we try to reference the exact version of the tool for which the results were obtained.<br />

Because these tools evolve continuously, this information can rapidly become dated and<br />

obsolete.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 17<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Automatically Generated Code<br />

1.13.6 Related Vulnerabilities<br />

The risk assessment sections on the wiki also contain a link to search for related vulnerabilities on<br />

the <strong>CERT</strong> website. Whenever possible, <strong>CERT</strong> Vulnerability Notes are tagged with a keyword corresponding<br />

to the unique ID of the coding guideline. This search provides you with an up-to-date<br />

list of real-world vulnerabilities that have been determined to be at least partially caused by a violation<br />

of this specific guideline. These vulnerabilities are labeled as such only when the vulnerability<br />

analysis team at the <strong>CERT</strong>/CC is able to evaluate the source code and precisely determine<br />

the cause of the vulnerability. Because many vulnerability notes refer to vulnerabilities in closedsource<br />

software systems, it is not always possible to provide this additional analysis. Consequently,<br />

the related vulnerabilities field tends to be somewhat sparsely populated.<br />

Related vulnerability sections are included only for specific rules in this standard, when the information<br />

is both relevant and interesting.<br />

1.13.7 Related Guidelines<br />

The related guidelines sections contain links to guidelines in related standards, technical specifications,<br />

and guideline collections such as Information Technology—Programming Languages, Their<br />

Environments and System Software Interfaces—C Secure <strong>Coding</strong> Rules [ISO/IEC TS<br />

17961:2013]; Information Technology—Programming Languages—Guidance to Avoiding Vulnerabilities<br />

in Programming Languages through Language Selection and Use [ISO/IEC TR<br />

24772:2013]; MISRA C 2012: Guidelines for the Use of the C Language in Critical Systems<br />

[MISRA C:2012]; and CWE IDs in MITRE’s Common Weakness Enumeration (CWE) [MITRE<br />

2010].<br />

You can create a unique URL to get more information on CWEs by appending the relevant ID to<br />

the end of a fixed string. For example, to find more information about CWE-192, Integer Coercion<br />

Error,” you can append 192.html to http://cwe.mitre.org/data/definitions/ and enter the resulting<br />

URL in your browser: http://cwe.mitre.org/data/definitions/192.html.<br />

The other referenced technical specifications, technical reports, and guidelines are commercially<br />

available.<br />

1.13.8 Bibliography<br />

Most guidelines have a small bibliography section that lists documents and section in those documents<br />

that provide information relevant to the rule.<br />

1.14 Automatically Generated Code<br />

If a code-generating tool is to be used, it is necessary to select an appropriate tool and undertake<br />

validation. Adherence to the requirements of this document may provide one criterion for assessing<br />

a tool.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 18<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Government Regulations<br />

<strong>Coding</strong> guidance varies depending on how code is generated and maintained. Categories of code<br />

include the following:<br />

• Tool-generated, tool-maintained code that is specified and maintained in a higher level format<br />

from which language-specific source code is generated. The source code is generated from<br />

this higher level description and then provided as input to the language compiler. The generated<br />

source code is never viewed or modified by the programmer.<br />

• Tool-generated, hand-maintained code that is specified and maintained in a higher level format<br />

from which language-specific source code is generated. It is expected or anticipated,<br />

however, that at some point in the development cycle, the tool will cease to be used and the<br />

generated source code will be visually inspected and/or manually modified and maintained.<br />

• Hand-coded code is manually written by a programmer using a text editor or interactive development<br />

environment; the programmer maintains source code directly in the source-code<br />

format provided to the compiler.<br />

Source code that is written and maintained by hand must have the following properties:<br />

• Readability<br />

• Program comprehension<br />

These requirements are not applicable for source code that is never directly handled by a programmer,<br />

although requirements for correct behavior still apply. Reading and comprehension requirements<br />

apply to code that is tool generated and hand maintained but do not apply to code that is<br />

tool generated and tool maintained. Tool-generated, tool-maintained code can impose consistent<br />

constraints that ensure the safety of some constructs that are risky in hand-generated code.<br />

1.15 Government Regulations<br />

Developing software to secure coding rules is a good idea and is increasingly a requirement. The<br />

National Defense Authorization Act for Fiscal Year 2013, Section 933, “Improvements in Assurance<br />

of Computer Software Procured by the Department of Defense,” requires evidence that government<br />

software development and maintenance organizations and contractors are conforming in<br />

computer software coding to approved secure coding standards of the Department of Defense<br />

(DoD) during software development, upgrade, and maintenance activities, including through the<br />

use of inspection and appraisals.<br />

DoD acquisition programs are specifying The Application Security and Development Security<br />

Technical Implementation Guide (STIG), Version 3, Release 10 [DISA 2015] in requests for proposal<br />

(RFPs). Section 2.1.5, “<strong>Coding</strong> <strong>Standard</strong>s,” requires that “the Program Manager will ensure<br />

the development team follows a set of coding standards.”<br />

The proper application of this standard would enable a system to comply with the following requirements<br />

from the Application Security and Development Security Technical Implementation<br />

Guide, Version 3, Release 10 [DISA 2015]:<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 19<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Acknowledgments<br />

• (APP2060.1: CAT II) The Program Manager will ensure the development team follows a set<br />

of coding standards.<br />

• (APP2060.2: CAT II) The Program Manager will ensure the development team creates a list<br />

of unsafe functions to avoid and document this list in the coding standards.<br />

• (APP3550: CAT I) The Designer will ensure the application is not vulnerable to integer<br />

arithmetic issues.<br />

• (APP3560: CAT I) The Designer will ensure the application does not contain format string<br />

vulnerabilities.<br />

• (APP3570: CAT I) The Designer will ensure the application does not allow command injection.<br />

• (APP3590.1: CAT I) The Designer will ensure the application does not have buffer overflows.<br />

• (APP3590.2: CAT I) The Designer will ensure the application does not use functions known<br />

to be vulnerable to buffer overflows.<br />

• (APP3590.3: CAT II) The Designer will ensure the application does not use signed values<br />

for memory allocation where permitted by the programming language.<br />

• (APP3600: CAT II) The Designer will ensure the application has no canonical representation<br />

vulnerabilities.<br />

• (APP3630.1: CAT II) The Designer will ensure the application is not vulnerable to race conditions.<br />

• (APP3630.2: CAT III) The Designer will ensure the application does not use global variables<br />

when local variables could be used.<br />

Training programmers and software testers on the standard will satisfy the following requirements:<br />

• (APP2120.3: CAT II) The Program Manager will ensure developers are provided with training<br />

on secure design and coding practices on at least an annual basis.<br />

• (APP2120.4: CAT II) The Program Manager will ensure testers are provided training on at<br />

least an annual basis.<br />

• (APP2060.3: CAT II) The Designer will follow the established coding standards established<br />

for the project.<br />

• (APP2060.4: CAT II) The Designer will not use unsafe functions documented in the project<br />

coding standards.<br />

• (APP5010: CAT III) The Test Manager will ensure at least one tester is designated to test for<br />

security flaws in addition to functional testing.<br />

1.16 Acknowledgments<br />

This standard was made possible through a broad community effort. We thank all those who contributed<br />

and provided reviews on the <strong>CERT</strong> Secure <strong>Coding</strong> wiki that helped to make the standards<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 20<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Acknowledgments<br />

a success. If you are interested in contributing to the rules, create an account on the wiki and then<br />

request contributor privileges by sending email to info@sei.cmu.edu.<br />

1.16.1 Contributors to this Edition of the <strong>Standard</strong><br />

Eric Azebu, Aaron Ballman, Jill Britton, Vaclav Bubnik, G. Ann Campbell, Geoff Clare, Lori<br />

Flynn, Amy Gale, Arthur Hicken, David Keaton, Will Klieber, Masaki Kubo, Carol Lallier, Fred<br />

Long, Daniel Marjamäki, Robert Seacord, Martin Sebor, Sandy Shrum, Will Snavely, David Svoboda,<br />

Yozo Toda, Barbara White, and Liz Whiting<br />

1.16.2 Contributors and Reviewers of Previous Editions of the <strong>Standard</strong><br />

Arbob Ahmad, Juan Alvarado, Dave Aronson, Abhishek Arya, Berin Babcock-McConnell, Roberto<br />

Bagnara, Aaron Ballman, BJ Bayha, John Benito, Joe Black, Jodi Blake, Jill Britton, Levi<br />

Broderick, Hal Burch, J. L. Charton, Steven Christey, Ciera Christopher, Geoff Clare, Frank Costello,<br />

Joe Damato, Stephen C. Dewhurst, Susan Ditmore, Chad Dougherty, Mark Dowd, Apoorv<br />

Dutta, Emily Evans, Xiaoyi Fei, William Fithen, Hallvard Furuseth, Jeffrey Gennari, Andrew<br />

Gidwani, Ankur Goyal, Douglas A. Gwyn, Shaun Hedrick, Michael Howard, Sujay Jain, Christina<br />

Johns, Pranjal Jumde, David Keaton, Andrew Keeton, David Kohlbrenner, Takuya Kondo,<br />

Masaki Kubo, Pranav Kukreja, Richard Lane, Stephanie Wan-Ruey Lee, Jonathan Leffler,<br />

Pengfei Li, Fred Long, Justin Loo, Gregory K. Look, Nat Lyle, Larry Maccherone, Aditya Mahendrakar,<br />

Lee Mancuso, John McDonald, James McNellis, Randy Meyers, Dhruv Mohindra,<br />

Bhaswanth Nalabothula, Todd Nowacki, Adrian Trejo Nuñez, Bhadrinath Pani, Vishal Patel, David<br />

M. Pickett, Justin Pincar, Dan Plakosh, Thomas Plum, Abhijit Rao, Raunak Rungta, Dan<br />

Saks, Alexandre Santos, Brendan Saulsbury, Robert C. Seacord, Martin Sebor, Jason Michael<br />

Sharp, Astha Singhal, Will Snavely, Nick Stoughton, Alexander E. Strommen, Glenn Stroz, David<br />

Svoboda, Dean Sutherland, Kazunori Takeuchi, Chris Tapp, Chris Taschner, Mira Sri Divya<br />

Thambireddy, Melanie Thompson, Elpiniki Tsakalaki, Ben Tucker, Fred J. Tydeman, Abhishek<br />

Veldurthy, Wietse Venema, Alex Volkovitsky, Michael Shaye-Wen Wang, Grant Watters, Tim<br />

Wilson, Eric Wong, Lutz Wrage, Shishir Kumar Yadav, Gary Yuan, Ricky Zhou, and Alen Zukich<br />

Stefan Achatz, Arbob Ahmad, Laurent Alebarde, Kevin Bagust, Greg Beeley, Arjun Bijanki, John<br />

Bode, Konrad Borowski, Stewart Brodie, Jordan Brown, Andrew Browne, G Bulmer, Kyle<br />

Comer, Sean Connelly, Ale Contenti, Tom Danielsen, Eric Decker, Mark Dowd, T. Edwin, Brian<br />

Ewins, Justin Ferguson, William L. Fithen, Stephen Friedl, Hallvard Furuseth, Shay Green, Samium<br />

Gromoff, Kowsik Guruswamy, Jens Gustedt, Peter Gutmann, Douglas A. Gwyn, Richard<br />

Heathfield, Darryl Hill, Paul Hsieh, Ivan Jager, Steven G. Johnson, Anders Kaseorg, Matt Kraai,<br />

Piotr Krukowiecki, Jerry Leichter, Nicholas Marriott, Frank Martinez, Scott Meyers, Eric Miller,<br />

Charles-Francois Natali, Ron Natalie, Adam O’Brien, Heikki Orsila, Balog Pal, Jonathan Paulson,<br />

P.J. Plauger, Leslie Satenstein, Kirk Sayre, Neil Schellenberger, Michel Schinz, Eric Sosman,<br />

Chris Tapp, Andrey Tarasevich, Yozo Toda, Josh Triplett, Pavel Vasilyev, Ivan Vecerina, Zeljko<br />

Vrba, David Wagner, Henry S. Warren, Colin Watson, Zhenyu Wu, Drew Yao, Christopher Yeleighton,<br />

and Robin Zhu<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 21<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Introduction - Acknowledgments<br />

1.16.3 The <strong>SEI</strong> <strong>CERT</strong> Secure <strong>Coding</strong> Team<br />

Aaron Ballman, Lori Flynn, David Keaton, William Klieber, Robert Schiela, William Snavely,<br />

and David Svoboda<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 22<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE30-C. Do not create a universal character name through concatenation<br />

2 Preprocessor (PRE)<br />

2.1 PRE30-C. Do not create a universal character name through<br />

concatenation<br />

The C <strong>Standard</strong> supports universal character names that may be used in identifiers, character constants,<br />

and string literals to designate characters that are not in the basic character set. The universal<br />

character name \Unnnnnnnn designates the character whose 8-digit short identifier (as specified<br />

by ISO/IEC 10646) is nnnnnnnn. Similarly, the universal character name \unnnn designates<br />

the character whose 4-digit short identifier is nnnn (and whose 8-digit short identifier is<br />

0000nnnn).<br />

The C <strong>Standard</strong>, 5.1.1.2, paragraph 4 [ISO/IEC 9899:2011], says<br />

If a character sequence that matches the syntax of a universal character name is produced<br />

by token concatenation (6.10.3.3), the behavior is undefined.<br />

See also undefined behavior 3.<br />

In general, avoid universal character names in identifiers unless absolutely necessary.<br />

2.1.1 Noncompliant Code Example<br />

This code example is noncompliant because it produces a universal character name by token concatenation:<br />

#define assign(uc1, uc2, val) uc1##uc2 = val<br />

void func(void) {<br />

int \u0401;<br />

/* ... */<br />

assign(\u04, 01, 4);<br />

/* ... */<br />

}<br />

2.1.1.1 Implementation Details<br />

This code compiles and runs with Microsoft Visual Studio 2013, assigning 4 to the variable as expected.<br />

GCC 4.8.1 on Linux refuses to compile this code; it emits a diagnostic reading, “stray '\' in program,”<br />

referring to the universal character fragment in the invocation of the assign macro.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 23<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE30-C. Do not create a universal character name through concatenation<br />

2.1.2 Compliant Solution<br />

This compliant solution uses a universal character name but does not create it by using token concatenation:<br />

#define assign(ucn, val) ucn = val<br />

void func(void) {<br />

int \u0401;<br />

/* ... */<br />

assign(\u0401, 4);<br />

/* ... */<br />

}<br />

2.1.3 Risk Assessment<br />

Creating a universal character name through token concatenation results in undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

PRE30-C Low Unlikely Medium P2 L3<br />

2.1.4 Bibliography<br />

[ISO/IEC 10646-2003]<br />

[ISO/IEC 9899:2011]<br />

Subclause 5.1.1.2, “Translation Phases”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 24<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE31-C. Avoid side effects in arguments to unsafe macros<br />

2.2 PRE31-C. Avoid side effects in arguments to unsafe macros<br />

An unsafe function-like macro is one whose expansion results in evaluating one of its parameters<br />

more than once or not at all. Never invoke an unsafe macro with arguments containing an assignment,<br />

increment, decrement, volatile access, input/output, or other expressions with side effects<br />

(including function calls, which may cause side effects).<br />

The documentation for unsafe macros should warn against invoking them with arguments with<br />

side effects, but the responsibility is on the programmer using the macro. Because of the risks associated<br />

with their use, it is recommended that the creation of unsafe function-like macros be<br />

avoided. (See PRE00-C. Prefer inline or static functions to function-like macros.)<br />

This rule is similar to EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or<br />

_Generic.<br />

2.2.1 Noncompliant Code Example<br />

One problem with unsafe macros is side effects on macro arguments, as shown by this noncompliant<br />

code example:<br />

#define ABS(x) (((x) < 0) ? -(x) : (x))<br />

void func(int n) {<br />

/* Validate that n is within the desired range */<br />

int m = ABS(++n);<br />

}<br />

/* ... */<br />

The invocation of the ABS() macro in this example expands to<br />

m = (((++n) < 0) ? -(++n) : (++n));<br />

The resulting code is well defined but causes n to be incremented twice rather than once.<br />

2.2.2 Compliant Solution<br />

In this compliant solution, the increment operation ++n is performed before the call to the unsafe<br />

macro.<br />

#define ABS(x) (((x) < 0) ? -(x) : (x)) /* UNSAFE */<br />

void func(int n) {<br />

/* Validate that n is within the desired range */<br />

++n;<br />

int m = ABS(n);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 25<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE31-C. Avoid side effects in arguments to unsafe macros<br />

}<br />

/* ... */<br />

Note the comment warning programmers that the macro is unsafe. The macro can also be renamed<br />

ABS_UNSAFE() to make it clear that the macro is unsafe. This compliant solution, like all<br />

the compliant solutions for this rule, has undefined behavior if the argument to ABS() is equal to<br />

the minimum (most negative) value for the signed integer type. (See INT32-C. Ensure that operations<br />

on signed integers do not result in overflow for more information.)<br />

2.2.3 Compliant Solution<br />

This compliant solution follows the guidance of PRE00-C. Prefer inline or static functions to<br />

function-like macros by defining an inline function iabs() to replace the ABS() macro. Unlike<br />

the ABS() macro, which operates on operands of any type, the iabs() function will truncate arguments<br />

of types wider than int whose value is not in range of the latter type.<br />

#include <br />

#include <br />

static inline int iabs(int x) {<br />

return (((x) < 0) ? -(x) : (x));<br />

}<br />

void func(int n) {<br />

/* Validate that n is within the desired range */<br />

int m = iabs(++n);<br />

}<br />

/* ... */<br />

2.2.4 Compliant Solution<br />

A more flexible compliant solution is to declare the ABS() macro using a _Generic selection.<br />

To support all arithmetic data types, this solution also makes use of inline functions to compute<br />

integer absolute values. (See PRE00-C. Prefer inline or static functions to function-like macros<br />

and PRE12-C. Do not define unsafe macros.)<br />

According to the C <strong>Standard</strong>, 6.5.1.1, paragraph 3 [ISO/IEC 9899:2011]:<br />

The controlling expression of a generic selection is not evaluated. If a generic selection<br />

has a generic association with a type name that is compatible with the type of the controlling<br />

expression, then the result expression of the generic selection is the expression<br />

in that generic association. Otherwise, the result expression of the generic selection is<br />

the expression in the default generic association. None of the expressions from any<br />

other generic association of the generic selection is evaluated.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 26<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE31-C. Avoid side effects in arguments to unsafe macros<br />

Because the expression is not evaluated as part of the generic selection, the use of a macro in this<br />

solution is guaranteed to evaluate the macro parameter v only once.<br />

#include <br />

#include <br />

static inline long llabs(long long v) {<br />

return v < 0 ? -v : v;<br />

}<br />

static inline long labs(long v) {<br />

return v < 0 ? -v : v;<br />

}<br />

static inline int iabs(int v) {<br />

return v < 0 ? -v : v;<br />

}<br />

static inline int sabs(short v) {<br />

return v < 0 ? -v : v;<br />

}<br />

static inline int scabs(signed char v) {<br />

return v < 0 ? -v : v;<br />

}<br />

#define ABS(v) _Generic(v, signed char : scabs, \<br />

short : sabs, \<br />

int : iabs, \<br />

long : labs, \<br />

long : llabs, \<br />

float : fabsf, \<br />

double : fabs, \<br />

long double : fabsl, \<br />

double complex : cabs, \<br />

float complex : cabsf, \<br />

long double complex : cabsl)(v)<br />

void func(int n) {<br />

/* Validate that n is within the desired range */<br />

int m = ABS(++n);<br />

/* ... */<br />

}<br />

Generic selections were introduced in C11 and are not available in C99 and earlier editions of the<br />

C <strong>Standard</strong>.<br />

2.2.5 Compliant Solution (GCC)<br />

GCC’s __typeof extension makes it possible to declare and assign the value of the macro operand<br />

to a temporary of the same type and perform the computation on the temporary, consequently<br />

guaranteeing that the operand will be evaluated exactly once. Another GCC extension, known as<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 27<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE31-C. Avoid side effects in arguments to unsafe macros<br />

statement expression, makes it possible for the block statement to appear where an expression is<br />

expected:<br />

#define ABS(x) __extension__ ({ __typeof (x) tmp = x; \<br />

tmp < 0 ? -tmp : tmp; })<br />

Relying on such extensions makes code nonportable and violates MSC14-C. Do not introduce unnecessary<br />

platform dependencies.<br />

2.2.6 Noncompliant Code Example (assert())<br />

The assert() macro is a convenient mechanism for incorporating diagnostic tests in code. (See<br />

MSC11-C. Incorporate diagnostic tests using assertions.) Expressions used as arguments to the<br />

standard assert() macro should not have side effects. The behavior of the assert() macro depends<br />

on the definition of the object-like macro NDEBUG. If the macro NDEBUG is undefined, the<br />

assert() macro is defined to evaluate its expression argument and, if the result of the expression<br />

compares equal to 0, call the abort() function. If NDEBUG is defined, assert is defined to<br />

expand to ((void)0). Consequently, the expression in the assertion is not evaluated, and no side<br />

effects it may have had otherwise take place in non-debugging executions of the code.<br />

This noncompliant code example includes an assert() macro containing an expression (index++)<br />

that has a side effect:<br />

#include <br />

#include <br />

void process(size_t index) {<br />

assert(index++ > 0); /* Side effect */<br />

/* ... */<br />

}<br />

2.2.7 Compliant Solution (assert())<br />

This compliant solution avoids the possibility of side effects in assertions by moving the expression<br />

containing the side effect outside of the assert() macro.<br />

#include <br />

#include <br />

void process(size_t index) {<br />

assert(index > 0); /* No side effect */<br />

++index;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 28<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE31-C. Avoid side effects in arguments to unsafe macros<br />

}<br />

/* ... */<br />

2.2.8 Exceptions<br />

PRE31-C-EX1: An exception can be made for invoking an unsafe macro with a function call argument<br />

provided that the function has no side effects. However, it is easy to forget about obscure<br />

side effects that a function might have, especially library functions for which source code is not<br />

available; even changing errno is a side effect. Unless the function is user-written and does nothing<br />

but perform a computation and return its result without calling any other functions, it is likely<br />

that many developers will forget about some side effect. Consequently, this exception must be<br />

used with great care.<br />

2.2.9 Risk Assessment<br />

Invoking an unsafe macro with an argument that has side effects may cause those side effects to<br />

occur more than once. This practice can lead to unexpected program behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

PRE31-C Low Unlikely Low P3 L3<br />

2.2.10 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

PRE00-C. Prefer inline or static functions to<br />

function-like macros<br />

PRE12-C. Do not define unsafe macros<br />

MSC14-C. Do not introduce unnecessary platform<br />

dependencies<br />

DCL37-C. Do not declare or define a reserved<br />

identifier<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

PRE31-CPP. Avoid side-effects in arguments<br />

to unsafe macros<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java EXP06-J. Expressions used in assertions must<br />

not produce side effects<br />

ISO/IEC TR 24772:2013<br />

Pre-processor Directives [NMP]<br />

MISRA C:2012<br />

Rule 20.5 (advisory)<br />

2.2.11 Bibliography<br />

[Dewhurst 2002]<br />

Gotcha #28, “Side Effects in Assertions”<br />

[ISO/IEC 9899:2011]<br />

Subclause 6.5.1.1, “Generic Selection”<br />

[Plum 1985] Rule 1-11<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 29<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE32-C. Do not use preprocessor directives in invocations of function-like macros<br />

2.3 PRE32-C. Do not use preprocessor directives in invocations of<br />

function-like macros<br />

The arguments to a macro must not include preprocessor directives, such as #define, #ifdef,<br />

and #include. Doing so results in undefined behavior, according to the C <strong>Standard</strong>, 6.10.3, paragraph<br />

11 [ISO/IEC 9899:2011]:<br />

The sequence of preprocessing tokens bounded by the outside-most matching parentheses<br />

forms the list of arguments for the function-like macro. The individual arguments<br />

within the list are separated by comma preprocessing tokens, but comma preprocessing<br />

tokens between matching inner parentheses do not separate arguments. If there are<br />

sequences of preprocessing tokens within the list of arguments that would otherwise<br />

act as preprocessing directives, the behavior is undefined.<br />

See also undefined behavior 93.<br />

This rule also applies to the use of preprocessor directives in arguments to a function where it is<br />

unknown whether or not the function is implemented using a macro. For example, standard library<br />

functions, such as memcpy(), printf(), and assert(), may be implemented as macros.<br />

2.3.1 Noncompliant Code Example<br />

In this noncompliant code example [GCC Bugs], the programmer uses preprocessor directives to<br />

specify platform-specific arguments to memcpy(). However, if memcpy() is implemented using a<br />

macro, the code results in undefined behavior.<br />

#include <br />

void func(const char *src) {<br />

/* Validate the source string; calculate size */<br />

char *dest;<br />

/* malloc() destination string */<br />

memcpy(dest, src,<br />

#ifdef PLATFORM1<br />

12<br />

#else<br />

24<br />

#endif<br />

);<br />

/* ... */<br />

);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 30<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Preprocessor (PRE) - PRE32-C. Do not use preprocessor directives in invocations of function-like macros<br />

2.3.2 Compliant Solution<br />

In this compliant solution [GCC Bugs], the appropriate call to memcpy() is determined outside<br />

the function call:<br />

#include <br />

void func(const char *src) {<br />

/* Validate the source string; calculate size */<br />

char *dest;<br />

/* malloc() destination string */<br />

#ifdef PLATFORM1<br />

memcpy(dest, src, 12);<br />

#else<br />

memcpy(dest, src, 24);<br />

#endif<br />

/* ... */<br />

}<br />

2.3.3 Risk Assessment<br />

Including preprocessor directives in macro arguments is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

PRE32-C Low Unlikely Medium P2 L3<br />

2.3.4 Bibliography<br />

[GCC Bugs]<br />

[ISO/IEC 9899:2011]<br />

“Non-bugs”<br />

6.10.3, “Macro Replacement”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 31<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL30-C. Declare objects with appropriate storage durations<br />

3 Declarations and Initialization (DCL)<br />

3.1 DCL30-C. Declare objects with appropriate storage durations<br />

Every object has a storage duration that determines its lifetime: static, thread, automatic, or allocated.<br />

According to the C <strong>Standard</strong>, 6.2.4, paragraph 2 [ISO/IEC 9899:2011],<br />

The lifetime of an object is the portion of program execution during which storage is<br />

guaranteed to be reserved for it. An object exists, has a constant address, and retains its<br />

last-stored value throughout its lifetime. If an object is referred to outside of its lifetime,<br />

the behavior is undefined. The value of a pointer becomes indeterminate when the object<br />

it points to reaches the end of its lifetime.<br />

Do not attempt to access an object outside of its lifetime. Attempting to do so is undefined behavior<br />

and can lead to an exploitable vulnerability. (See also undefined behavior 9 in the C <strong>Standard</strong>,<br />

Annex J.)<br />

3.1.1 Noncompliant Code Example (Differing Storage Durations)<br />

In this noncompliant code example, the address of the variable c_str with automatic storage duration<br />

is assigned to the variable p, which has static storage duration. The assignment itself is<br />

valid, but it is invalid for c_str to go out of scope while p holds its address, as happens at the<br />

end of dont_do_this().<br />

#include <br />

const char *p;<br />

void dont_do_this(void) {<br />

const char c_str[] = "This will change";<br />

p = c_str; /* Dangerous */<br />

}<br />

void innocuous(void) {<br />

printf("%s\n", p);<br />

}<br />

int main(void) {<br />

dont_do_this();<br />

innocuous();<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 32<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL30-C. Declare objects with appropriate storage durations<br />

3.1.2 Compliant Solution (Same Storage Durations)<br />

In this compliant solution, p is declared with the same storage duration as c_str, preventing p<br />

from taking on an indeterminate value outside of this_is_OK():<br />

void this_is_OK(void) {<br />

const char c_str[] = "Everything OK";<br />

const char *p = c_str;<br />

/* ... */<br />

}<br />

/* p is inaccessible outside the scope of string c_str */<br />

Alternatively, both p and c_str could be declared with static storage duration.<br />

3.1.3 Compliant Solution (Differing Storage Durations)<br />

If it is necessary for p to be defined with static storage duration but c_str with a more limited<br />

duration, then p can be set to NULL before c_str is destroyed. This practice prevents p from taking<br />

on an indeterminate value, although any references to p must check for NULL.<br />

const char *p;<br />

void is_this_OK(void) {<br />

const char c_str[] = "Everything OK?";<br />

p = c_str;<br />

/* ... */<br />

p = NULL;<br />

}<br />

3.1.4 Noncompliant Code Example (Return Values)<br />

In this noncompliant code sample, the function init_array() returns a pointer to a character<br />

array with automatic storage duration, which is accessible to the caller:<br />

char *init_array(void) {<br />

char array[10];<br />

/* Initialize array */<br />

return array;<br />

}<br />

Some compilers generate a diagnostic message when a pointer to an object with automatic storage<br />

duration is returned from a function, as in this example. Programmers should compile code at high<br />

warning levels and resolve any diagnostic messages. (See MSC00-C. Compile cleanly at high<br />

warning levels.)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 33<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL30-C. Declare objects with appropriate storage durations<br />

3.1.5 Compliant Solution (Return Values)<br />

The solution, in this case, depends on the intent of the programmer. If the intent is to modify the<br />

value of array and have that modification persist outside the scope of init_array(), the desired<br />

behavior can be achieved by declaring array elsewhere and passing it as an argument to<br />

init_array():<br />

#include <br />

void init_array(char *array, size_t len) {<br />

/* Initialize array */<br />

return;<br />

}<br />

int main(void) {<br />

char array[10];<br />

init_array(array, sizeof(array) / sizeof(array[0]));<br />

/* ... */<br />

return 0;<br />

}<br />

3.1.6 Noncompliant Code Example (Output Parameter)<br />

In this noncompliant code example, the function squirrel_away() stores a pointer to local variable<br />

local into a location pointed to by function parameter ptr_param. Upon the return of<br />

squirrel_away(), the pointer ptr_param points to a variable that has an expired lifetime.<br />

void squirrel_away(char **ptr_param) {<br />

char local[10];<br />

/* Initialize array */<br />

*ptr_param = local;<br />

}<br />

void rodent(void) {<br />

char *ptr;<br />

squirrel_away(&ptr);<br />

/* ptr is live but invalid here */<br />

}<br />

3.1.7 Compliant Solution (Output Parameter)<br />

In this compliant solution, the variable local has static storage duration; consequently, ptr can<br />

be used to reference the local array within the rodent() function:<br />

char local[10];<br />

void squirrel_away(char **ptr_param) {<br />

/* Initialize array */<br />

*ptr_param = local;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 34<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL30-C. Declare objects with appropriate storage durations<br />

void rodent(void) {<br />

char *ptr;<br />

squirrel_away(&ptr);<br />

/* ptr is valid in this scope */<br />

}<br />

3.1.8 Risk Assessment<br />

Referencing an object outside of its lifetime can result in an attacker being able to execute arbitrary<br />

code.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL30-C High Probable High P6 L2<br />

3.1.9 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MISRA C:2012<br />

MSC00-C. Compile cleanly at high warning<br />

levels<br />

EXP54-CPP. Do not access an object outside of<br />

its lifetime<br />

Dangling References to Stack Frames [DCM]<br />

Escaping of the address of an automatic object<br />

[addrescape]<br />

Rule 18.6 (required)<br />

3.1.10 Bibliography<br />

[Coverity 2007]<br />

[ISO/IEC 9899:2011]<br />

6.2.4, “Storage Durations of Objects”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 35<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL31-C. Declare identifiers before using them<br />

3.2 DCL31-C. Declare identifiers before using them<br />

The C11 <strong>Standard</strong> requires type specifiers and forbids implicit function declarations. The C90<br />

<strong>Standard</strong> allows implicit typing of variables and functions. Consequently, some existing legacy<br />

code uses implicit typing. Some C compilers still support legacy code by allowing implicit typing,<br />

but it should not be used for new code. Such an implementation may choose to assume an implicit<br />

declaration and continue translation to support existing programs that used this feature.<br />

3.2.1 Noncompliant Code Example (Implicit int)<br />

C no longer allows the absence of type specifiers in a declaration. The C <strong>Standard</strong>, 6.7.2 [ISO/IEC<br />

9899:2011], states<br />

At least one type specifier shall be given in the declaration specifiers in each declaration,<br />

and in the specifier-qualifier list in each struct declaration and type name.<br />

This noncompliant code example omits the type specifier:<br />

extern foo;<br />

Some C implementations do not issue a diagnostic for the violation of this constraint. These nonconforming<br />

C translators continue to treat such declarations as implying the type int.<br />

3.2.2 Compliant Solution (Implicit int)<br />

This compliant solution explicitly includes a type specifier:<br />

extern int foo;<br />

3.2.3 Noncompliant Code Example (Implicit Function Declaration)<br />

Implicit declaration of functions is not allowed; every function must be explicitly declared before<br />

it can be called. In C90, if a function is called without an explicit prototype, the compiler provides<br />

an implicit declaration.<br />

The C90 <strong>Standard</strong> [ISO/IEC 9899:1990] includes this requirement:<br />

If the expression that precedes the parenthesized argument list in a function call consists<br />

solely of an identifier, and if no declaration is visible for this identifier, the identifier<br />

is implicitly declared exactly as if, in the innermost block containing the function call, the<br />

declaration extern int identifier(); appeared.<br />

If a function declaration is not visible at the point at which a call to the function is made, C90-<br />

compliant platforms assume an implicit declaration of extern int identifier();.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 36<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL31-C. Declare identifiers before using them<br />

This declaration implies that the function may take any number and type of arguments and return<br />

an int. However, to conform to the current C <strong>Standard</strong>, programmers must explicitly prototype<br />

every function before invoking it. An implementation that conforms to the C <strong>Standard</strong> may or<br />

may not perform implicit function declarations, but C does require a conforming implementation<br />

to issue a diagnostic if it encounters an undeclared function being used.<br />

In this noncompliant code example, if malloc() is not declared, either explicitly or by including<br />

stdlib.h, a compiler that conforms only to C90 may implicitly declare malloc() as int malloc().<br />

If the platform’s size of int is 32 bits, but the size of pointers is 64 bits, the resulting<br />

pointer would likely be truncated as a result of the implicit declaration of malloc(), returning a<br />

32-bit integer.<br />

#include <br />

/* #include is missing */<br />

int main(void) {<br />

for (size_t i = 0; i < 100; ++i) {<br />

/* int malloc() assumed */<br />

char *ptr = (char *)malloc(0x10000000);<br />

*ptr = 'a';<br />

}<br />

return 0;<br />

}<br />

3.2.3.1 Implementation Details<br />

When compiled with Microsoft Visual Studio 2013 for a 64-bit platform, this noncompliant code<br />

example will eventually cause an access violation when dereferencing ptr in the loop.<br />

3.2.4 Compliant Solution (Implicit Function Declaration)<br />

This compliant solution declares malloc() by including the appropriate header file:<br />

#include <br />

int main(void) {<br />

for (size_t i = 0; i < 100; ++i) {<br />

char *ptr = (char *)malloc(0x10000000);<br />

*ptr = 'a';<br />

}<br />

return 0;<br />

}<br />

For more information on function declarations, see DCL07-C. Include the appropriate type information<br />

in function declarators.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 37<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL31-C. Declare identifiers before using them<br />

3.2.5 Noncompliant Code Example (Implicit Return Type)<br />

Do not declare a function with an implicit return type. For example, if a function returns a meaningful<br />

integer value, declare it as returning int. If it returns no meaningful value, declare it as returning<br />

void.<br />

#include <br />

#include <br />

foo(void) {<br />

return UINT_MAX;<br />

}<br />

int main(void) {<br />

long long int c = foo();<br />

printf("%lld\n", c);<br />

return 0;<br />

}<br />

Because the compiler assumes that foo() returns a value of type int for this noncompliant code<br />

example, UINT_MAX is incorrectly converted to −1.<br />

3.2.6 Compliant Solution (Implicit Return Type)<br />

This compliant solution explicitly defines the return type of foo() as unsigned int. As a result,<br />

the function correctly returns UINT_MAX.<br />

#include <br />

#include <br />

unsigned int foo(void) {<br />

return UINT_MAX;<br />

}<br />

int main(void) {<br />

long long int c = foo();<br />

printf("%lld\n", c);<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 38<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL31-C. Declare identifiers before using them<br />

3.2.7 Risk Assessment<br />

Because implicit declarations lead to less stringent type checking, they can introduce unexpected<br />

and erroneous behavior. Occurrences of an omitted type specifier in existing code are rare, and the<br />

consequences are generally minor, perhaps resulting in abnormal program termination.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL31-C Low Unlikely Low P3 L3<br />

3.2.8 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

MISRA C:2012<br />

DCL07-C. Include the appropriate type information<br />

in function declarators<br />

Subprogram Signature Mismatch [OTR]<br />

Rule 8.1 (required)<br />

3.2.9 Bibliography<br />

[ISO/IEC 9899:1990]<br />

[ISO/IEC 9899:2011]<br />

[Jones 2008]<br />

Subclause 6.7.2, “Type Specifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 39<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL36-C. Do not declare an identifier with conflicting linkage classifications<br />

3.3 DCL36-C. Do not declare an identifier with conflicting linkage<br />

classifications<br />

Linkage can make an identifier declared in different scopes or declared multiple times within the<br />

same scope refer to the same object or function. Identifiers are classified as externally linked, internally<br />

linked, or not linked. These three kinds of linkage have the following characteristics<br />

[Kirch-Prinz 2002]:<br />

• External linkage: An identifier with external linkage represents the same object or function<br />

throughout the entire program, that is, in all compilation units and libraries belonging to the<br />

program. The identifier is available to the linker. When a second declaration of the same identifier<br />

with external linkage occurs, the linker associates the identifier with the same object or<br />

function.<br />

• Internal linkage: An identifier with internal linkage represents the same object or function<br />

within a given translation unit. The linker has no information about identifiers with internal<br />

linkage. Consequently, these identifiers are internal to the translation unit.<br />

• No linkage: If an identifier has no linkage, then any further declaration using the identifier<br />

declares something new, such as a new variable or a new type.<br />

According to the C <strong>Standard</strong>, 6.2.2 [ISO/IEC 9899:2011], linkage is determined as follows:<br />

If the declaration of a file scope identifier for an object or a function contains the storage<br />

class specifier static, the identifier has internal linkage.<br />

For an identifier declared with the storage-class specifier extern in a scope in which a<br />

prior declaration of that identifier is visible, if the prior declaration specifies internal or external<br />

linkage, the linkage of the identifier at the later declaration is the same as the linkage<br />

specified at the prior declaration. If no prior declaration is visible, or if the prior declaration<br />

specifies no linkage, then the identifier has external linkage.<br />

If the declaration of an identifier for a function has no storage-class specifier, its linkage<br />

is determined exactly as if it were declared with the storage-class specifier extern. If<br />

the declaration of an identifier for an object has file scope and no storage-class specifier,<br />

its linkage is external.<br />

The following identifiers have no linkage: an identifier declared to be anything other than<br />

an object or a function; an identifier declared to be a function parameter; a block scope<br />

identifier for an object declared without the storage-class specifier extern.<br />

Use of an identifier (within one translation unit) classified as both internally and externally linked<br />

is undefined behavior. (See also undefined behavior 8.) A translation unit includes the source file<br />

together with its headers and all source files included via the preprocessing directive #include.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 40<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL36-C. Do not declare an identifier with conflicting linkage classifications<br />

The following table identifies the linkage assigned to an object that is declared twice in a single<br />

translation unit. The column designates the first declaration, and the row designates the redeclaration.<br />

3.3.1 Noncompliant Code Example<br />

In this noncompliant code example, i2 and i5 are defined as having both internal and external<br />

linkage. Future use of either identifier results in undefined behavior.<br />

int i1 = 10; /* Definition, external linkage */<br />

static int i2 = 20; /* Definition, internal linkage */<br />

extern int i3 = 30; /* Definition, external linkage */<br />

int i4; /* Tentative definition, external linkage */<br />

static int i5; /* Tentative definition, internal linkage */<br />

int i1; /* Valid tentative definition */<br />

int i2; /* Undefined, linkage disagreement with previous */<br />

int i3; /* Valid tentative definition */<br />

int i4; /* Valid tentative definition */<br />

int i5; /* Undefined, linkage disagreement with previous */<br />

int main(void) {<br />

/* ... */<br />

return 0;<br />

}<br />

3.3.1.1 Implementation Details<br />

Microsoft Visual Studio 2013 issues no warnings about this code, even at the highest diagnostic<br />

levels.<br />

The GCC compiler generates a fatal diagnostic for the conflicting definitions of i2 and i5.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 41<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL36-C. Do not declare an identifier with conflicting linkage classifications<br />

3.3.2 Compliant Solution<br />

This compliant solution does not include conflicting definitions:<br />

int i1 = 10; /* Definition, external linkage */<br />

static int i2 = 20; /* Definition, internal linkage */<br />

extern int i3 = 30; /* Definition, external linkage */<br />

int i4; /* Tentative definition, external linkage */<br />

static int i5; /* Tentative definition, internal linkage */<br />

int main(void) {<br />

/* ... */<br />

return 0;<br />

}<br />

3.3.3 Risk Assessment<br />

Use of an identifier classified as both internally and externally linked is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL36-C Medium Probable Medium P8 L2<br />

3.3.4 Related Guidelines<br />

MISRA C:2012<br />

Rule 8.2 (required)<br />

Rule 8.4 (required)<br />

Rule 8.8 (required)<br />

Rule 17.3 (mandatory)<br />

3.3.5 Bibliography<br />

[Banahan 2003]<br />

[ISO/IEC 9899:2011]<br />

[Kirch-Prinz 2002]<br />

Section 8.2, “Declarations, Definitions and Accessibility”<br />

6.2.2, “Linkages of Identifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 42<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

3.4 DCL37-C. Do not declare or define a reserved identifier<br />

According to the C <strong>Standard</strong>, 7.1.3 [ISO/IEC 9899:2011],<br />

All identifiers that begin with an underscore and either an uppercase letter or another underscore<br />

are always reserved for any use.<br />

All identifiers that begin with an underscore are always reserved for use as identifiers<br />

with file scope in both the ordinary and tag name spaces.<br />

Each macro name in any of the following subclauses (including the future library directions)<br />

is reserved for use as specified if any of its associated headers is included, unless<br />

explicitly stated otherwise.<br />

All identifiers with external linkage (including future library directions) and errno are always<br />

reserved for use as identifiers with external linkage.<br />

Each identifier with file scope listed in any of the following subclauses (including the future<br />

library directions) is reserved for use as a macro name and as an identifier with file<br />

scope in the same name space if any of its associated headers is included.<br />

Additionally, subclause 7.31 defines many other reserved identifiers for future library directions.<br />

No other identifiers are reserved. (The POSIX standard extends the set of identifiers reserved by<br />

the C <strong>Standard</strong> to include an open-ended set of its own. See Portable Operating System Interface<br />

[POSIX®], Base Specifications, Issue 7, Section 2.2, “The Compilation Environment” [IEEE Std<br />

1003.1-2013].) The behavior of a program that declares or defines an identifier in a context in<br />

which it is reserved or that defines a reserved identifier as a macro name is undefined. (See undefined<br />

behavior 106.)<br />

3.4.1 Noncompliant Code Example (Header Guard)<br />

A common, but noncompliant, practice is to choose a reserved name for a macro used in a preprocessor<br />

conditional guarding against multiple inclusions of a header file. (See also PRE06-C. Enclose<br />

header files in an inclusion guard.) The name may clash with reserved names defined by the<br />

implementation of the C standard library in its headers or with reserved names implicitly predefined<br />

by the compiler even when no C standard library header is included.<br />

#ifndef _MY_HEADER_H_<br />

#define _MY_HEADER_H_<br />

/* Contents of */<br />

#endif /* _MY_HEADER_H_ */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 43<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

3.4.2 Compliant Solution (Header Guard)<br />

This compliant solution avoids using leading underscores in the name of the header guard:<br />

#ifndef MY_HEADER_H<br />

#define MY_HEADER_H<br />

/* Contents of */<br />

#endif /* MY_HEADER_H */<br />

3.4.3 Noncompliant Code Example (File Scope Objects)<br />

In this noncompliant code example, the names of the file scope objects _max_limit and _limit<br />

both begin with an underscore. Because _max_limit is static, this declaration might seem to be<br />

impervious to clashes with names defined by the implementation. However, because the header<br />

is included to define size_t, a potential for a name clash exists. (Note, however,<br />

that a conforming compiler may implicitly declare reserved names regardless of whether any C<br />

standard library header is explicitly included.)<br />

In addition, because _limit has external linkage, it may clash with a symbol of the same name<br />

defined in the language runtime library even if such a symbol is not declared in any header. Consequently,<br />

it is not safe to start the name of any file scope identifier with an underscore even if its<br />

linkage limits its visibility to a single translation unit.<br />

#include <br />

static const size_t _max_limit = 1024;<br />

size_t _limit = 100;<br />

unsigned int getValue(unsigned int count) {<br />

return count < _limit ? count : _limit;<br />

}<br />

3.4.4 Compliant Solution (File Scope Objects)<br />

In this compliant solution, names of file scope objects do not begin with an underscore:<br />

#include <br />

static const size_t max_limit = 1024;<br />

size_t limit = 100;<br />

unsigned int getValue(unsigned int count) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 44<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

}<br />

return count < limit ? count : limit;<br />

3.4.5 Noncompliant Code Example (Reserved Macros)<br />

In this noncompliant code example, because the C standard library header is<br />

specified to include , the name SIZE_MAX conflicts with a standard macro of the<br />

same name, which is used to denote the upper limit of size_t. In addition, although the name<br />

INTFAST16_LIMIT_MAX is not defined by the C standard library, it is a reserved identifier because<br />

it begins with the INT prefix and ends with the _MAX suffix. (See the C <strong>Standard</strong>, 7.31.10.)<br />

#include <br />

#include <br />

static const int_fast16_t INTFAST16_LIMIT_MAX = 12000;<br />

void print_fast16(int_fast16_t val) {<br />

enum { SIZE_MAX = 80 };<br />

char buf[SIZE_MAX];<br />

if (INTFAST16_LIMIT_MAX < val) {<br />

sprintf(buf, "The value is too large");<br />

} else {<br />

snprintf(buf, SIZE_MAX, "The value is %" PRIdFAST16, val);<br />

}<br />

}<br />

3.4.6 Compliant Solution (Reserved Macros)<br />

This compliant solution avoids redefining reserved names or using reserved prefixes and suffixes:<br />

#include <br />

#include <br />

static const int_fast16_t MY_INTFAST16_UPPER_LIMIT = 12000;<br />

void print_fast16(int_fast16_t val) {<br />

enum { BUFSIZE = 80 };<br />

char buf[BUFSIZE];<br />

if (MY_INTFAST16_UPPER_LIMIT < val) {<br />

sprintf(buf, "The value is too large");<br />

} else {<br />

snprintf(buf, BUFSIZE, "The value is %" PRIdFAST16, val);<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 45<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

3.4.7 Noncompliant Code Example (Identifiers with External Linkage)<br />

In addition to symbols defined as functions in each C standard library header, identifiers with external<br />

linkage include errno and math_errhandling, among others, regardless of whether any<br />

of them are masked by a macro of the same name.<br />

This noncompliant example provides definitions for the C standard library functions malloc()<br />

and free(). Although this practice is permitted by many traditional implementations of UNIX<br />

(for example, the Dmalloc library), it is undefined behavior according to the C <strong>Standard</strong>. Even on<br />

systems that allow replacing malloc(), doing so without also replacing aligned_alloc(),<br />

calloc(), and realloc() is likely to cause problems.<br />

#include <br />

void *malloc(size_t nbytes) {<br />

void *ptr;<br />

/* Allocate storage from own pool and set ptr */<br />

return ptr;<br />

}<br />

void free(void *ptr) {<br />

/* Return storage to own pool */<br />

}<br />

3.4.8 Compliant Solution (Identifiers with External Linkage)<br />

The compliant, portable solution avoids redefining any C standard library identifiers with external<br />

linkage. In addition, it provides definitions for all memory allocation functions:<br />

#include <br />

void *my_malloc(size_t nbytes) {<br />

void *ptr;<br />

/* Allocate storage from own pool and set ptr */<br />

return ptr;<br />

}<br />

void *my_aligned_alloc(size_t alignment, size_t size) {<br />

void *ptr;<br />

/* Allocate storage from own pool, align properly, set ptr */<br />

return ptr;<br />

}<br />

void *my_calloc(size_t nelems, size_t elsize) {<br />

void *ptr;<br />

/* Allocate storage from own pool, zero memory, and set ptr */<br />

return ptr;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 46<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

void *my_realloc(void *ptr, size_t nbytes) {<br />

/* Reallocate storage from own pool and set ptr */<br />

return ptr;<br />

}<br />

void my_free(void *ptr) {<br />

/* Return storage to own pool */<br />

}<br />

3.4.9 Noncompliant Code Example (errno)<br />

According to the C <strong>Standard</strong>, 7.5, paragraph 2 [ISO/IEC 9899:2011], the behavior of a program is<br />

undefined when<br />

A macro definition of errno is suppressed in order to access an actual object, or the<br />

program defines an identifier with the name errno.<br />

See undefined behavior 114.<br />

The errno identifier expands to a modifiable lvalue that has type int but is not necessarily the<br />

identifier of an object. It might expand to a modifiable lvalue resulting from a function call, such<br />

as *errno(). It is unspecified whether errno is a macro or an identifier declared with external<br />

linkage. If a macro definition is suppressed to access an actual object, or if a program defines an<br />

identifier with the name errno, the behavior is undefined.<br />

Legacy code is apt to include an incorrect declaration, such as the following:<br />

extern int errno;<br />

3.4.10 Compliant Solution (errno)<br />

The correct way to declare errno is to include the header :<br />

#include <br />

Implementations conforming to C are required to declare errno in , although some<br />

historic implementations failed to do so.<br />

3.4.11 Exceptions<br />

DCL37-C-EX1: Provided that a library function can be declared without reference to any type<br />

defined in a header, it is permissible to declare that function without including its header provided<br />

that declaration is compatible with the standard declaration.<br />

/* Not including stdlib.h */<br />

void free(void *);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 47<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

void func(void *ptr) {<br />

free(ptr);<br />

}<br />

Such code is compliant because the declaration matches what stdlib.h would provide and does<br />

not redefine the reserved identifier. However, it would not be acceptable to provide a definition<br />

for the free() function in this example.<br />

DCL37-C-EX2: For compatibility with other compiler vendors or language standard modes, it is<br />

acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior<br />

is idempotent, as in this example:<br />

/* Sometimes generated by configuration tools such as autoconf */<br />

#define const<br />

/* Allowed compilers with semantically equivalent extension behavior<br />

*/<br />

#define inline __inline<br />

DCL37-C-EX3: As a compiler vendor or standard library developer, it is acceptable to use identifiers<br />

reserved for your implementation. Reserved identifiers may be defined by the compiler, in<br />

standard library headers or headers included by a standard library header, as in this example declaration<br />

from the glibc standard C library implementation:<br />

/*<br />

The following declarations of reserved identifiers exist in the<br />

glibc implementation of<br />

. The original source code may be found at:<br />

https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=include/stdio.h;hb=HEAD<br />

*/<br />

# define __need_size_t<br />

# include <br />

/* Generate a unique file name (and possibly open it). */<br />

extern int __path_search (char *__tmpl, size_t __tmpl_len,<br />

const char *__dir, const char *__pfx,<br />

int __try_tempdir);<br />

3.4.12 Risk Assessment<br />

Using reserved identifiers can lead to incorrect program operation.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL37-C Low Unlikely Low P3 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 48<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL37-C. Do not declare or define a reserved identifier<br />

3.4.13 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961<br />

MISRA C:2012<br />

PRE00-C. Prefer inline or static functions to<br />

function-like macros<br />

PRE06-C. Enclose header files in an inclusion<br />

guard<br />

PRE31-C. Avoid side effects in arguments to<br />

unsafe macros<br />

DCL51-CPP. Do not declare or define a reserved<br />

identifier<br />

Using identifiers that are reserved for the implementation<br />

[resident]<br />

Rule 21.1 (required)<br />

Rule 21.2 (required)<br />

3.4.14 Bibliography<br />

[IEEE Std 1003.1-2013]<br />

[ISO/IEC 9899:2011]<br />

Section 2.2, “The Compilation Environment”<br />

7.1.3, “Reserved Identifiers”<br />

7.31.10, “Integer Types “<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 49<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL38-C. Use the correct syntax when declaring a flexible array member<br />

3.5 DCL38-C. Use the correct syntax when declaring a flexible array<br />

member<br />

Flexible array members are a special type of array in which the last element of a structure with<br />

more than one named member has an incomplete array type; that is, the size of the array is not<br />

specified explicitly within the structure. This “struct hack” was widely used in practice and supported<br />

by a variety of compilers. Consequently, a variety of different syntaxes have been used for<br />

declaring flexible array members. For conforming C implementations, use the syntax guaranteed<br />

to be valid by the C <strong>Standard</strong>.<br />

Flexible array members are defined in the C <strong>Standard</strong>, 6.7.2.1, paragraph 18 [ISO/IEC<br />

9899:2011], as follows:<br />

As a special case, the last element of a structure with more than one named member<br />

may have an incomplete array type; this is called a flexible array member. In most situations,<br />

the flexible array member is ignored. In particular, the size of the structure is as if<br />

the flexible array member were omitted except that it may have more trailing padding<br />

than the omission would imply. However, when a . (or ->) operator has a left operand<br />

that is (a pointer to) a structure with a flexible array member and the right operand<br />

names that member, it behaves as if that member were replaced with the longest array<br />

(with the same element type) that would not make the structure larger than the object<br />

being accessed; the offset of the array shall remain that of the flexible array member,<br />

even if this would differ from that of the replacement array. If this array would have no<br />

elements, it behaves as if it had one element but the behavior is undefined if any attempt<br />

is made to access that element or to generate a pointer one past it.<br />

Structures with a flexible array member can be used to produce code with defined behavior. However,<br />

some restrictions apply:<br />

1. The incomplete array type must be the last element within the structure.<br />

2. There cannot be an array of structures that contain a flexible array member.<br />

3. Structures that contain a flexible array member cannot be used as a member of another structure<br />

except as the last element of that structure.<br />

4. The structure must contain at least one named member in addition to the flexible array member.<br />

MEM33-C. Allocate and copy structures containing a flexible array member dynamically describes<br />

how to allocate and copy structures containing flexible array members.<br />

3.5.1 Noncompliant Code Example<br />

Before the introduction of flexible array members in the C <strong>Standard</strong>, structures with a one-element<br />

array as the final member were used to achieve similar functionality. This noncompliant<br />

code example illustrates how struct flexArrayStruct is declared in this case.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 50<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL38-C. Use the correct syntax when declaring a flexible array member<br />

This noncompliant code example attempts to allocate a flexible array-like member with a one-element<br />

array as the final member. When the structure is instantiated, the size computed for malloc()<br />

is modified to account for the actual size of the dynamic array.<br />

#include <br />

struct flexArrayStruct {<br />

int num;<br />

int data[1];<br />

};<br />

void func(size_t array_size) {<br />

/* Space is allocated for the struct */<br />

struct flexArrayStruct *structP<br />

= (struct flexArrayStruct *)<br />

malloc(sizeof(struct flexArrayStruct)<br />

+ sizeof(int) * (array_size - 1));<br />

if (structP == NULL) {<br />

/* Handle malloc failure */<br />

}<br />

structP->num = array_size;<br />

}<br />

/*<br />

* Access data[] as if it had been allocated<br />

* as data[array_size].<br />

*/<br />

for (size_t i = 0; i < array_size; ++i) {<br />

structP->data[i] = 1;<br />

}<br />

This example has undefined behavior when accessing any element other than the first element of<br />

the data array. (See the C <strong>Standard</strong>, 6.5.6.) Consequently, the compiler can generate code that<br />

does not return the expected value when accessing the second element of data.<br />

This approach may be the only alternative for compilers that do not yet implement the standard C<br />

syntax.<br />

3.5.2 Compliant Solution<br />

This compliant solution uses a flexible array member to achieve a dynamically sized structure:<br />

#include <br />

struct flexArrayStruct{<br />

int num;<br />

int data[];<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 51<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL38-C. Use the correct syntax when declaring a flexible array member<br />

};<br />

void func(size_t array_size) {<br />

/* Space is allocated for the struct */<br />

struct flexArrayStruct *structP<br />

= (struct flexArrayStruct *)<br />

malloc(sizeof(struct flexArrayStruct)<br />

+ sizeof(int) * array_size);<br />

if (structP == NULL) {<br />

/* Handle malloc failure */<br />

}<br />

structP->num = array_size;<br />

}<br />

/*<br />

* Access data[] as if it had been allocated<br />

* as data[array_size].<br />

*/<br />

for (size_t i = 0; i < array_size; ++i) {<br />

structP->data[i] = 1;<br />

}<br />

This compliant solution allows the structure to be treated as if its member data[] was declared to<br />

be data[array_size] in a manner that conforms to the C <strong>Standard</strong>.<br />

3.5.3 Risk Assessment<br />

Failing to use the correct syntax when declaring a flexible array member can result in undefined<br />

behavior, although the incorrect syntax will work on most implementations.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL38-C Low Unlikely Low P3 L3<br />

3.5.4 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

MEM33-C. Allocate and copy structures containing<br />

flexible array members dynamically<br />

3.5.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[McCluskey 2001]<br />

6.5.6, “Additive Operators”<br />

6.7.2.1, “Structure and Union Specifiers”<br />

“Flexible Array Members and Designators in<br />

C9X”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 52<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

3.6 DCL39-C. Avoid information leakage when passing a structure<br />

across a trust boundary<br />

The C <strong>Standard</strong>, 6.7.2.1, discusses the layout of structure fields. It specifies that non-bit-field<br />

members are aligned in an implementation-defined manner and that there may be padding within<br />

or at the end of a structure. Furthermore, initializing the members of the structure does not guarantee<br />

initialization of the padding bytes. The C <strong>Standard</strong>, 6.2.6.1, paragraph 6 [ISO/IEC<br />

9899:2011], states<br />

When a value is stored in an object of structure or union type, including in a member object,<br />

the bytes of the object representation that correspond to any padding bytes take unspecified<br />

values.<br />

Additionally, the storage units in which a bit-field resides may also have padding bits. For an object<br />

with automatic storage duration, these padding bits do not take on specific values and can<br />

contribute to leaking sensitive information.<br />

When passing a pointer to a structure across a trust boundary to a different trusted domain, the<br />

programmer must ensure that the padding bytes and bit-field storage unit padding bits of such a<br />

structure do not contain sensitive information.<br />

3.6.1 Noncompliant Code Example<br />

This noncompliant code example runs in kernel space and copies data from struct test to user<br />

space. However, padding bytes may be used within the structure, for example, to ensure the<br />

proper alignment of the structure members. These padding bytes may contain sensitive information,<br />

which may then be leaked when the data is copied to user space.<br />

#include <br />

struct test {<br />

int a;<br />

char b;<br />

int c;<br />

};<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = {.a = 1, .b = 2, .c = 3};<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 53<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

3.6.2 Noncompliant Code Example (memset())<br />

The padding bytes can be explicitly initialized by calling memset():<br />

#include <br />

struct test {<br />

int a;<br />

char b;<br />

int c;<br />

};<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg;<br />

/* Set all bytes (including padding bytes) to zero */<br />

memset(&arg, 0, sizeof(arg));<br />

arg.a = 1;<br />

arg.b = 2;<br />

arg.c = 3;<br />

}<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

However, compilers are free to implement arg.b = 2 by setting the low byte of a 32-bit register<br />

to 2, leaving the high bytes unchanged and storing all 32 bits of the register into memory. This<br />

implementation could leak the high-order bytes resident in the register to a user.<br />

3.6.3 Compliant Solution<br />

This compliant solution serializes the structure data before copying it to an untrusted context:<br />

#include <br />

#include <br />

struct test {<br />

int a;<br />

char b;<br />

int c;<br />

};<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = {.a = 1, .b = 2, .c = 3};<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 54<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

/* May be larger than strictly needed */<br />

unsigned char buf[sizeof(arg)];<br />

size_t offset = 0;<br />

memcpy(buf + offset, &arg.a, sizeof(arg.a));<br />

offset += sizeof(arg.a);<br />

memcpy(buf + offset, &arg.b, sizeof(arg.b));<br />

offset += sizeof(arg.b);<br />

memcpy(buf + offset, &arg.c, sizeof(arg.c));<br />

offset += sizeof(arg.c);<br />

}<br />

copy_to_user(usr_buf, buf, offset /* size of info copied */);<br />

This code ensures that no uninitialized padding bytes are copied to unprivileged users. The structure<br />

copied to user space is now a packed structure and the copy_to_user() function would<br />

need to unpack it to recreate the original padded structure.<br />

3.6.4 Compliant Solution (Padding Bytes)<br />

Padding bytes can be explicitly declared as fields within the structure. This solution is not portable,<br />

however, because it depends on the implementation and target memory architecture. The following<br />

solution is specific to the x86-32 architecture:<br />

#include <br />

#include <br />

struct test {<br />

int a;<br />

char b;<br />

char padding_1, padding_2, padding_3;<br />

int c;<br />

};<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

/* Ensure c is the next byte after the last padding byte */<br />

static_assert(offsetof(struct test, c) ==<br />

offsetof(struct test, padding_3) + 1,<br />

"Structure contains intermediate padding");<br />

/* Ensure there is no trailing padding */<br />

static_assert(sizeof(struct test) ==<br />

offsetof(struct test, c) + sizeof(int),<br />

"Structure contains trailing padding");<br />

struct test arg = {.a = 1, .b = 2, .c = 3};<br />

arg.padding_1 = 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 55<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

}<br />

arg.padding_2 = 0;<br />

arg.padding_3 = 0;<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

The C <strong>Standard</strong> static_assert() macro accepts a constant expression and an error message.<br />

The expression is evaluated at compile time and, if false, the compilation is terminated and the error<br />

message is output. (See DCL03-C. Use a static assertion to test the value of a constant expression<br />

for more details.) The explicit insertion of the padding bytes into the struct should ensure<br />

that no additional padding bytes are added by the compiler and consequently both static assertions<br />

should be true. However, it is necessary to validate these assumptions to ensure that the solution is<br />

correct for a particular implementation.<br />

3.6.5 Compliant Solution (Structure Packing—GCC)<br />

GCC allows specifying declaration attributes using the keyword __attribute__((__packed__)).<br />

When this attribute is present, the compiler will not add padding bytes<br />

for memory alignment unless otherwise required by the _Alignas alignment specifier, and it will<br />

attempt to place fields at adjacent memory offsets when possible.<br />

#include <br />

struct test {<br />

int a;<br />

char b;<br />

int c;<br />

} __attribute__((__packed__));<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = {.a = 1, .b = 2, .c = 3};<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

}<br />

3.6.6 Compliant Solution (Structure Packing—Microsoft Visual Studio)<br />

Microsoft Visual Studio supports #pragma pack() to suppress padding bytes [MSDN]. The<br />

compiler adds padding bytes for memory alignment, depending on the current packing mode, but<br />

still honors the alignment specified by __declspec(align()). In this compliant solution, the<br />

packing mode is set to 1 in an attempt to ensure all fields are given adjacent offsets:<br />

#include <br />

#pragma pack(push, 1) /* 1 byte */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 56<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

struct test {<br />

int a;<br />

char b;<br />

int c;<br />

};<br />

#pragma pack(pop)<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = {1, 2, 3};<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

}<br />

The pack pragma takes effect at the first struct declaration after the pragma is seen.<br />

3.6.7 Noncompliant Code Example<br />

This noncompliant code example also runs in kernel space and copies data from struct test to<br />

user space. However, padding bits will be used within the structure due to the bit-field member<br />

lengths not adding up to the number of bits in an unsigned object. Further, there is an unnamed<br />

bit-field that causes no further bit-fields to be packed into the same storage unit. These padding<br />

bits may contain sensitive information, which may then be leaked when the data is copied to user<br />

space. For instance, the uninitialized bits may contain a sensitive kernel space pointer value that<br />

can be trivially reconstructed by an attacker in user space.<br />

#include <br />

struct test {<br />

unsigned a : 1;<br />

unsigned : 0;<br />

unsigned b : 4;<br />

};<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = { .a = 1, .b = 10 };<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

}<br />

However, compilers are free to implement the initialization of arg.a and arg.b by setting the<br />

low byte of a 32-bit register to the value specified, leaving the high bytes unchanged and storing<br />

all 32 bits of the register into memory. This implementation could leak the high-order bytes resident<br />

in the register to a user.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 57<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

3.6.8 Compliant Solution<br />

Padding bits can be explicitly declared, allowing the programmer to specify the value of those<br />

bits. When explicitly declaring all of the padding bits, any unnamed bit-fields of length 0 must be<br />

removed from the structure because the explicit padding bits ensure that no further bit-fields will<br />

be packed into the same storage unit.<br />

#include <br />

#include <br />

#include <br />

struct test {<br />

unsigned a : 1;<br />

unsigned padding1 : sizeof(unsigned) * CHAR_BIT - 1;<br />

unsigned b : 4;<br />

unsigned padding2 : sizeof(unsigned) * CHAR_BIT - 4;<br />

};<br />

/* Ensure that we have added the correct number of padding bits. */<br />

static_assert(sizeof(struct test) == sizeof(unsigned) * 2,<br />

"Incorrect number of padding bits for type: unsigned");<br />

/* Safely copy bytes to user space */<br />

extern int copy_to_user(void *dest, void *src, size_t size);<br />

void do_stuff(void *usr_buf) {<br />

struct test arg = { .a = 1, .padding1 = 0, .b = 10, .padding2 = 0<br />

};<br />

copy_to_user(usr_buf, &arg, sizeof(arg));<br />

}<br />

This solution is not portable, however, because it depends on the implementation and target<br />

memory architecture. The explicit insertion of padding bits into the struct should ensure that no<br />

additional padding bits are added by the compiler. However, it is still necessary to validate these<br />

assumptions to ensure that the solution is correct for a particular implementation. For instance, the<br />

DEC Alpha is an example of a 64-bit architecture with 32-bit integers that allocates 64 bits to a<br />

storage unit.<br />

In addition, this solution assumes that there are no integer padding bits in an unsigned int.<br />

The portable version of the width calculation from INT35-C. Use correct integer precisions cannot<br />

be used because the bit-field width must be an integer constant expression.<br />

From this situation, it can be seen that special care must be taken because no solution to the bitfield<br />

padding issue will be 100% portable.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 58<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL39-C. Avoid information leakage when passing a structure across a trust boundary<br />

3.6.9 Risk Assessment<br />

Padding units might contain sensitive data because the C <strong>Standard</strong> allows any padding to take unspecified<br />

values. A pointer to such a structure could be passed to other functions, causing information<br />

leakage.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL39-C Low Unlikely High P1 L3<br />

3.6.9.1 Related Vulnerabilities<br />

Numerous vulnerabilities in the Linux Kernel have resulted from violations of this rule. CVE-<br />

2010-4083 describes a vulnerability in which the semctl() system call allows unprivileged users<br />

to read uninitialized kernel stack memory because various fields of a semid_ds struct declared<br />

on the stack are not altered or zeroed before being copied back to the user.<br />

CVE-2010-3881 describes a vulnerability in which structure padding and reserved fields in certain<br />

data structures in QEMU-KVM were not initialized properly before being copied to user space.<br />

A privileged host user with access to /dev/kvm could use this flaw to leak kernel stack memory<br />

to user space. CVE-2010-3477 describes a kernel information leak in act_police where incorrectly<br />

initialized structures in the traffic-control dump code may allow the disclosure of kernel<br />

memory to user space applications.<br />

3.6.10 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

DCL03-C. Use a static assertion to test the<br />

value of a constant expression<br />

3.6.11 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Graff 2003]<br />

[Sun 1993]<br />

6.2.6.1, “General”<br />

6.7.2.1, “Structure and Union Specifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 59<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

3.7 DCL40-C. Do not create incompatible declarations of the same<br />

function or object<br />

Two or more incompatible declarations of the same function or object must not appear in the<br />

same program because they result in undefined behavior. The C <strong>Standard</strong>, 6.2.7, mentions that<br />

two types may be distinct yet compatible and addresses precisely when two distinct types are<br />

compatible.<br />

The C <strong>Standard</strong> identifies four situations in which undefined behavior (UB) may arise as a result<br />

of incompatible declarations of the same function or object:<br />

UB Description Code<br />

15 Two declarations of the same<br />

object or function specify types<br />

that are not compatible (6.2.7).<br />

31 Two identifiers differ only in nonsignificant<br />

characters (6.4.2.1).<br />

37 An object has its stored value<br />

accessed other than by an lvalue<br />

of an allowable type (6.5).<br />

41 A function is defined with a type<br />

that is not compatible with the<br />

type (of the expression) pointed<br />

to by the expression that denotes<br />

the called function<br />

(6.5.2.2).<br />

All noncompliant code in this<br />

guideline<br />

Excessively Long Identifiers<br />

Incompatible Object Declarations<br />

Incompatible Array Declarations<br />

Incompatible Function Declarations<br />

Excessively Long Identifiers<br />

Although the effect of two incompatible declarations simply appearing in the same program may<br />

be benign on most implementations, the effects of invoking a function through an expression<br />

whose type is incompatible with the function definition are typically catastrophic. Similarly, the<br />

effects of accessing an object using an lvalue of a type that is incompatible with the object definition<br />

may range from unintended information exposure to memory overwrite to a hardware trap.<br />

3.7.1 Noncompliant Code Example (Incompatible Object Declarations)<br />

In this noncompliant code example, the variable i is declared to have type int in file a.c but defined<br />

to be of type short in file b.c. The declarations are incompatible, resulting in undefined<br />

behavior 15. Furthermore, accessing the object using an lvalue of an incompatible type, as shown<br />

in function f(), is undefined behavior 37 with possible observable results ranging from unintended<br />

information exposure to memory overwrite to a hardware trap.<br />

/* In a.c */<br />

extern int i; /* UB 15 */<br />

int f(void) {<br />

return ++i; /* UB 37 */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 60<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

/* In b.c */<br />

short i; /* UB 15 */<br />

3.7.2 Compliant Solution (Incompatible Object Declarations)<br />

This compliant solution has compatible declarations of the variable i:<br />

/* In a.c */<br />

extern int i;<br />

int f(void) {<br />

return ++i;<br />

}<br />

/* In b.c */<br />

int i;<br />

3.7.3 Noncompliant Code Example (Incompatible Array Declarations)<br />

In this noncompliant code example, the variable a is declared to have a pointer type in file a.c<br />

but defined to have an array type in file b.c. The two declarations are incompatible, resulting in<br />

undefined behavior 15. As before, accessing the object in function f() is undefined behavior 37<br />

with the typical effect of triggering a hardware trap.<br />

/* In a.c */<br />

extern int *a; /* UB 15 */<br />

int f(unsigned int i, int x) {<br />

int tmp = a[i]; /* UB 37: read access */<br />

a[i] = x; /* UB 37: write access */<br />

return tmp;<br />

}<br />

/* In b.c */<br />

int a[] = { 1, 2, 3, 4 }; /* UB 15 */<br />

3.7.4 Compliant Solution (Incompatible Array Declarations)<br />

This compliant solution declares a as an array in a.c and b.c:<br />

/* In a.c */<br />

extern int a[];<br />

int f(unsigned int i, int x) {<br />

int tmp = a[i];<br />

a[i] = x;<br />

return tmp;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 61<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

/* In b.c */<br />

int a[] = { 1, 2, 3, 4 };<br />

3.7.5 Noncompliant Code Example (Incompatible Function Declarations)<br />

In this noncompliant code example, the function f() is declared in file a.c with one prototype<br />

but defined in file b.c with another. The two prototypes are incompatible, resulting in undefined<br />

behavior 15. Furthermore, invoking the function is undefined behavior 41 and typically has catastrophic<br />

consequences.<br />

/* In a.c */<br />

extern int f(int a); /* UB 15 */<br />

int g(int a) {<br />

return f(a); /* UB 41 */<br />

}<br />

/* In b.c */<br />

long f(long a) { /* UB 15 */<br />

return a * 2;<br />

}<br />

3.7.6 Compliant Solution (Incompatible Function Declarations)<br />

This compliant solution has compatible prototypes for the function f():<br />

/* In a.c */<br />

extern int f(int a);<br />

int g(int a) {<br />

return f(a);<br />

}<br />

/* In b.c */<br />

int f(int a) {<br />

return a * 2;<br />

}<br />

3.7.7 Noncompliant Code Example (Incompatible Variadic Function<br />

Declarations)<br />

In this noncompliant code example, the function buginf() is defined to take a variable number<br />

of arguments and expects them all to be signed integers with a sentinel value of -1:<br />

/* In a.c */<br />

void buginf(const char *fmt, ...) {<br />

/* ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 62<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

}<br />

/* In b.c */<br />

void buginf();<br />

Although this code appears to be well defined because of the prototype-less declaration of<br />

buginf(), it exhibits undefined behavior in accordance with the C <strong>Standard</strong>, 6.7.6.3, paragraph<br />

15 [ISO/IEC 9899:2011],<br />

For two function types to be compatible, both shall specify compatible return types.<br />

Moreover, the parameter type lists, if both are present, shall agree in the number of parameters<br />

and in use of the ellipsis terminator; corresponding parameters shall have compatible<br />

types. If one type has a parameter type list and the other type is specified by a<br />

function declarator that is not part of a function definition and that contains an empty<br />

identifier list, the parameter list shall not have an ellipsis terminator and the type of each<br />

parameter shall be compatible with the type that results from the application of the default<br />

argument promotions.<br />

3.7.8 Compliant Solution (Incompatible Variadic Function Declarations)<br />

In this compliant solution, the prototype for the function buginf() is included in the scope in the<br />

source file where it will be used:<br />

/* In a.c */<br />

void buginf(const char *fmt, ...) {<br />

/* ... */<br />

}<br />

/* In b.c */<br />

void buginf(const char *fmt, ...);<br />

3.7.9 Noncompliant Code Example (Excessively Long Identifiers)<br />

In this noncompliant code example, the length of the identifier declaring the function pointer<br />

bash_groupname_completion_function() in the file bashline.h exceeds by 3 the minimum<br />

implementation limit of 31 significant initial characters in an external identifier. This introduces<br />

the possibility of colliding with the bash_groupname_completion_funct integer variable<br />

defined in file b.c, which is exactly 31 characters long. On an implementation that exactly<br />

meets this limit, this is undefined behavior 31. It results in two incompatible declarations of the<br />

same function. (See undefined behavior 15.) In addition, invoking the function leads to undefined<br />

behavior 41 with typically catastrophic effects.<br />

/* In bashline.h */<br />

/* UB 15, UB 31 */<br />

extern char * bash_groupname_completion_function(const char *,<br />

int);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 63<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

/* In a.c */<br />

#include "bashline.h"<br />

void f(const char *s, int i) {<br />

bash_groupname_completion_function(s, i); /* UB 41 */<br />

}<br />

/* In b.c */<br />

int bash_groupname_completion_funct; /* UB 15, UB 31 */<br />

NOTE: The identifier bash_groupname_completion_function referenced here was taken<br />

from GNU Bash, version 3.2.<br />

3.7.10 Compliant Solution (Excessively Long Identifiers)<br />

In this compliant solution, the length of the identifier declaring the function pointer<br />

bash_groupname_completion() in bashline.h is less than 32 characters. Consequently, it<br />

cannot clash with bash_groupname_completion_funct on any compliant platform.<br />

/* In bashline.h */<br />

extern char * bash_groupname_completion(const char *, int);<br />

/* In a.c */<br />

#include "bashline.h"<br />

void f(const char *s, int i) {<br />

bash_groupname_completion(s, i);<br />

}<br />

/* In b.c */<br />

int bash_groupname_completion_funct;<br />

3.7.11 Risk Assessment<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL40-C Low Unlikely Medium P2 L3<br />

3.7.12 Related Guidelines<br />

ISO/IEC TS 17961<br />

MISRA C:2012<br />

Declaring the same function or object in incompatible<br />

ways [funcdecl]<br />

Rule 8.4 (required)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 64<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL40-C. Do not create incompatible declarations of the same function or object<br />

3.7.13 Bibliography<br />

[Hatton 1995] Section 2.8.3<br />

[ISO/IEC 9899:2011]<br />

6.7.6.3, “Function Declarators (including Prototypes)”<br />

J.2, “Undefined Behavior”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 65<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL41-C. Do not declare variables inside a switch statement before the first case<br />

label<br />

3.8 DCL41-C. Do not declare variables inside a switch statement before<br />

the first case label<br />

According to the C <strong>Standard</strong>, 6.8.4.2, paragraph 4 [ISO/IEC 9899:2011],<br />

A switch statement causes control to jump to, into, or past the statement that is the<br />

switch body, depending on the value of a controlling expression, and on the presence of<br />

a default label and the values of any case labels on or in the switch body.<br />

If a programmer declares variables, initializes them before the first case statement, and then tries<br />

to use them inside any of the case statements, those variables will have scope inside the switch<br />

block but will not be initialized and will consequently contain indeterminate values.<br />

3.8.1 Noncompliant Code Example<br />

This noncompliant code example declares variables and contains executable statements before the<br />

first case label within the switch statement:<br />

#include <br />

extern void f(int i);<br />

void func(int expr) {<br />

switch (expr) {<br />

int i = 4;<br />

f(i);<br />

case 0:<br />

i = 17;<br />

/* Falls through into default code */<br />

default:<br />

printf("%d\n" , i);<br />

}<br />

}<br />

3.8.1.1 Implementation Details<br />

When the preceding example is executed on GCC 4.8.1, the variable i is instantiated with automatic<br />

storage duration within the block, but it is not initialized. Consequently, if the controlling<br />

expression expr has a nonzero value, the call to printf() will access an indeterminate value of<br />

i. Similarly, the call to f() is not executed.<br />

Value of expr<br />

0 17<br />

Nonzero<br />

Output<br />

Indeterminate<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 66<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Declarations and Initialization (DCL) - DCL41-C. Do not declare variables inside a switch statement before the first case<br />

label<br />

3.8.2 Compliant Solution<br />

In this compliant solution, the statements before the first case label occur before the switch statement:<br />

#include <br />

extern void f(int i);<br />

int func(int expr) {<br />

/*<br />

* Move the code outside the switch block; now the statements<br />

* will get executed.<br />

*/<br />

int i = 4;<br />

f(i);<br />

}<br />

switch (expr) {<br />

case 0:<br />

i = 17;<br />

/* Falls through into default code */<br />

default:<br />

printf("<br />

}<br />

return 0;<br />

œ%d \n"<br />

, i);<br />

3.8.3 Risk Assessment<br />

Using test conditions or initializing variables before the first case statement in a switch block<br />

can result in unexpected behavior and undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

DCL41-C Medium Unlikely Medium P4 L3<br />

3.8.4 Related Guidelines<br />

MISRA C:2012<br />

Rule 16.1 (required)<br />

3.8.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.8.4.2, “The switch Statement”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 67<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

4 Expressions (EXP)<br />

4.1 EXP30-C. Do not depend on the order of evaluation for side effects<br />

Evaluation of an expression may produce side effects. At specific points during execution, known<br />

as sequence points, all side effects of previous evaluations are complete, and no side effects of<br />

subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects<br />

unless there is an intervening sequence point.<br />

The C <strong>Standard</strong>, 6.5, paragraph 2 [ISO/IEC 9899:2011], states<br />

If a side effect on a scalar object is unsequenced relative to either a different side effect<br />

on the same scalar object or a value computation using the value of the same scalar object,<br />

the behavior is undefined. If there are multiple allowable orderings of the subexpressions<br />

of an expression, the behavior is undefined if such an unsequenced side effect<br />

occurs in any of the orderings.<br />

This requirement must be met for each allowable ordering of the subexpressions of a full expression;<br />

otherwise, the behavior is undefined. (See undefined behavior 35.)<br />

The following sequence points are defined in the C <strong>Standard</strong>, Annex C [ISO/IEC 9899:2011]:<br />

• Between the evaluations of the function designator and actual arguments in a function call<br />

and the actual call<br />

• Between the evaluations of the first and second operands of the following operators:<br />

− Logical AND: &&<br />

− Logical OR: ||<br />

− Comma: ,<br />

• Between the evaluations of the first operand of the conditional ?: operator and whichever of<br />

the second and third operands is evaluated<br />

• The end of a full declarator<br />

• Between the evaluation of a full expression and the next full expression to be evaluated; the<br />

following are full expressions:<br />

− An initializer that is not part of a compound literal<br />

− The expression in an expression statement<br />

− The controlling expression of a selection statement (if or switch)<br />

− The controlling expression of a while or do statement<br />

− Each of the (optional) expressions of a for statement<br />

− The (optional) expression in a return statement<br />

• Immediately before a library function returns<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 68<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

• After the actions associated with each formatted input/output function conversion specifier<br />

• Immediately before and immediately after each call to a comparison function, and also between<br />

any call to a comparison function and any movement of the objects passed as arguments<br />

to that call<br />

This rule means that statements such as<br />

i = i + 1;<br />

a[i] = i;<br />

have defined behavior, and statements such as the following do not:<br />

/* i is modified twice between sequence points */<br />

i = ++i + 1;<br />

/* i is read other than to determine the value to be stored */<br />

a[i++] = i;<br />

Not all instances of a comma in C code denote a usage of the comma operator. For example, the<br />

comma between arguments in a function call is not a sequence point. However, according to the C<br />

<strong>Standard</strong>, 6.5.2.2, paragraph 10 [ISO/IEC 9899:2011]<br />

Every evaluation in the calling function (including other function calls) that is not otherwise<br />

specifically sequenced before or after the execution of the body of the called function<br />

is indeterminately sequenced with respect to the execution of the called function.<br />

This rule means that the order of evaluation for function call arguments is unspecified and can<br />

happen in any order.<br />

4.1.1 Noncompliant Code Example<br />

Programs cannot safely rely on the order of evaluation of operands between sequence points. In<br />

this noncompliant code example, i is evaluated twice without an intervening sequence point so<br />

the behavior of the expression is undefined:<br />

#include <br />

void func(int i, int *b) {<br />

int a = i + b[++i];<br />

printf("%d, %d", a, i);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 69<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

4.1.2 Compliant Solution<br />

These examples are independent of the order of evaluation of the operands and can be interpreted<br />

in only one way:<br />

#include <br />

void func(int i, int *b) {<br />

int a;<br />

++i;<br />

a = i + b[i];<br />

printf("%d, %d", a, i);<br />

}<br />

Alternatively:<br />

#include <br />

void func(int i, int *b) {<br />

int a = i + b[i + 1];<br />

++i;<br />

printf("%d, %d", a, i);<br />

}<br />

4.1.3 Noncompliant Code Example<br />

The call to func() in this noncompliant code example has undefined behavior because there is<br />

no sequence point between the argument expressions:<br />

extern void func(int i, int j);<br />

void f(int i) {<br />

func(i++, i);<br />

}<br />

The first (left) argument expression reads the value of i (to determine the value to be stored) and<br />

then modifies i. The second (right) argument expression reads the value of i between the same<br />

pair of sequence points as the first argument, but not to determine the value to be stored in i. This<br />

additional attempt to read the value of i has undefined behavior.<br />

4.1.4 Compliant Solution<br />

This compliant solution is appropriate when the programmer intends for both arguments to<br />

func() to be equivalent:<br />

extern void func(int i, int j);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 70<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

void f(int i) {<br />

i++;<br />

func(i, i);<br />

}<br />

This compliant solution is appropriate when the programmer intends the second argument to be 1<br />

greater than the first:<br />

extern void func(int i, int j);<br />

void f(int i) {<br />

int j = i++;<br />

func(j, i);<br />

}<br />

4.1.5 Noncompliant Code Example<br />

The order of evaluation for function arguments is unspecified. This noncompliant code example<br />

exhibits unspecified behavior but not undefined behavior:<br />

extern void c(int i, int j);<br />

int glob;<br />

int a(void) {<br />

return glob + 10;<br />

}<br />

int b(void) {<br />

glob = 42;<br />

return glob;<br />

}<br />

void func(void) {<br />

c(a(), b());<br />

}<br />

It is unspecified what order a() and b() are called in; the only guarantee is that both a() and<br />

b() will be called before c() is called. If a() or b() rely on shared state when calculating their<br />

return value, as they do in this example, the resulting arguments passed to c() may differ between<br />

compilers or architectures.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 71<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

4.1.6 Compliant Solution<br />

In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified<br />

behavior occurs:<br />

extern void c(int i, int j);<br />

int glob;<br />

int a(void) {<br />

return glob + 10;<br />

}<br />

int b(void) {<br />

glob = 42;<br />

return glob;<br />

}<br />

void func(void) {<br />

int a_val, b_val;<br />

a_val = a();<br />

b_val = b();<br />

}<br />

c(a_val, b_val);<br />

4.1.7 Risk Assessment<br />

Attempting to modify an object multiple times between sequence points may cause that object to<br />

take on an unexpected value, which can lead to unexpected program behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP30-C Medium Probable Medium P8 L2<br />

4.1.8 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

EXP50-CPP. Do not depend on the order of<br />

evaluation for side effects<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java EXP05-J. Do not follow a write by a subsequent<br />

write or read of the same object within an<br />

expression<br />

ISO/IEC TR 24772:2013<br />

Operator Precedence/Order of Evaluation<br />

[JCW]<br />

Side-effects and Order of Evaluation [SAM]<br />

MISRA C:2012<br />

Rule 12.1 (advisory)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 72<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP30-C. Do not depend on the order of evaluation for side effects<br />

4.1.9 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Saks 2007]<br />

6.5, “Expressions”<br />

6.5.2.2, “Function Calls”<br />

Annex C, “Sequence Points”<br />

[Summit 2005] Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9,<br />

3.10a, 3.10b, and 3.11<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 73<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP32-C. Do not access a volatile object through a nonvolatile reference<br />

4.2 EXP32-C. Do not access a volatile object through a nonvolatile<br />

reference<br />

An object that has volatile-qualified type may be modified in ways unknown to the implementation<br />

or have other unknown side effects. Referencing a volatile object by using a non-volatile<br />

lvalue is undefined behavior. The C <strong>Standard</strong>, 6.7.3 [ISO/IEC 9899:2011], states<br />

If an attempt is made to refer to an object defined with a volatile-qualified type through<br />

use of an lvalue with non-volatile-qualified type, the behavior is undefined.<br />

See undefined behavior 65.<br />

4.2.1 Noncompliant Code Example<br />

In this noncompliant code example, a volatile object is accessed through a non-volatile-qualified<br />

reference, resulting in undefined behavior:<br />

#include <br />

void func(void) {<br />

static volatile int **ipp;<br />

static int *ip;<br />

static volatile int i = 0;<br />

printf("i = %d.\n", i);<br />

ipp = &ip; /* May produce a warning diagnostic */<br />

ipp = (int**) &ip; /* Constraint violation; may produce a warning<br />

diagnostic */<br />

*ipp = &i; /* Valid */<br />

if (*ip != 0) { /* Valid */<br />

/* ... */<br />

}<br />

}<br />

The assignment ipp = &ip is not safe because it allows the valid code that follows to reference<br />

the value of the volatile object i through the non-volatile-qualified reference ip. In this example,<br />

the compiler may optimize out the entire if block because *ip != 0 must be false if the object<br />

to which ip points is not volatile.<br />

4.2.1.1 Implementation Details<br />

This example compiles without warning on Microsoft Visual Studio 2013 when compiled in C<br />

mode (/TC) but causes errors when compiled in C++ mode (/TP).<br />

GCC 4.8.1 generates a warning but compiles successfully.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 74<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP32-C. Do not access a volatile object through a nonvolatile reference<br />

4.2.2 Compliant Solution<br />

In this compliant solution, ip is declared volatile:<br />

#include <br />

void func(void) {<br />

static volatile int **ipp;<br />

static volatile int *ip;<br />

static volatile int i = 0;<br />

}<br />

printf("i = %d.\n", i);<br />

ipp = &ip;<br />

*ipp = &i;<br />

if (*ip != 0) {<br />

/* ... */<br />

}<br />

4.2.3 Risk Assessment<br />

Accessing an object with a volatile-qualified type through a reference with a non-volatile-qualified<br />

type is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP32-C Low Likely Medium P6 L2<br />

4.2.4 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

MISRA C:2012<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

Pointer Casting and Pointer Type Changes<br />

[HFC]<br />

Type System [IHN]<br />

Rule 11.8 (required)<br />

EXP55-CPP. Do not access a cv-qualified object<br />

through a cv-unqualified type<br />

4.2.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.7.3, “Type Qualifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 75<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

4.3 EXP33-C. Do not read uninitialized memory<br />

Local, automatic variables assume unexpected values if they are read before they are initialized.<br />

The C <strong>Standard</strong>, 6.7.9, paragraph 10, specifies [ISO/IEC 9899:2011]<br />

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.<br />

See undefined behavior 11.<br />

When local, automatic variables are stored on the program stack, for example, their values default<br />

to whichever values are currently stored in stack memory.<br />

Additionally, some dynamic memory allocation functions do not initialize the contents of the<br />

memory they allocate.<br />

Function<br />

aligned_alloc()<br />

calloc()<br />

malloc()<br />

realloc()<br />

Initialization<br />

Does not perform initialization<br />

Zero-initializes allocated memory<br />

Does not perform initialization<br />

Copies contents from original pointer; may not initialize<br />

all memory<br />

Uninitialized automatic variables or dynamically allocated memory has indeterminate values,<br />

which, for objects of some types, can be a trap representation. Reading such trap representations<br />

is undefined behavior (see undefined behavior 10 and undefined behavior 12); it can cause a program<br />

to behave in an unexpected manner and provide an avenue for attack. In many cases, compilers<br />

issue a warning diagnostic message when reading uninitialized variables. (See MSC00-C.<br />

Compile cleanly at high warning levels for more information.)<br />

4.3.1 Noncompliant Code Example (Return-by-Reference)<br />

In this noncompliant code example, the set_flag() function is intended to set the parameter,<br />

sign_flag, to the sign of number. However, the programmer neglected to account for the case<br />

where number is equal to 0. Because the local variable sign is uninitialized when calling<br />

set_flag() and is never written to by set_flag(), the comparison operation exhibits undefined<br />

behavior when reading sign.<br />

void set_flag(int number, int *sign_flag) {<br />

if (NULL == sign_flag) {<br />

return;<br />

}<br />

if (number > 0) {<br />

*sign_flag = 1;<br />

} else if (number < 0) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 76<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

}<br />

}<br />

*sign_flag = -1;<br />

int is_negative(int number) {<br />

int sign;<br />

set_flag(number, &sign);<br />

return sign < 0;<br />

}<br />

Some compilers assume that when the address of an uninitialized variable is passed to a function,<br />

the variable is initialized within that function. Because compilers frequently fail to diagnose any<br />

resulting failure to initialize the variable, the programmer must apply additional scrutiny to ensure<br />

the correctness of the code.<br />

This defect results from a failure to consider all possible data states. (See MSC01-C. Strive for<br />

logical completeness for more information.)<br />

4.3.2 Compliant Solution (Return-by-Reference)<br />

This compliant solution trivially repairs the problem by accounting for the possibility that number<br />

can be equal to 0.<br />

Although compilers and static analysis tools often detect uses of uninitialized variables when they<br />

have access to the source code, diagnosing the problem is difficult or impossible when either the<br />

initialization or the use takes place in object code for which the source code is inaccessible. Unless<br />

doing so is prohibitive for performance reasons, an additional defense-in-depth practice worth<br />

considering is to initialize local variables immediately after declaration.<br />

void set_flag(int number, int *sign_flag) {<br />

if (NULL == sign_flag) {<br />

return;<br />

}<br />

}<br />

/* Account for number being 0 */<br />

if (number >= 0) {<br />

*sign_flag = 1;<br />

} else {<br />

*sign_flag = -1;<br />

}<br />

int is_negative(int number) {<br />

int sign = 0; /* Initialize for defense-in-depth */<br />

set_flag(number, &sign);<br />

return sign < 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 77<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

4.3.3 Noncompliant Code Example (Uninitialized Local)<br />

In this noncompliant code example, the programmer mistakenly fails to set the local variable error_log<br />

to the msg argument in the report_error() function [Mercy 2006]. Because error_log<br />

has not been initialized, an indeterminate value is read. The sprintf() call copies data<br />

from the arbitrary location pointed to by the indeterminate error_log variable until a null byte is<br />

reached, which can result in a buffer overflow.<br />

#include <br />

/* Get username and password from user, return -1 on error */<br />

extern int do_auth(void);<br />

enum { BUFFERSIZE = 24 };<br />

void report_error(const char *msg) {<br />

const char *error_log;<br />

char buffer[BUFFERSIZE];<br />

}<br />

sprintf(buffer, "Error: %s", error_log);<br />

printf("%s\n", buffer);<br />

int main(void) {<br />

if (do_auth() == -1) {<br />

report_error("Unable to login");<br />

}<br />

return 0;<br />

}<br />

4.3.4 Noncompliant Code Example (Uninitialized Local)<br />

In this noncompliant code example, the report_error() function has been modified so that<br />

error_log is properly initialized:<br />

#include <br />

enum { BUFFERSIZE = 24 };<br />

void report_error(const char *msg) {<br />

const char *error_log = msg;<br />

char buffer[BUFFERSIZE];<br />

}<br />

sprintf(buffer, "Error: %s", error_log);<br />

printf("%s\n", buffer);<br />

This example remains problematic because a buffer overflow will occur if the null-terminated<br />

byte string referenced by msg is greater than 17 characters, including the null terminator. (See<br />

STR31-C. Guarantee that storage for strings has sufficient space for character data and the null<br />

terminator for more information.)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 78<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

4.3.5 Compliant Solution (Uninitialized Local)<br />

In this compliant solution, the buffer overflow is eliminated by calling the snprintf() function:<br />

#include <br />

enum { BUFFERSIZE = 24 };<br />

void report_error(const char *msg) {<br />

char buffer[BUFFERSIZE];<br />

}<br />

if (0 < snprintf(buffer, BUFFERSIZE, "Error: %s", msg))<br />

printf("%s\n", buffer);<br />

else<br />

puts("Unknown error");<br />

4.3.6 Compliant Solution (Uninitialized Local)<br />

A less error-prone compliant solution is to simply print the error message directly instead of using<br />

an intermediate buffer:<br />

#include <br />

void report_error(const char *msg) {<br />

printf("Error: %s\n", msg);<br />

}<br />

4.3.7 Noncompliant Code Example (mbstate_t)<br />

In this noncompliant code example, the function mbrlen() is passed the address of an automatic<br />

mbstate_t object that has not been properly initialized. This is undefined behavior 200 because<br />

mbrlen() dereferences and reads its third argument.<br />

#include <br />

#include <br />

void func(const char *mbs) {<br />

size_t len;<br />

mbstate_t state;<br />

}<br />

len = mbrlen(mbs, strlen(mbs), &state);<br />

4.3.8 Compliant Solution (mbstate_t)<br />

Before being passed to a multibyte conversion function, an mbstate_t object must be either initialized<br />

to the initial conversion state or set to a value that corresponds to the most recent shift<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 79<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

state by a prior call to a multibyte conversion function. This compliant solution sets the<br />

mbstate_t object to the initial conversion state by setting it to all zeros:<br />

#include <br />

#include <br />

void func(const char *mbs) {<br />

size_t len;<br />

mbstate_t state;<br />

}<br />

memset(&state, 0, sizeof(state));<br />

len = mbrlen(mbs, strlen(mbs), &state);<br />

4.3.9 Noncompliant Code Example (POSIX, Entropy)<br />

In this noncompliant code example described in “More Randomness or Less” [Wang 2012], the<br />

process ID, time of day, and uninitialized memory junk is used to seed a random number generator.<br />

This behavior is characteristic of some distributions derived from Debian Linux that use uninitialized<br />

memory as a source of entropy because the value stored in junk is indeterminate. However,<br />

because accessing an indeterminate value is undefined behavior, compilers may optimize<br />

out the uninitialized variable access completely, leaving only the time and process ID and resulting<br />

in a loss of desired entropy.<br />

#include <br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

struct timeval tv;<br />

unsigned long junk;<br />

}<br />

gettimeofday(&tv, NULL);<br />

srandom((getpid()


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

#include <br />

#include <br />

void func(void) {<br />

double cpu_time;<br />

struct timeval tv;<br />

}<br />

cpu_time = ((double) clock()) / CLOCKS_PER_SEC;<br />

gettimeofday(&tv, NULL);<br />

srandom((getpid()


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

if (0 == array) {<br />

/* Handle error */<br />

}<br />

for (size_t i = 0; i < OLD_SIZE; ++i) {<br />

array[i] = i;<br />

}<br />

array = resize_array(array, NEW_SIZE);<br />

if (0 == array) {<br />

/* Handle error */<br />

}<br />

}<br />

for (size_t i = 0; i < NEW_SIZE; ++i) {<br />

printf("%d ", array[i]);<br />

}<br />

4.3.12 Compliant Solution (realloc())<br />

In this compliant solution, the resize_array() helper function takes a second parameter for the<br />

old size of the array so that it can initialize any newly allocated elements:<br />

#include <br />

#include <br />

#include <br />

enum { OLD_SIZE = 10, NEW_SIZE = 20 };<br />

int *resize_array(int *array, size_t old_count, size_t new_count) {<br />

if (0 == new_count) {<br />

return 0;<br />

}<br />

int *ret = (int *)realloc(array, new_count * sizeof(int));<br />

if (!ret) {<br />

free(array);<br />

return 0;<br />

}<br />

if (new_count > old_count) {<br />

memset(ret + old_count, 0, (new_count – old_count) *<br />

sizeof(int));<br />

}<br />

}<br />

return ret;<br />

void func(void) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 82<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

int *array = (int *)malloc(OLD_SIZE * sizeof(int));<br />

if (0 == array) {<br />

/* Handle error */<br />

}<br />

for (size_t i = 0; i < OLD_SIZE; ++i) {<br />

array[i] = i;<br />

}<br />

array = resize_array(array, OLD_SIZE, NEW_SIZE);<br />

if (0 == array) {<br />

/* Handle error */<br />

}<br />

}<br />

for (size_t i = 0; i < NEW_SIZE; ++i) {<br />

printf("%d ", array[i]);<br />

}<br />

4.3.13 Exceptions<br />

EXP33-C-EX1: Reading uninitialized memory by an lvalue of type unsigned char does not<br />

trigger undefined behavior. The unsigned char type is defined to not have a trap representation<br />

(see the C <strong>Standard</strong>, 6.2.6.1, paragraph 3), which allows for moving bytes without knowing if they<br />

are initialized. However, on some architectures, such as the Intel Itanium, registers have a bit to<br />

indicate whether or not they have been initialized. The C <strong>Standard</strong>, 6.3.2.1, paragraph 2, allows<br />

such implementations to cause a trap for an object that never had its address taken and is stored in<br />

a register if such an object is referred to in any way.<br />

4.3.14 Risk Assessment<br />

Reading uninitialized variables is undefined behavior and can result in unexpected program behavior.<br />

In some cases, these security flaws may allow the execution of arbitrary code.<br />

Reading uninitialized variables for creating entropy is problematic because these memory accesses<br />

can be removed by compiler optimization. VU#925211 is an example of a vulnerability<br />

caused by this coding error.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP33-C High Probable Medium P12 L1<br />

4.3.14.1 Related Vulnerabilities<br />

CVE-2009-1888 results from a violation of this rule. Some versions of SAMBA (up to 3.3.5) call<br />

a function that takes in two potentially uninitialized variables involving access rights. An attacker<br />

can exploit these coding errors to bypass the access control list and gain access to protected files<br />

[xorl 2009].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 83<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP33-C. Do not read uninitialized memory<br />

4.3.15 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

MSC00-C. Compile cleanly at high warning<br />

levels<br />

MSC01-C. Strive for logical completeness<br />

EXP53-CPP. Do not read uninitialized memory<br />

Initialization of Variables [LAV]<br />

Referencing uninitialized memory [uninitref]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-665, Improper Initialization<br />

4.3.16 Bibliography<br />

[Flake 2006]<br />

[ISO/IEC 9899:2011]<br />

[Mercy 2006]<br />

[VU#925211]<br />

[Wang 2012]<br />

[xorl 2009]<br />

Subclause 6.7.9, “Initialization”<br />

Subclause 6.2.6.1, “General”<br />

Subclause 6.3.2.1, “Lvalues, Arrays, and Function<br />

Designators”<br />

“More Randomness or Less”<br />

“CVE-2009-1888: SAMBA ACLs Uninitialized<br />

Memory Read”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 84<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP34-C. Do not dereference null pointers<br />

4.4 EXP34-C. Do not dereference null pointers<br />

Dereferencing a null pointer is undefined behavior.<br />

On many platforms, dereferencing a null pointer results in abnormal program termination, but this<br />

is not required by the standard. See “Clever Attack Exploits Fully-Patched Linux Kernel”<br />

[Goodin 2009] for an example of a code execution exploit that resulted from a null pointer dereference.<br />

4.4.1 Noncompliant Code Example<br />

This noncompliant code example is derived from a real-world example taken from a vulnerable<br />

version of the libpng library as deployed on a popular ARM-based cell phone [Jack 2007]. The<br />

libpng library allows applications to read, create, and manipulate PNG (Portable Network<br />

Graphics) raster image files. The libpng library implements its own wrapper to malloc() that<br />

returns a null pointer on error or on being passed a 0-byte-length argument.<br />

This code also violates ERR33-C. Detect and handle standard library errors.<br />

#include /* From libpng */<br />

#include <br />

void func(png_structp png_ptr, int length, const void *user_data) {<br />

png_charp chunkdata;<br />

chunkdata = (png_charp)png_malloc(png_ptr, length + 1);<br />

/* ... */<br />

memcpy(chunkdata, user_data, length);<br />

/* ... */<br />

}<br />

If length has the value −1, the addition yields 0, and png_malloc() subsequently returns a null<br />

pointer, which is assigned to chunkdata. The chunkdata pointer is later used as a destination<br />

argument in a call to memcpy(), resulting in user-defined data overwriting memory starting at address<br />

0. In the case of the ARM and XScale architectures, the 0x0 address is mapped in memory<br />

and serves as the exception vector table; consequently, dereferencing 0x0 did not cause an abnormal<br />

program termination.<br />

4.4.2 Compliant Solution<br />

This compliant solution ensures that the pointer returned by png_malloc() is not null. It also<br />

uses the unsigned type size_t to pass the length parameter, ensuring that negative values are<br />

not passed to func().<br />

#include /* From libpng */<br />

#include <br />

void func(png_structp png_ptr, size_t length, const void<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 85<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP34-C. Do not dereference null pointers<br />

*user_data) {<br />

png_charp chunkdata;<br />

if (length == SIZE_MAX) {<br />

/* Handle error */<br />

}<br />

chunkdata = (png_charp)png_malloc(png_ptr, length + 1);<br />

if (NULL == chunkdata) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

memcpy(chunkdata, user_data, length);<br />

/* ... */<br />

}<br />

4.4.3 Noncompliant Code Example<br />

In this noncompliant code example, input_str is copied into dynamically allocated memory referenced<br />

by c_str. If malloc() fails, it returns a null pointer that is assigned to c_str. When<br />

c_str is dereferenced in memcpy(), the program exhibits undefined behavior. Additionally, if<br />

input_str is a null pointer, the call to strlen() dereferences a null pointer, also resulting in<br />

undefined behavior. This code also violates ERR33-C. Detect and handle standard library errors.<br />

#include <br />

#include <br />

void f(const char *input_str) {<br />

size_t size = strlen(input_str) + 1;<br />

char *c_str = (char *)malloc(size);<br />

memcpy(c_str, input_str, size);<br />

/* ... */<br />

free(c_str);<br />

c_str = NULL;<br />

/* ... */<br />

}<br />

4.4.4 Compliant Solution<br />

This compliant solution ensures that both input_str and the pointer returned by malloc() are<br />

not null:<br />

#include <br />

#include <br />

void f(const char *input_str) {<br />

size_t size;<br />

char *c_str;<br />

if (NULL == input_str) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 86<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP34-C. Do not dereference null pointers<br />

}<br />

/* Handle error */<br />

}<br />

size = strlen(input_str) + 1;<br />

c_str = (char *)malloc(size);<br />

if (NULL == c_str) {<br />

/* Handle error */<br />

}<br />

memcpy(c_str, input_str, size);<br />

/* ... */<br />

free(c_str);<br />

c_str = NULL;<br />

/* ... */<br />

4.4.5 Noncompliant Code Example<br />

This noncompliant code example is from a version of drivers/net/tun.c and affects Linux<br />

Kernel 2.6.30 [Goodin 2009]:<br />

static unsigned int tun_chr_poll(struct file *file, poll_table<br />

*wait) {<br />

struct tun_file *tfile = file->private_data;<br />

struct tun_struct *tun = __tun_get(tfile);<br />

struct sock *sk = tun->sk;<br />

unsigned int mask = 0;<br />

if (!tun)<br />

return POLLERR;<br />

DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);<br />

poll_wait(file, &tun->socket.wait, wait);<br />

if (!skb_queue_empty(&tun->readq))<br />

mask |= POLLIN | POLLRDNORM;<br />

if (sock_writeable(sk) ||<br />

(!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)<br />

&&<br />

sock_writeable(sk)))<br />

mask |= POLLOUT | POLLWRNORM;<br />

}<br />

if (tun->dev->reg_state != NETREG_REGISTERED)<br />

mask = POLLERR;<br />

tun_put(tun);<br />

return mask;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 87<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP34-C. Do not dereference null pointers<br />

The sk pointer is initialized to tun->sk before checking if tun is a null pointer. Because null<br />

pointer dereferencing is undefined behavior, the compiler (GCC in this case) can optimize away<br />

the if (!tun) check because it is performed after tun->sk is accessed, implying that tun is<br />

non-null. As a result, this noncompliant code example is vulnerable to a null pointer dereference<br />

exploit, because null pointer dereferencing can be permitted on several platforms, for example, by<br />

using mmap(2) with the MAP_FIXED flag on Linux and Mac OS X, or by using the shmat()<br />

POSIX function with the SHM_RND flag [Liu 2009].<br />

4.4.6 Compliant Solution<br />

This compliant solution eliminates the null pointer deference by initializing sk to tun->sk following<br />

the null pointer check:<br />

static unsigned int tun_chr_poll(struct file *file, poll_table<br />

*wait) {<br />

struct tun_file *tfile = file->private_data;<br />

struct tun_struct *tun = __tun_get(tfile);<br />

struct sock *sk;<br />

unsigned int mask = 0;<br />

}<br />

if (!tun)<br />

return POLLERR;<br />

sk = tun->sk;<br />

/* The remaining code is omitted because it is unchanged... */<br />

4.4.7 Risk Assessment<br />

Dereferencing a null pointer is undefined behavior, typically abnormal program termination. In<br />

some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code<br />

[Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case; on platforms<br />

where it is not possible to exploit a null pointer dereference to execute arbitrary code, the actual<br />

severity is low.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP34-C High Likely Medium P18 L1<br />

4.4.8 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java EXP01-J. Do not use a null in a case where an<br />

object is required<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 88<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP34-C. Do not dereference null pointers<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Pointer Casting and Pointer Type Changes<br />

[HFC]<br />

Null Pointer Dereference [XYH]<br />

Dereferencing an out-of-domain pointer<br />

[nullref]<br />

CWE-476, NULL Pointer Dereference<br />

4.4.9 Bibliography<br />

[Goodin 2009]<br />

[Jack 2007]<br />

[Liu 2009]<br />

[van Sprundel 2006]<br />

[Viega 2005]<br />

Section 5.2.18, “Null-Pointer Dereference”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 89<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP35-C. Do not modify objects with temporary lifetime<br />

4.5 EXP35-C. Do not modify objects with temporary lifetime<br />

The C11 <strong>Standard</strong> [ISO/IEC 9899:2011] introduced a new term: temporary lifetime. Modifying an<br />

object with temporary lifetime is undefined behavior. According to subclause 6.2.4, paragraph 8<br />

A non-lvalue expression with structure or union type, where the structure or union contains<br />

a member with array type (including, recursively, members of all contained structures<br />

and unions) refers to an object with automatic storage duration and temporary lifetime.<br />

Its lifetime begins when the expression is evaluated and its initial value is the value<br />

of the expression. Its lifetime ends when the evaluation of the containing full expression<br />

or full declarator ends. Any attempt to modify an object with temporary lifetime results in<br />

undefined behavior.<br />

This definition differs from the C99 <strong>Standard</strong> (which defines modifying the result of a function<br />

call or accessing it after the next sequence point as undefined behavior) because a temporary object’s<br />

lifetime ends when the evaluation containing the full expression or full declarator ends, so<br />

the result of a function call can be accessed. This extension to the lifetime of a temporary also removes<br />

a quiet change to C90 and improves compatibility with C++.<br />

C functions may not return arrays; however, functions can return a pointer to an array or a<br />

struct or union that contains arrays. Consequently, if a function call returns by value a struct<br />

or union containing an array, do not modify those arrays within the expression containing the<br />

function call. Do not access an array returned by a function after the next sequence point or after<br />

the evaluation of the containing full expression or full declarator ends.<br />

4.5.1 Noncompliant Code Example (C99)<br />

This noncompliant code example conforms to the C11 <strong>Standard</strong>; however, it fails to conform to<br />

C99. If compiled with a C99-conforming implementation, this code has undefined behavior because<br />

the sequence point preceding the call to printf() comes between the call and the access<br />

by printf() of the string in the returned object.<br />

#include <br />

struct X { char a[8]; };<br />

struct X salutation(void) {<br />

struct X result = { "Hello" };<br />

return result;<br />

}<br />

struct X addressee(void) {<br />

struct X result = { "world" };<br />

return result;<br />

}<br />

int main(void) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 90<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP35-C. Do not modify objects with temporary lifetime<br />

}<br />

printf("%s, %s!\n", salutation().a, addressee().a);<br />

return 0;<br />

4.5.2 Compliant Solution<br />

This compliant solution stores the structures returned by the call to addressee() before calling<br />

the printf() function. Consequently, this program conforms to both C99 and C11.<br />

#include <br />

struct X { char a[8]; };<br />

struct X salutation(void) {<br />

struct X result = { "Hello" };<br />

return result;<br />

}<br />

struct X addressee(void) {<br />

struct X result = { "world" };<br />

return result;<br />

}<br />

int main(void) {<br />

struct X my_salutation = salutation();<br />

struct X my_addressee = addressee();<br />

}<br />

printf("%s, %s!\n", my_salutation.a, my_addressee.a);<br />

return 0;<br />

4.5.3 Noncompliant Code Example<br />

This noncompliant code example attempts to retrieve an array and increment the array’s first<br />

value. The array is part of a struct that is returned by a function call. Consequently, the array<br />

has temporary lifetime, and modifying the array is undefined behavior.<br />

#include <br />

struct X { int a[6]; };<br />

struct X addressee(void) {<br />

struct X result = { { 1, 2, 3, 4, 5, 6 } };<br />

return result;<br />

}<br />

int main(void) {<br />

printf("%x", ++(addressee().a[0]));<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 91<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP35-C. Do not modify objects with temporary lifetime<br />

}<br />

return 0;<br />

4.5.4 Compliant Solution<br />

This compliant solution stores the structure returned by the call to addressee() as my_x before<br />

calling the printf() function. When the array is modified, its lifetime is no longer temporary<br />

but matches the lifetime of the block in main().<br />

#include <br />

struct X { int a[6]; };<br />

struct X addressee(void) {<br />

struct X result = { { 1, 2, 3, 4, 5, 6 } };<br />

return result;<br />

}<br />

int main(void) {<br />

struct X my_x = addressee();<br />

printf("%x", ++(my_x.a[0]));<br />

return 0;<br />

}<br />

4.5.5 Risk Assessment<br />

Attempting to modify an array or access it after its lifetime expires may result in erroneous program<br />

behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP35-C Low Probable Medium P4 L3<br />

4.5.6 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

Dangling References to Stack Frames [DCM]<br />

Side-effects and Order of Evaluation [SAM]<br />

4.5.7 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.2.4, “Storage Durations of Objects”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 92<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP36-C. Do not cast pointers into more strictly aligned pointer types<br />

4.6 EXP36-C. Do not cast pointers into more strictly aligned pointer<br />

types<br />

Do not convert a pointer value to a pointer type that is more strictly aligned than the referenced<br />

type. Different alignments are possible for different types of objects. If the type-checking system<br />

is overridden by an explicit cast or the pointer is converted to a void pointer (void *) and then to<br />

a different type, the alignment of an object may be changed.<br />

The C <strong>Standard</strong>, 6.3.2.3, paragraph 7 [ISO/IEC 9899:2011], states<br />

A pointer to an object or incomplete type may be converted to a pointer to a different object<br />

or incomplete type. If the resulting pointer is not correctly aligned for the referenced<br />

type, the behavior is undefined.<br />

See undefined behavior 25.<br />

If the misaligned pointer is dereferenced, the program may terminate abnormally. On some architectures,<br />

the cast alone may cause a loss of information even if the value is not dereferenced if the<br />

types involved have differing alignment requirements.<br />

4.6.1 Noncompliant Code Example<br />

In this noncompliant example, the char pointer &c is converted to the more strictly aligned int<br />

pointer ip. On some implementations, cp will not match &c. As a result, if a pointer to one object<br />

type is converted to a pointer to a different object type, the second object type must not require<br />

stricter alignment than the first.<br />

#include <br />

void func(void) {<br />

char c = 'x';<br />

int *ip = (int *)&c; /* This can lose information */<br />

char *cp = (char *)ip;<br />

}<br />

/* Will fail on some conforming implementations */<br />

assert(cp == &c);<br />

4.6.2 Compliant Solution (Intermediate Object)<br />

In this compliant solution, the char value is stored into an object of type int so that the pointer's<br />

value will be properly aligned:<br />

#include <br />

void func(void) {<br />

char c = 'x';<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 93<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP36-C. Do not cast pointers into more strictly aligned pointer types<br />

int i = c;<br />

int *ip = &i;<br />

}<br />

assert(ip == &i);<br />

4.6.3 Noncompliant Code Example<br />

The C <strong>Standard</strong> allows any object pointer to be cast to and from void *. As a result, it is possible<br />

to silently convert from one pointer type to another without the compiler diagnosing the problem<br />

by storing or casting a pointer to void * and then storing or casting it to the final type. In this<br />

noncompliant code example, loop_function() is passed the char pointer loop_ptr but returns<br />

an object of type int pointer:<br />

int *loop_function(void *v_pointer) {<br />

/* ... */<br />

return v_pointer;<br />

}<br />

void func(char *loop_ptr) {<br />

int *int_ptr = loop_function(loop_ptr);<br />

}<br />

/* ... */<br />

This example compiles without warning using GCC 4.8 on Ubuntu Linux 14.04. However,<br />

v_pointer can be more strictly aligned than an object of type int *.<br />

4.6.4 Compliant Solution<br />

Because the input parameter directly influences the return value, and loop_function() returns<br />

an object of type int *, the formal parameter v_pointer is redeclared to accept only an object<br />

of type int *:<br />

int *loop_function(int *v_pointer) {<br />

/* ... */<br />

return v_pointer;<br />

}<br />

void func(int *loop_ptr) {<br />

int *int_ptr = loop_function(loop_ptr);<br />

}<br />

/* ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 94<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP36-C. Do not cast pointers into more strictly aligned pointer types<br />

4.6.5 Noncompliant Code Example<br />

Some architectures require that pointers are correctly aligned when accessing objects larger than a<br />

byte. However, it is common in system code that unaligned data (for example, the network stacks)<br />

must be copied to a properly aligned memory location, such as in this noncompliant code example:<br />

#include <br />

struct foo_header {<br />

int len;<br />

/* ... */<br />

};<br />

void func(char *data, size_t offset) {<br />

struct foo_header *tmp;<br />

struct foo_header header;<br />

tmp = (struct foo_header *)(data + offset);<br />

memcpy(&header, tmp, sizeof(header));<br />

}<br />

/* ... */<br />

Assigning an unaligned value to a pointer that references a type that needs to be aligned is undefined<br />

behavior. An implementation may notice, for example, that tmp and header must be<br />

aligned and use an inline memcpy() that uses instructions that assume aligned data.<br />

4.6.6 Compliant Solution<br />

This compliant solution avoids the use of the foo_header pointer:<br />

#include <br />

struct foo_header {<br />

int len;<br />

/* ... */<br />

};<br />

void func(char *data, size_t offset) {<br />

struct foo_header header;<br />

memcpy(&header, data + offset, sizeof(header));<br />

}<br />

/* ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 95<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP36-C. Do not cast pointers into more strictly aligned pointer types<br />

4.6.7 Exceptions<br />

EXP36-C-EX1: Some hardware architectures have relaxed requirements with regard to pointer<br />

alignment. Using a pointer that is not properly aligned is correctly handled by the architecture, although<br />

there might be a performance penalty. On such an architecture, improper pointer alignment<br />

is permitted but remains an efficiency problem.<br />

EXP36-C-EX2: If a pointer is known to be correctly aligned to the target type, then a cast to that<br />

type is permitted. There are several cases where a pointer is known to be correctly aligned to the<br />

target type. The pointer could point to an object declared with a suitable alignment specifier. It<br />

could point to an object returned by aligned_alloc(), calloc(), malloc(), or realloc(),<br />

as per the C standard, section 7.22.3, paragraph 1 [ISO/IEC 9899:2011].<br />

This compliant solution uses the alignment specifier, which is new to C11, to declare the char<br />

object c with the same alignment as that of an object of type int. As a result, the two pointers<br />

reference equally aligned pointer types:<br />

#include <br />

#include <br />

void func(void) {<br />

/* Align c to the alignment of an int */<br />

alignas(int) char c = 'x';<br />

int *ip = (int *)&c;<br />

char *cp = (char *)ip;<br />

/* Both cp and &c point to equally aligned objects */<br />

assert(cp == &c);<br />

}<br />

4.6.8 Risk Assessment<br />

Accessing a pointer or an object that is not properly aligned can cause a program to crash or give<br />

erroneous information, or it can cause slow pointer accesses (if the architecture allows misaligned<br />

accesses).<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP36-C Low Probable Medium P4 L3<br />

4.6.9 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

EXP56-CPP. Do not cast pointers into more<br />

strictly aligned pointer types<br />

Pointer Casting and Pointer Type Changes<br />

[HFC]<br />

Converting pointer values to more strictly<br />

aligned pointer types [alignconv]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 96<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP36-C. Do not cast pointers into more strictly aligned pointer types<br />

MISRA C:2012<br />

Rule 11.1 (required)<br />

Rule 11.2 (required)<br />

Rule 11.5 (advisory)<br />

Rule 11.7 (required)<br />

4.6.10 Bibliography<br />

[Bryant 2003]<br />

[ISO/IEC 9899:2011]<br />

6.3.2.3, “Pointers”<br />

[Walfridsson 2003] Aliasing, Pointer Casts and GCC 3.3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 97<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP37-C. Call functions with the correct number and type of arguments<br />

4.7 EXP37-C. Call functions with the correct number and type of<br />

arguments<br />

Do not call a function with the wrong number or type of arguments.<br />

The C <strong>Standard</strong> identifies five distinct situations in which undefined behavior (UB) may arise as a<br />

result of invoking a function using a declaration that is incompatible with its definition or by supplying<br />

incorrect types or numbers of arguments:<br />

UB<br />

Description<br />

26 A pointer is used to call a function whose type is not compatible with the referenced type<br />

(6.3.2.3).<br />

38 For a call to a function without a function prototype in scope, the number of arguments does<br />

not equal the number of parameters (6.5.2.2).<br />

39 For a call to a function without a function prototype in scope where the function is defined<br />

with a function prototype, either the prototype ends with an ellipsis or the types of the arguments<br />

after promotion are not compatible with the types of the parameters (6.5.2.2).<br />

40 For a call to a function without a function prototype in scope where the function is not defined<br />

with a function prototype, the types of the arguments after promotion are not compatible<br />

with those of the parameters after promotion (with certain exceptions) (6.5.2.2).<br />

41 A function is defined with a type that is not compatible with the type (of the expression)<br />

pointed to by the expression that denotes the called function (6.5.2.2).<br />

Functions that are appropriately declared (as in DCL40-C. Do not create incompatible declarations<br />

of the same function or object) will typically generate a compiler diagnostic message if they<br />

are supplied with the wrong number or types of arguments. However, there are cases in which<br />

supplying the incorrect arguments to a function will, at best, generate compiler warnings. Although<br />

such warnings should be resolved, they do not prevent program compilation. (See MSC00-<br />

C. Compile cleanly at high warning levels.)<br />

4.7.1 Noncompliant Code Example<br />

The header provides type-generic macros for math functions. Although most functions<br />

from the header have a complex counterpart in , several functions<br />

do not. Calling any of the following type-generic functions with complex values is undefined behavior.<br />

Functions That Should Not Be Called with Complex Values<br />

atan2() erf() fdim() fmin() ilogb()<br />

llround() logb() nextafter() rint() tgamma()<br />

cbrt() erfc() floor() fmod() ldexp()<br />

log10() lrint() nexttoward() round() trunc()<br />

ceil() exp2() fma() frexp() lgamma()<br />

log1p() lround() remainder() scalbn() copysign()<br />

expm1() fmax() hypot() llrint() log2()<br />

nearbyint() remquo() scalbln()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 98<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP37-C. Call functions with the correct number and type of arguments<br />

This noncompliant code example attempts to take the base-2 logarithm of a complex number, resulting<br />

in undefined behavior:<br />

#include <br />

void func(void) {<br />

double complex c = 2.0 + 4.0 * I;<br />

double complex result = log2(c);<br />

}<br />

4.7.2 Compliant Solution (Complex Number)<br />

If the clog2() function is not available for an implementation as an extension, the programmer<br />

can take the base-2 logarithm of a complex number, using log() instead of log2(), because<br />

log() can be used on complex arguments, as shown in this compliant solution:<br />

#include <br />

void func(void) {<br />

double complex c = 2.0 + 4.0 * I;<br />

double complex result = log(c)/log(2);<br />

}<br />

4.7.3 Compliant Solution (Real Number)<br />

The programmer can use this compliant solution if the intent is to take the base-2 logarithm of the<br />

real part of the complex number:<br />

#include <br />

void func(void) {<br />

double complex c = 2.0 + 4.0 * I;<br />

double complex result = log2(creal(c));<br />

}<br />

4.7.4 Noncompliant Code Example<br />

In this noncompliant example, the C standard library function strchr() is called through the<br />

function pointer fp declared with a prototype with incorrectly typed arguments. According to the<br />

C <strong>Standard</strong>, 6.3.2.3, paragraph 8 [ISO/IEC 9899:2011],<br />

A pointer to a function of one type may be converted to a pointer to a function of another<br />

type and back again; the result shall compare equal to the original pointer. If a converted<br />

pointer is used to call a function whose type is not compatible with the referenced type,<br />

the behavior is undefined.<br />

See undefined behavior 26.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 99<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP37-C. Call functions with the correct number and type of arguments<br />

#include <br />

#include <br />

char *(*fp)();<br />

int main(void) {<br />

const char *c;<br />

fp = strchr;<br />

c = fp('e', "Hello");<br />

printf("%s\n", c);<br />

return 0;<br />

}<br />

4.7.5 Compliant Solution<br />

In this compliant solution, the function pointer fp, which points to the C standard library function<br />

strchr(), is declared with the correct parameters and is invoked with the correct number and<br />

type of arguments:<br />

#include <br />

#include <br />

char *(*fp)(const char *, int);<br />

int main(void) {<br />

const char *c;<br />

fp = strchr;<br />

c = fp("Hello",'e');<br />

printf("%s\n", c);<br />

return 0;<br />

}<br />

4.7.6 Noncompliant Code Example<br />

In this noncompliant example, the function f() is defined to take an argument of type long but<br />

f() is called from another file with an argument of type int:<br />

/* In another source file */<br />

long f(long x) {<br />

return x < 0 ? -x : x;<br />

}<br />

/* In this source file, no f prototype in scope */<br />

long f();<br />

long g(int x) {<br />

return f(x);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 100<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP37-C. Call functions with the correct number and type of arguments<br />

4.7.7 Compliant Solution<br />

In this compliant solution, the prototype for the function f() is included in the source file in the<br />

scope of where it is called, and the function f() is correctly called with an argument of type<br />

long:<br />

/* In another source file */<br />

long f(long x) {<br />

return x < 0 ? -x : x;<br />

}<br />

/* f prototype in scope in this source file */<br />

long f(long x);<br />

long g(int x) {<br />

return f((long)x);<br />

}<br />

4.7.8 Noncompliant Code Example (POSIX)<br />

The POSIX function open() [IEEE Std 1003.1:2013] is a variadic function with the following<br />

prototype:<br />

int open(const char *path, int oflag, ... );<br />

The open() function accepts a third argument to determine a newly created file’s access mode. If<br />

open() is used to create a new file and the third argument is omitted, the file may be created with<br />

unintended access permissions. (See FIO06-C. Create files with appropriate access permissions.)<br />

In this noncompliant code example from a vulnerability in the useradd() function of the<br />

shadow-utils package CVE-2006-1174, the third argument to open() is accidentally omitted:<br />

fd = open(ms, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC);<br />

Technically, it is incorrect to pass a third argument to open() when not creating a new file (that<br />

is, with the O_CREAT flag not set).<br />

4.7.9 Compliant Solution (POSIX)<br />

In this compliant solution, a third argument is specified in the call to open():<br />

#include <br />

void func(const char *ms, mode_t perms) {<br />

/* ... */<br />

int fd;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 101<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP37-C. Call functions with the correct number and type of arguments<br />

}<br />

fd = open(ms, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, perms);<br />

if (fd == -1) {<br />

/* Handle error */<br />

}<br />

4.7.10 Risk Assessment<br />

Calling a function with incorrect arguments can result in unexpected or unintended program behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP37-C Medium Probable High P4 L3<br />

4.7.11 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MISRA C:2012<br />

MITRE CWE<br />

DCL07-C. Include the appropriate type information<br />

in function declarators<br />

MSC00-C. Compile cleanly at high warning<br />

levels<br />

FIO06-C. Create files with appropriate access<br />

permissions<br />

Subprogram Signature Mismatch [OTR]<br />

Calling functions with incorrect arguments [argcomp]<br />

Rule 8.2 (required)<br />

Rule 17.3 (mandatory)<br />

CWE-628, Function Call with Incorrectly<br />

Specified Arguments<br />

CWE-686, Function Call with Incorrect Argument<br />

Type<br />

4.7.12 Bibliography<br />

[CVE]<br />

[ISO/IEC 9899:2011]<br />

[IEEE Std 1003.1:2013]<br />

[Spinellis 2006]<br />

CVE-2006-1174<br />

6.3.2.3, “Pointers”<br />

6.5.2.2, “Function Calls”<br />

open()<br />

Section 2.6.1, “Incorrect Routine or Arguments”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 102<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

4.8 EXP39-C. Do not access a variable through a pointer of an<br />

incompatible type<br />

Modifying a variable through a pointer of an incompatible type (other than unsigned char) can<br />

lead to unpredictable results. Subclause 6.2.7 of the C <strong>Standard</strong> states that two types may be distinct<br />

yet compatible and addresses precisely when two distinct types are compatible.<br />

This problem is often caused by a violation of aliasing rules. The C <strong>Standard</strong>, 6.5, paragraph 7<br />

[ISO/IEC 9899:2011], specifies those circumstances in which an object may or may not be aliased.<br />

An object shall have its stored value accessed only by an lvalue expression that has<br />

one of the following types:<br />

• a type compatible with the effective type of the object,<br />

• a qualified version of a type compatible with the effective type of the object,<br />

• a type that is the signed or unsigned type corresponding to the effective type of the<br />

object,<br />

• a type that is the signed or unsigned type corresponding to a qualified version of<br />

the effective type of the object,<br />

• an aggregate or union type that includes one of the aforementioned types among<br />

its members (including, recursively, a member of a subaggregate or contained union),<br />

or<br />

• a character type.<br />

Accessing an object by means of any other lvalue expression (other than unsigned char) is undefined<br />

behavior 37.<br />

4.8.1 Noncompliant Code Example<br />

In this noncompliant example, an object of type float is incremented through an int *. The<br />

programmer can use the unit in the last place to get the next representable value for a floatingpoint<br />

type. However, accessing an object through a pointer of an incompatible type is undefined<br />

behavior.<br />

#include <br />

void f(void) {<br />

if (sizeof(int) == sizeof(float)) {<br />

float f = 0.0f;<br />

int *ip = (int *)&f;<br />

(*ip)++;<br />

printf("float is %f\n", f);<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 103<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

4.8.2 Compliant Solution<br />

In this compliant solution, the standard C function nextafterf() is used to round toward the<br />

highest representable floating-point value:<br />

#include <br />

#include <br />

#include <br />

void f(void) {<br />

float f = 0.0f;<br />

f = nextafterf(f, FLT_MAX);<br />

printf("float is %f\n", f);<br />

}<br />

4.8.3 Noncompliant Code Example<br />

In this noncompliant code example, an array of two values of type short is treated as an integer<br />

and assigned an integer value. The resulting values are indeterminate.<br />

#include <br />

void func(void) {<br />

short a[2];<br />

a[0]=0x1111;<br />

a[1]=0x1111;<br />

*(int *)a = 0x22222222;<br />

}<br />

printf("%x %x\n", a[0], a[1]);<br />

When translating this code, an implementation can assume that no access through an integer<br />

pointer can change the array a, consisting of shorts. Consequently, printf() may be called with<br />

the original values of a[0] and a[1].<br />

4.8.3.1 Implementation Details<br />

Recent versions of GCC turn on the option -fstrict-aliasing (which allows alias-based optimizations)<br />

by default with -O2. Some architectures then print “1111 1111” as a result. Without<br />

optimization, the executable generates the expected output “2222 2222.”<br />

To disable optimizations based on alias analysis for faulty legacy code, the option -fnostrict-aliasing<br />

can be used as a workaround. The option -Wstrict-aliasing (which is<br />

included in -Wall) warns about some, but not all, violations of aliasing rules when -fstrictaliasing<br />

is active.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 104<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

When GCC 3.4.6 compiles this code with optimization, the assignment through the aliased pointer<br />

is effectively eliminated.<br />

4.8.4 Compliant Solution<br />

This compliant solution uses a union type that includes a type compatible with the effective type<br />

of the object:<br />

#include <br />

void func(void) {<br />

union {<br />

short a[2];<br />

int i;<br />

} u;<br />

u.a[0]=0x1111;<br />

u.a[1]=0x1111;<br />

u.i = 0x22222222;<br />

printf("%x %x\n", u.a[0], u.a[1]);<br />

}<br />

/* ... */<br />

The printf() behavior in this compliant solution is unspecified, but it is commonly accepted as<br />

an implementation extension. (See unspecified behavior 11.)<br />

This function typically outputs “2222 2222.” However, there is no guarantee that this will be true,<br />

even on implementations that defined the unspecified behavior; values of type short need not<br />

have the same representation as values of type int.<br />

4.8.5 Noncompliant Code Example<br />

In this noncompliant code example, a gadget object is allocated, then realloc() is called to<br />

create a widget object using the memory from the gadget object. Although reusing memory to<br />

change types is acceptable, accessing the memory copied from the original object is undefined behavior.<br />

#include <br />

struct gadget {<br />

int i;<br />

double d;<br />

char *p;<br />

};<br />

struct widget {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 105<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

char *q;<br />

int j;<br />

double e;<br />

};<br />

void func(void) {<br />

struct gadget *gp;<br />

struct widget *wp;<br />

}<br />

gp = (struct gadget *)malloc(sizeof(struct gadget));<br />

if (!gp) {<br />

/* Handle error */<br />

}<br />

/* ... Initialize gadget ... */<br />

wp = (struct widget *)realloc(gp, sizeof(struct widget));<br />

if (!wp) {<br />

free(gp);<br />

/* Handle error */<br />

}<br />

if (wp->j == 12) {<br />

/* ... */<br />

}<br />

4.8.6 Compliant Solution<br />

This compliant solution reuses the memory from the gadget object but reinitializes the memory<br />

to a consistent state before reading from it:<br />

#include <br />

#include <br />

struct gadget {<br />

int i;<br />

double d;<br />

char *p;<br />

};<br />

struct widget {<br />

char *q;<br />

int j;<br />

double e;<br />

};<br />

void func(void) {<br />

struct gadget *gp;<br />

struct widget *wp;<br />

gp = (struct gadget *)malloc(sizeof (struct gadget));<br />

if (!gp) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 106<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

/* Handle error */<br />

}<br />

/* ... */<br />

wp = (struct widget *)realloc(gp, sizeof(struct widget));<br />

if (!wp) {<br />

free(gp);<br />

/* Handle error */<br />

}<br />

memset(wp, 0, sizeof(struct widget));<br />

/* ... Initialize widget ... */<br />

}<br />

if (wp->j == 12) {<br />

/* ... */<br />

}<br />

4.8.7 Noncompliant Code Example<br />

According to the C <strong>Standard</strong>, 6.7.6.2 [ISO/IEC 9899:2011], using two or more incompatible arrays<br />

in an expression is undefined behavior. (See also undefined behavior 76.)<br />

For two array types to be compatible, both should have compatible underlying element types, and<br />

both size specifiers should have the same constant value. If either of these properties is violated,<br />

the resulting behavior is undefined.<br />

In this noncompliant code example, the two arrays a and b fail to satisfy the equal size specifier<br />

criterion for array compatibility. Because a and b are not equal, writing to what is believed to be a<br />

valid member of a might exceed its defined memory boundary, resulting in an arbitrary memory<br />

overwrite.<br />

enum { ROWS = 10, COLS = 15 };<br />

void func(void) {<br />

int a[ROWS][COLS];<br />

int (*b)[ROWS] = a;<br />

}<br />

Most compilers will produce a warning diagnostic if the two array types used in an expression are<br />

incompatible.<br />

4.8.8 Compliant Solution<br />

In this compliant solution, b is declared to point to an array with the same number of elements as<br />

a, satisfying the size specifier criterion for array compatibility:<br />

enum { ROWS = 10, COLS = 15 };<br />

void func(void) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 107<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP39-C. Do not access a variable through a pointer of an incompatible type<br />

}<br />

int a[ROWS][COLS];<br />

int (*b)[COLS] = a;<br />

4.8.9 Risk Assessment<br />

Optimizing for performance can lead to aliasing errors that can be quite difficult to detect. Furthermore,<br />

as in the preceding example, unexpected results can lead to buffer overflow attacks, bypassing<br />

security checks, or unexpected execution.<br />

Recommendation Severity Likelihood Remediation Cost Priority Level<br />

EXP39-C Medium Unlikely High P2 L3<br />

4.8.10 Related Guidelines<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Accessing an object through a pointer to an incompatible<br />

type [ptrcomp]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

4.8.11 Bibliography<br />

[Acton 2006]<br />

“Understanding Strict Aliasing”<br />

GCC Known Bugs<br />

“C Bugs, Aliasing Issues while Casting to Incompatible<br />

Types”<br />

[ISO/IEC 9899:2011]<br />

6.5, “Expressions”<br />

6.7.6.2, “Array Declarators”<br />

[Walfridsson 2003] Aliasing, Pointer Casts and GCC 3.3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 108<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP40-C. Do not modify constant objects<br />

4.9 EXP40-C. Do not modify constant objects<br />

The C <strong>Standard</strong>, 6.7.3, paragraph 6 [ISO/IEC 9899:2011], states<br />

If an attempt is made to modify an object defined with a const-qualified type through<br />

use of an lvalue with non-const-qualified type, the behavior is undefined.<br />

See also undefined behavior 64.<br />

There are existing compiler implementations that allow const-qualified objects to be modified<br />

without generating a warning message.<br />

Avoid casting away const qualification because doing so makes it possible to modify constqualified<br />

objects without issuing diagnostics. (See EXP05-C. Do not cast away a const qualification<br />

and STR30-C. Do not attempt to modify string literals for more details.)<br />

4.9.1 Noncompliant Code Example<br />

This noncompliant code example allows a constant object to be modified:<br />

const int **ipp;<br />

int *ip;<br />

const int i = 42;<br />

void func(void) {<br />

ipp = &ip; /* Constraint violation */<br />

*ipp = &i; /* Valid */<br />

*ip = 0; /* Modifies constant i (was 42) */<br />

}<br />

The first assignment is unsafe because it allows the code that follows it to attempt to change the<br />

value of the const object i.<br />

4.9.1.1 Implementation Details<br />

If ipp, ip, and i are declared as automatic variables, this example compiles without warning with<br />

Microsoft Visual Studio 2013 when compiled in C mode (/TC) and the resulting program changes<br />

the value of i. GCC 4.8.1 generates a warning but compiles, and the resulting program changes<br />

the value of i.<br />

If ipp, ip, and i are declared with static storage duration, this program compiles without warning<br />

and terminates abnormally with Microsoft Visual Studio 2013, and compiles with warning and<br />

terminates abnormally with GCC 4.8.1.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 109<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP40-C. Do not modify constant objects<br />

4.9.2 Compliant Solution<br />

The compliant solution depends on the intent of the programmer. If the intent is that the value of i<br />

is modifiable, then it should not be declared as a constant, as in this compliant solution:<br />

int **ipp;<br />

int *ip;<br />

int i = 42;<br />

void func(void) {<br />

ipp = &ip; /* Valid */<br />

*ipp = &i; /* Valid */<br />

*ip = 0; /* Valid */<br />

}<br />

If the intent is that the value of i is not meant to change, then do not write noncompliant code that<br />

attempts to modify it.<br />

4.9.3 Risk Assessment<br />

Modifying constant objects through nonconstant references is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP40-C Low Unlikely Medium P2 L3<br />

4.9.4 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

EXP05-C. Do not cast away a const qualification<br />

STR30-C. Do not attempt to modify string literals<br />

4.9.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 6.7.3, “Type Qualifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 110<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP42-C. Do not compare padding data<br />

4.10 EXP42-C. Do not compare padding data<br />

The C <strong>Standard</strong>, 6.7.2.1 [ISO/IEC 9899:2011], states<br />

There may be unnamed padding within a structure object, but not at its beginning. . . .<br />

There may be unnamed padding at the end of a structure or union.<br />

Subclause 6.7.9, paragraph 9, states that<br />

unnamed members of objects of structure and union type do not participate in initialization.<br />

Unnamed members of structure objects have indeterminate value even after initialization.<br />

The only exception is that padding bits are set to zero when a static or thread-local object is implicitly<br />

initialized (paragraph10):<br />

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.<br />

If an object that has static or thread storage duration is not initialized explicitly,<br />

then:<br />

• if it is an aggregate, every member is initialized (recursively) according to these rules,<br />

and any padding is initialized to zero bits;<br />

• if it is a union, the first named member is initialized (recursively) according to these<br />

rules, and any padding is initialized to zero bits;<br />

Because these padding values are unspecified, attempting a byte-by-byte comparison between<br />

structures can lead to incorrect results [Summit 1995].<br />

4.10.1 Noncompliant Code Example<br />

In this noncompliant code example, memcmp() is used to compare the contents of two structures,<br />

including any padding bytes:<br />

#include <br />

struct s {<br />

char c;<br />

int i;<br />

char buffer[13];<br />

};<br />

void compare(const struct s *left, const struct s *right) {<br />

if (0 == memcmp(left, right, sizeof(struct s))) {<br />

/* ... */<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 111<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP42-C. Do not compare padding data<br />

4.10.2 Compliant Solution<br />

In this compliant solution, all of the fields are compared manually to avoid comparing any padding<br />

bytes:<br />

#include <br />

struct s {<br />

char c;<br />

int i;<br />

char buffer[13];<br />

};<br />

void compare(const struct s *left, const struct s *right) {<br />

if ((left && right) &&<br />

(left->c == right->c) &&<br />

(left->i == right->i) &&<br />

(0 == memcmp(left->buffer, right->buffer, 13))) {<br />

/* ... */<br />

}<br />

}<br />

4.10.3 Exceptions<br />

EXP42-C-EX1: A structure can be defined such that the members are aligned properly or the<br />

structure is packed using implementation-specific packing instructions. This is true only when the<br />

members’ data types have no padding bits of their own and when their object representations are<br />

the same as their value representations. This frequently is not true for the _Bool type or floatingpoint<br />

types and need not be true for pointers. In such cases, the compiler does not insert padding,<br />

and use of functions such as memcmp() is acceptable.<br />

This compliant example uses the #pragma pack compiler extension from Microsoft Visual Studio<br />

to ensure the structure members are packed as tightly as possible:<br />

#include <br />

#pragma pack(push, 1)<br />

struct s {<br />

char c;<br />

int i;<br />

char buffer[13];<br />

};<br />

#pragma pack(pop)<br />

void compare(const struct s *left, const struct s *right) {<br />

if (0 == memcmp(left, right, sizeof(struct s))) {<br />

/* ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 112<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP42-C. Do not compare padding data<br />

}<br />

}<br />

4.10.4 Risk Assessment<br />

Comparing padding bytes, when present, can lead to unexpected program behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP42-C Medium Probable Medium P8 L2<br />

4.10.5 Related Guidelines<br />

ISO/IEC TS 17961<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

Comparison of padding data [padcomp]<br />

EXP62-CPP. Do not access the bits of an object<br />

representation that are not part of the object’s<br />

value representation<br />

4.10.6 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Summit 1995] Question 2.8<br />

Question 2.12<br />

6.7.2.1, “Structure and Union Specifiers”<br />

6.7.9, “Initialization”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 113<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

4.11 EXP43-C. Avoid undefined behavior when using restrict-qualified<br />

pointers<br />

An object that is accessed through a restrict-qualified pointer has a special association with<br />

that pointer. This association requires that all accesses to that object use, directly or indirectly, the<br />

value of that particular pointer. The intended use of the restrict qualifier is to promote optimization,<br />

and deleting all instances of the qualifier from a program does not change its meaning (that<br />

is, observable behavior). In the absence of this qualifier, other pointers can alias this object. Caching<br />

the value in an object designated through a restrict-qualified pointer is safe at the beginning<br />

of the block in which the pointer is declared because no preexisting aliases may also be used<br />

to reference that object. The cached value must be restored to the object by the end of the block,<br />

where preexisting aliases again become available. New aliases may be formed within the block,<br />

but these must all depend on the value of the restrict-qualified pointer so that they can be identified<br />

and adjusted to refer to the cached value. For a restrict-qualified pointer at file scope,<br />

the block is the body of each function in the file [Walls 2006]. Developers should be aware that<br />

C++ does not support the restrict qualifier, but some C++ compiler implementations support<br />

an equivalent qualifier as an extension.<br />

The C <strong>Standard</strong> [ISO/IEC 9899:2011] identifies the following undefined behavior:<br />

A restrict-qualified pointer is assigned a value based on another restricted pointer whose<br />

associated block neither began execution before the block associated with this pointer,<br />

nor ended before the assignment (6.7.3.1).<br />

This is an oversimplification, however, and it is important to review the formal definition of restrict<br />

in subclause 6.7.3.1 of the C <strong>Standard</strong> to properly understand undefined behaviors associated<br />

with the use of restrict-qualified pointers.<br />

4.11.1 Overlapping Objects<br />

The restrict qualifier requires that the pointers do not reference overlapping objects. If the objects<br />

referenced by arguments to functions overlap (meaning the objects share some common<br />

memory addresses), the behavior is undefined.<br />

4.11.1.1 Noncompliant Code Example<br />

This code example is noncompliant because an assignment is made between two restrict-qualified<br />

pointers in the same scope:<br />

int *restrict a;<br />

int *restrict b;<br />

extern int c[];<br />

int main(void) {<br />

c[0] = 17;<br />

c[1] = 18;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 114<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

}<br />

a = &c[0];<br />

b = &c[1];<br />

a = b; /* Undefined behavior */<br />

/* ... */<br />

Note that undefined behavior occurs only when a is assigned to b. It is valid for a and b to point<br />

into the same array object, provided the range of elements accessed through one of the pointers<br />

does not overlap with the range of elements accessed through the other pointer.<br />

4.11.1.2 Compliant Solution<br />

One way to eliminate the undefined behavior is simply to remove the restrict-qualification<br />

from the affected pointers:<br />

int *a;<br />

int *b;<br />

extern int c[];<br />

int main(void) {<br />

c[0] = 17;<br />

c[1] = 18;<br />

a = &c[0];<br />

b = &c[1];<br />

a = b; /* Defined behavior */<br />

/* ... */<br />

}<br />

4.11.2 restrict-Qualified Function Parameters<br />

When calling functions that have restrict-qualified function parameters, it is important that the<br />

pointer arguments do not reference overlapping objects if one or more of the pointers are used to<br />

modify memory. Consequently, it is important to understand the semantics of the function being<br />

called.<br />

4.11.2.1 Noncompliant Code Example<br />

In this noncompliant code example, the function f() accepts three parameters. The function copies<br />

n integers from the int array referenced by the restrict-qualified pointer p to the int array<br />

referenced by the restrict-qualified pointer q. Because the destination array is modified during<br />

each execution of the function (for which n is nonzero), if the array is accessed through one of the<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 115<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

pointer parameters, it cannot also be accessed through the other. Declaring these function parameters<br />

as restrict-qualified pointers allows aggressive optimization by the compiler but can also<br />

result in undefined behavior if these pointers refer to overlapping objects.<br />

#include <br />

void f(size_t n, int *restrict p, const int *restrict q) {<br />

while (n-- > 0) {<br />

*p++ = *q++;<br />

}<br />

}<br />

void g(void) {<br />

extern int d[100];<br />

/* ... */<br />

f(50, d + 1, d); /* Undefined behavior */<br />

}<br />

The function g() declares an array d consisting of 100 int values and then invokes f() to copy<br />

memory from one area of the array to another. This call has undefined behavior because each of<br />

d[1]through d[49] is accessed through both p and q.<br />

4.11.2.2 Compliant Solution<br />

In this compliant solution, the function f() is unchanged but the programmer has ensured that<br />

none of the calls to f() result in undefined behavior. The call to f() in g() is valid because the<br />

storage allocated to d is effectively divided into two disjoint objects.<br />

#include <br />

void f(size_t n, int *restrict p, const int *restrict q) {<br />

while (n-- > 0) {<br />

*p++ = *q++;<br />

}<br />

}<br />

void g(void) {<br />

extern int d[100];<br />

/* ... */<br />

f(50, d + 50, d); /* Defined behavior */<br />

}<br />

4.11.2.3 Noncompliant Code Example<br />

In this noncompliant code example, the function add() adds the integer array referenced by the<br />

restrict-qualified pointers lhs to the integer array referenced by the restrict-qualified<br />

pointer rhs and stores the result in the restrict-qualified pointer referenced by res. The function<br />

f() declares an array a consisting of 100 int values and then invokes add() to copy<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 116<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

memory from one area of the array to another. The call add(100, a, a, a)has undefined behavior<br />

because the object modified by res is accessed by lhs and rhs.<br />

#include <br />

void add(size_t n, int *restrict res, const int *restrict lhs,<br />

const int *restrict rhs) {<br />

for (size_t i = 0; i < n; ++i) {<br />

res[i] = lhs[i] + rhs[i];<br />

}<br />

}<br />

void f(void) {<br />

int a[100];<br />

add(100, a, a, a); /* Undefined behavior */<br />

}<br />

4.11.2.4 Compliant Solution<br />

In this compliant solution, an unmodified object is aliased through two restricted pointers. Because<br />

a and b are disjoint arrays, a call of the form add(100, a, b, b) has defined behavior,<br />

because array b is not modified within function add.<br />

#include <br />

void add(size_t n, int *restrict res, const int *restrict lhs,<br />

const int *restrict rhs) {<br />

for (size_t i = 0; i < n; ++i) {<br />

res[i] = lhs[i] + rhs[i];<br />

}<br />

}<br />

void f(void) {<br />

int a[100];<br />

int b[100];<br />

add(100, a, b, b); /* Defined behavior */<br />

}<br />

4.11.3 Invoking Library Functions with restrict-Qualified Pointers<br />

Ensure that restrict-qualified source and destination pointers do not reference overlapping objects<br />

when invoking library functions. For example, the following table lists C standard library<br />

functions that copy memory from a source object referenced by a restrict-qualified pointer to a<br />

destination object that is also referenced by a restrict-qualified pointer:<br />

<strong>Standard</strong> C<br />

strcpy()<br />

strncpy()<br />

Annex K<br />

strcpy_s()<br />

strncpy_s()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 117<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

<strong>Standard</strong> C<br />

strcat()<br />

strncat()<br />

memcpy()<br />

Annex K<br />

strcat_s()<br />

strncat_s()<br />

memcpy_s()<br />

strtok_s()<br />

If the objects referenced by arguments to functions overlap (meaning the objects share some common<br />

memory addresses), the behavior is undefined. (See also undefined behavior 68.) The result<br />

of the functions is unknown, and data may be corrupted. As a result, these functions must never<br />

be passed pointers to overlapping objects. If data must be copied between objects that share common<br />

memory addresses, a copy function guaranteed to work on overlapping memory, such as<br />

memmove(), should be used.<br />

4.11.3.1 Noncompliant Code Example<br />

In this noncompliant code example, the values of objects referenced by ptr1 and ptr2 become<br />

unpredictable after the call to memcpy() because their memory areas overlap:<br />

#include <br />

void func(void) {<br />

char c_str[]= "test string";<br />

char *ptr1 = c_str;<br />

char *ptr2;<br />

}<br />

ptr2 = ptr1 + 3;<br />

/* Undefined behavior because of overlapping objects */<br />

memcpy(ptr2, ptr1, 6);<br />

/* ... */<br />

4.11.3.2 Compliant Solution<br />

In this compliant solution, the call to memcpy() is replaced with a call to memmove(). The<br />

memmove() function performs the same operation as memcpy() when the memory regions do not<br />

overlap. When the memory regions do overlap, the n characters from the object pointed to by the<br />

source (ptr1) are first copied into a temporary array of n characters that does not overlap the objects<br />

pointed to by the destination (ptr2) or the source. The n characters from the temporary array<br />

are then copied into the object pointed to by the destination.<br />

#include <br />

void func(void) {<br />

char c_str[]= "test string";<br />

char *ptr1 = c_str;<br />

char *ptr2;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 118<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

}<br />

ptr2 = ptr1 + 3;<br />

memmove(ptr2, ptr1, 6); /* Replace call to memcpy() */<br />

/* ... */<br />

Similar solutions using memmove() can replace the string functions as long as care is taken regarding<br />

the byte size of the characters and proper null-termination of the copied string.<br />

4.11.4 Calling Functions with restrict-Qualified Pointer to a const-Qualified<br />

Type<br />

Ensure that functions that accept a restrict-qualified pointer to a const-qualified type do not<br />

modify the object referenced by that pointer. Formatted input and output standard library functions<br />

frequently fit this description. The following table lists of some of the common functions for<br />

which the format argument is a restrict-qualified pointer to a const-qualified type.<br />

<strong>Standard</strong> C<br />

printf()<br />

scanf()<br />

sprintf()<br />

snprintf()<br />

Annex K<br />

printf_s()<br />

scanf_s()<br />

sprintf_s()<br />

snprintf_s()<br />

For formatted output functions such as printf(), it is unlikely that a programmer would modify<br />

the format string. However, an attacker may attempt to do so if a program violates FIO30-C. Exclude<br />

user input from format strings and passes tainted values as part of the format string.<br />

4.11.4.1 Noncompliant Code Example<br />

In this noncompliant code example, the programmer is attempting to overwrite the format string<br />

with a string value read in from stdin such as “%d%f 1 3.3” and use the resulting modified<br />

string of “%s%d%f” to input the subsequent values of 1 and 3.3:<br />

#include <br />

void func(void) {<br />

int i;<br />

float x;<br />

char format[100] = "%s";<br />

/* Undefined behavior */<br />

int n = scanf(format, format + 2, &i, &x);<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 119<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

4.11.4.2 Compliant Solution<br />

The intended results are achieved by this compliant solution:<br />

#include <br />

void func(void) {<br />

int i;<br />

float x<br />

int n = scanf("%d%f", &i, &x); /* Defined behavior */<br />

/* ... */<br />

}<br />

4.11.5 Outer-to-Inner Assignments between Restricted Pointers<br />

The assignment between restrict-qualified pointers declared in an inner nested block from an<br />

outer block has defined behavior.<br />

4.11.5.1 Noncompliant Code Example<br />

The assignment of restrict-qualified pointers to other restrict-qualified pointers within the<br />

same block has undefined behavior:<br />

void func(void) {<br />

int *restrict p1;<br />

int *restrict q1;<br />

int *restrict p2 = p1; /* Undefined behavior */<br />

int *restrict q2 = q1; /* Undefined behavior */<br />

}<br />

4.11.5.2 Compliant Solution<br />

The intended results can be achieved using an inner nested block, as shown in this compliant solution:<br />

void func(void) {<br />

int *restrict p1;<br />

int *restrict q1;<br />

{ /* Added inner block */<br />

int *restrict p2 = p1; /* Valid, well-defined behavior */<br />

int *restrict q2 = q1; /* Valid, well-defined behavior */<br />

}<br />

}<br />

4.11.6 Risk Assessment<br />

The incorrect use of restrict-qualified pointers can result in undefined behavior that might be<br />

exploited to cause data integrity violations.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 120<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP43-C. Avoid undefined behavior when using restrict-qualified pointers<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP43-C Medium Probable High P4 L3<br />

4.11.7 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

FIO30-C. Exclude user input from format<br />

strings<br />

MISRA C:2012 Rule 8.14 (required) 1<br />

Passing Parameters and Return Values [CSJ]<br />

Passing pointers into the same object as arguments<br />

to different restrict-qualified parameters<br />

[restrict]<br />

4.11.8 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Walls 2006]<br />

6.7.3.1, “Formal Definition of restrict”<br />

______________________<br />

1. MISRA Rule 8.14 prohibits the use of the restrict keyword except in C standard library functions.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 121<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic<br />

4.12 EXP44-C. Do not rely on side effects in operands to sizeof,<br />

_Alignof, or _Generic<br />

Some operators do not evaluate their operands beyond the type information the operands provide.<br />

When using one of these operators, do not pass an operand that would otherwise yield a side effect<br />

since the side effect will not be generated.<br />

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the<br />

parenthesized name of a type. In most cases, the operand is not evaluated. A possible exception<br />

is when the type of the operand is a variable length array type (VLA); then the expression is evaluated.<br />

When part of the operand of the sizeof operator is a VLA type and when changing the<br />

value of the VLA’s size expression would not affect the result of the operator, it is unspecified<br />

whether or not the size expression is evaluated. (See unspecified behavior 22.)<br />

The operand passed to_Alignof is never evaluated, despite not being an expression. For instance,<br />

if the operand is a VLA type and the VLA’s size expression contains a side effect, that<br />

side effect is never evaluated.<br />

The operand used in the controlling expression of a _Generic selection expression is never evaluated.<br />

Providing an expression that appears to produce side effects may be misleading to programmers<br />

who are not aware that these expressions are not evaluated, and in the case of a VLA used in<br />

sizeof, have unspecified results. As a result, programmers may make invalid assumptions about<br />

program state, leading to errors and possible software vulnerabilities.<br />

This rule is similar to PRE31-C. Avoid side effects in arguments to unsafe macros.<br />

4.12.1 Noncompliant Code Example (sizeof)<br />

In this noncompliant code example, the expression a++ is not evaluated:<br />

#include <br />

void func(void) {<br />

int a = 14;<br />

int b = sizeof(a++);<br />

printf("%d, %d\n", a, b);<br />

}<br />

Consequently, the value of a after b has been initialized is 14.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 122<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic<br />

4.12.2 Compliant Solution (sizeof)<br />

In this compliant solution, the variable a is incremented outside of the sizeof operation:<br />

#include <br />

void func(void) {<br />

int a = 14;<br />

int b = sizeof(a);<br />

++a;<br />

printf("%d, %d\n", a, b);<br />

}<br />

4.12.3 Noncompliant Code Example (sizeof, VLA)<br />

In this noncompliant code example, the expression ++n in the initialization expression of a must<br />

be evaluated because its value affects the size of the VLA operand of the sizeof operator. However,<br />

in the initialization expression of b, the expression ++n % 1 evaluates to 0. This means that<br />

the value of n does not affect the result of the sizeof operator. Consequently, it is unspecified<br />

whether or not n will be incremented when initializing b.<br />

#include <br />

#include <br />

void f(size_t n) {<br />

/* n must be incremented */<br />

size_t a = sizeof(int[++n]);<br />

/* n need not be incremented */<br />

size_t b = sizeof(int[++n % 1 + 1]);<br />

}<br />

printf("%zu, %zu, %zu\n", a, b, n);<br />

/* ... */<br />

4.12.4 Compliant Solution (sizeof, VLA)<br />

This compliant solution avoids changing the value of the variable n used in each sizeof expression<br />

and instead increments n safely afterwards:<br />

#include <br />

#include <br />

void f(size_t n) {<br />

size_t a = sizeof(int[n + 1]);<br />

++n;<br />

size_t b = sizeof(int[n % 1 + 1]);<br />

++n;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 123<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic<br />

}<br />

printf("%zu, %zu, %zu\n", a, b, n);<br />

/* ... */<br />

4.12.5 Noncompliant Code Example (_Generic)<br />

This noncompliant code example attempts to modify a variable’s value as part of the _Generic<br />

selection control expression. The programmer may expect that a is incremented, but because<br />

_Generic does not evaluate its control expression, the value of a is not modified.<br />

#include <br />

#define S(val) _Generic(val, int : 2, \<br />

short : 3, \<br />

default : 1)<br />

void func(void) {<br />

int a = 0;<br />

int b = S(a++);<br />

printf("%d, %d\n", a, b);<br />

}<br />

4.12.6 Compliant Solution (_Generic)<br />

In this compliant solution, a is incremented outside of the _Generic selection expression:<br />

#include <br />

#define S(val) _Generic(val, int : 2, \<br />

short : 3, \<br />

default : 1)<br />

void func(void) {<br />

int a = 0;<br />

int b = S(a);<br />

++a;<br />

printf("%d, %d\n", a, b);<br />

}<br />

4.12.7 Noncompliant Code Example (_Alignof)<br />

This noncompliant code example attempts to modify a variable while getting its default alignment<br />

value. The user may have expected val to be incremented as part of the _Alignof expression,<br />

but because _Alignof does not evaluate its operand, val is unchanged.<br />

#include <br />

void func(void) {<br />

int val = 0;<br />

/* ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 124<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic<br />

}<br />

size_t align = _Alignof(int[++val]);<br />

printf("%zu, %d\n", align, val);<br />

/* ... */<br />

4.12.8 Compliant Solution (_Alignof)<br />

This compliant solution moves the expression out of the _Alignof operator:<br />

#include <br />

void func(void) {<br />

int val = 0;<br />

/* ... */<br />

++val;<br />

size_t align = _Alignof(int[val]);<br />

printf("%zu, %d\n, align, val);<br />

/* ... */<br />

}<br />

4.12.9 Exceptions<br />

EXP44-C-EX1: Reading a volatile-qualified value is a side-effecting operation. However, accessing<br />

a value through a volatile-qualified type does not guarantee side effects will happen on<br />

the read of the value unless the underlying object is also volatile-qualified. Idiomatic reads of a<br />

volatile-qualified object are permissible as an operand to a sizeof(), _Alignof(), or _Generic<br />

expression, as in the following example:<br />

void f(void) {<br />

int * volatile v;<br />

(void)sizeof(*v);<br />

}<br />

4.12.10 Risk Assessment<br />

If expressions that appear to produce side effects are supplied to an operator that does not evaluate<br />

its operands, the results may be different than expected. Depending on how this result is used, it<br />

can lead to unintended program behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP44-C Low Unlikely Low P3 L3<br />

4.12.11 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

EXP52-CPP. Do not rely on side effects in unevaluated<br />

operands<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 125<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP45-C. Do not perform assignments in selection statements<br />

4.13 EXP45-C. Do not perform assignments in selection statements<br />

Do not use the assignment operator in the contexts listed in the following table because doing so<br />

typically indicates programmer error and can result in unexpected behavior.<br />

Operator<br />

if<br />

while<br />

do ... while<br />

for<br />

Context<br />

Controlling expression<br />

Controlling expression<br />

Controlling expression<br />

Second operand<br />

?: First operand<br />

?: Second or third operands, where the ternary expression<br />

is used in any of these contexts<br />

&&<br />

Either operand<br />

|| either operand<br />

, Second operand, when the comma expression is<br />

used in any of these contexts<br />

4.13.1 Noncompliant Code Example<br />

In this noncompliant code example, an assignment expression is the outermost expression in an<br />

if statement:<br />

if (a = b) {<br />

/* ... */<br />

}<br />

Although the intent of the code may be to assign b to a and test the value of the result for equality<br />

to 0, it is frequently a case of the programmer mistakenly using the assignment operator = instead<br />

of the equals operator ==. Consequently, many compilers will warn about this condition, making<br />

this coding error detectable by adhering to MSC00-C. Compile cleanly at high warning levels.<br />

4.13.2 Compliant Solution (Unintentional Assignment)<br />

When the assignment of b to a is not intended, the conditional block is now executed when a is<br />

equal to b:<br />

if (a == b) {<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 126<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP45-C. Do not perform assignments in selection statements<br />

4.13.3 Compliant Solution (Intentional Assignment)<br />

When the assignment is intended, this compliant solution explicitly uses inequality as the outermost<br />

expression while performing the assignment in the inner expression:<br />

if ((a = b) != 0) {<br />

/* ... */<br />

}<br />

It is less desirable in general, depending on what was intended, because it mixes the assignment in<br />

the condition, but it is clear that the programmer intended the assignment to occur.<br />

4.13.4 Noncompliant Code Example<br />

In this noncompliant code example, the expression x = y is used as the controlling expression of<br />

the while statement:<br />

do { /* ... */ } while (foo(), x = y);<br />

The same result can be obtained using the for statement, which is specifically designed to evaluate<br />

an expression on each iteration of the loop, just before performing the test in its controlling expression:<br />

for (; x; foo(), x = y) { /* ... */ }<br />

4.13.5 Compliant Solution (Unintentional Assignment)<br />

When the assignment of y to x is not intended, the conditional block should be executed only<br />

when x is equal to y, as in this compliant solution:<br />

do { /* ... */ } while (foo(), x == y);<br />

4.13.6 Compliant Solution (Intentional Assignment)<br />

When the assignment is intended, this compliant solution can be used:<br />

do { /* ... */ } while (foo(), (x = y) != 0);<br />

4.13.7 Noncompliant Code Example<br />

In this noncompliant example, the expression p = q is used as the controlling expression of the<br />

while statement:<br />

do { /* ... */ } while (x = y, p = q);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 127<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP45-C. Do not perform assignments in selection statements<br />

4.13.8 Compliant Solution<br />

In this compliant solution, the expression x = y is not used as the controlling expression of the<br />

while statement:<br />

do { /* ... */ } while (x = y, p == q);<br />

4.13.9 Noncompliant Code Example<br />

This noncompliant code example has a typo that results in an assignment rather than a comparison.<br />

while (ch = '\t' && ch == ' ' && ch == '\n') {<br />

/* ... */<br />

}<br />

Many compilers will warn about this condition. This coding error would typically be eliminated<br />

by adherence to MSC00-C. Compile cleanly at high warning levels. Although this code compiles,<br />

it will cause unexpected behavior to an unsuspecting programmer. If the intent was to verify a<br />

string such as a password, user name, or group user ID, the code may produce significant vulnerabilities<br />

and require significant debugging.<br />

4.13.10 Compliant Solution (RHS Variable)<br />

When comparisons are made between a variable and a literal or const-qualified variable, placing<br />

the variable on the right of the comparison operation can prevent a spurious assignment.<br />

In this code example, the literals are placed on the left-hand side of each comparison. If the programmer<br />

were to inadvertently use an assignment operator, the statement would assign ch to<br />

'\t', which is invalid and produces a diagnostic message.<br />

while ('\t' = ch && ' ' == ch && '\n' == ch) {<br />

/* ... */<br />

}<br />

Due to the diagnostic, the typo will be easily spotted and fixed.<br />

while ('\t' == ch && ' ' == ch && '\n' == ch) {<br />

/* ... */<br />

}<br />

As a result, any mistaken use of the assignment operator that could otherwise create a vulnerability<br />

for operations such as string verification will result in a compiler diagnostic regardless of compiler,<br />

warning level, or implementation.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 128<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP45-C. Do not perform assignments in selection statements<br />

4.13.11 Exceptions<br />

EXP45-C-EX1: Assignment can be used where the result of the assignment is itself an operand to<br />

a comparison expression or relational expression. In this compliant example, the expression x =<br />

y is itself an operand to a comparison operation:<br />

if ((x = y) != 0) { /* ... */ }<br />

EXP45-C-EX2: Assignment can be used where the expression consists of a single primary expression.<br />

The following code is compliant because the expression x = y is a single primary expression:<br />

if ((x = y)) { /* ... */ }<br />

The following controlling expression is noncompliant because && is not a comparison or relational<br />

operator and the entire expression is not primary:<br />

if ((v = w) && flag) { /* ... */ }<br />

When the assignment of v to w is not intended, the following controlling expression can be used to<br />

execute the conditional block when v is equal to w:<br />

if ((v == w) && flag) { /* ... */ };<br />

When the assignment is intended, the following controlling expression can be used:<br />

if (((v = w) != 0) && flag) { /* ... */ };<br />

EXP45-C-EX3: Assignment can be used in a function argument or array index. In this compliant<br />

solution, the expression x = y is used in a function argument:<br />

if (foo(x = y)) { /* ... */ }<br />

4.13.12 Risk Assessment<br />

Errors of omission can result in unintended program flow.<br />

Recommendation Severity Likelihood Remediation Cost Priority Level<br />

EXP45-C Low Likely Medium P6 L2<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 129<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP45-C. Do not perform assignments in selection statements<br />

4.13.13 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

EXP19-CPP. Do not perform assignments in<br />

conditional expressions<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java EXP51-J. Do not perform assignments in conditional<br />

expressions<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Likely Incorrect Expression [KOA]<br />

No assignment in conditional expressions<br />

[boolasgn]<br />

CWE-480, Use of Incorrect Operator<br />

4.13.14 Bibliography<br />

[Dutta 03] “Best Practices for Programming in C”<br />

[Hatton 1995]<br />

Section 2.7.2, “Errors of Omission and Addition”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 130<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Expressions (EXP) - EXP46-C. Do not use a bitwise operator with a Boolean-like operand<br />

4.14 EXP46-C. Do not use a bitwise operator with a Boolean-like<br />

operand<br />

Mixing bitwise and relational operators in the same full expression can be a sign of a logic error<br />

in the expression where a logical operator is usually the intended operator. Do not use the bitwise<br />

AND (&), bitwise OR (|), or bitwise XOR (^) operators with an operand of type _Bool, or the result<br />

of a relational-expression or equality-expression. If the bitwise operator is intended, it should<br />

be indicated with use of a parenthesized expression.<br />

4.14.1 Noncompliant Code Example<br />

In this noncompliant code example, a bitwise & operator is used with the results of an equalityexpression:<br />

if (!(getuid() & geteuid() == 0)) {<br />

/* ... */<br />

}<br />

4.14.2 Compliant Solution<br />

This compliant solution uses the && operator for the logical operation within the conditional expression:<br />

if (!(getuid() && geteuid() == 0)) {<br />

/* ... */<br />

}<br />

4.14.3 Risk Assessment<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

EXP46-C Low Likely Low P9 L2<br />

4.14.4 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

MITRE CWE<br />

Likely Incorrect Expression [KOA]<br />

CWE-480, Use of incorrect operator<br />

4.14.5 Bibliography<br />

[Hatton 1995]<br />

Section 2.7.2, “Errors of Omission and Addition”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 131<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

5 Integers (INT)<br />

5.1 INT30-C. Ensure that unsigned integer operations do not wrap<br />

The C <strong>Standard</strong>, 6.2.5, paragraph 9 [ISO/IEC 9899:2011], states<br />

A computation involving unsigned operands can never overflow, because a result that<br />

cannot be represented by the resulting unsigned integer type is reduced modulo the<br />

number that is one greater than the largest value that can be represented by the resulting<br />

type.<br />

This behavior is more informally called unsigned integer wrapping. Unsigned integer operations<br />

can wrap if the resulting value cannot be represented by the underlying representation of the integer.<br />

The following table indicates which operators can result in wrapping:<br />

Operator Wrap Operator Wrap Operator Wrap Operator Wrap<br />

+ Yes -= Yes > No > No<br />

* Yes /= No & No >= No<br />

/ No %= No | No


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

• Function arguments of type size_t or rsize_t (for example, an argument to a memory allocation<br />

function)<br />

• In security-critical code<br />

The C <strong>Standard</strong> defines arithmetic on atomic integer types as read-modify-write operations with<br />

the same representation as regular integer types. As a result, wrapping of atomic unsigned integers<br />

is identical to regular unsigned integers and should also be prevented or detected.<br />

5.1.1 Addition<br />

Addition is between two operands of arithmetic type or between a pointer to an object type and an<br />

integer type. This rule applies only to addition between two operands of arithmetic type. (See<br />

ARR37-C. Do not add or subtract an integer to a pointer to a non-array object and ARR30-C. Do<br />

not form or use out-of-bounds pointers or array subscripts.)<br />

Incrementing is equivalent to adding 1.<br />

5.1.1.1 Noncompliant Code Example<br />

This noncompliant code example can result in an unsigned integer wrap during the addition of the<br />

unsigned operands ui_a and ui_b. If this behavior is unexpected, the resulting value may be<br />

used to allocate insufficient memory for a subsequent operation or in some other manner that can<br />

lead to an exploitable vulnerability.<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int usum = ui_a + ui_b;<br />

/* ... */<br />

}<br />

5.1.1.2 Compliant Solution (Precondition Test)<br />

This compliant solution performs a precondition test of the operands of the addition to guarantee<br />

there is no possibility of unsigned wrap:<br />

#include <br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int usum;<br />

if (UINT_MAX - ui_a < ui_b) {<br />

/* Handle error */<br />

} else {<br />

usum = ui_a + ui_b;<br />

}<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 133<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

5.1.1.3 Compliant Solution (Postcondition Test)<br />

This compliant solution performs a postcondition test to ensure that the result of the unsigned addition<br />

operation usum is not less than the first operand:<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int usum = ui_a + ui_b;<br />

if (usum < ui_a) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

}<br />

5.1.2 Subtraction<br />

Subtraction is between two operands of arithmetic type, two pointers to qualified or unqualified<br />

versions of compatible object types, or a pointer to an object type and an integer type. This rule<br />

applies only to subtraction between two operands of arithmetic type. (See ARR36-C. Do not subtract<br />

or compare two pointers that do not refer to the same array, ARR37-C. Do not add or subtract<br />

an integer to a pointer to a non-array object, and ARR30-C. Do not form or use out-ofbounds<br />

pointers or array subscripts for information about pointer subtraction.)<br />

Decrementing is equivalent to subtracting 1.<br />

5.1.2.1 Noncompliant Code Example<br />

This noncompliant code example can result in an unsigned integer wrap during the subtraction of<br />

the unsigned operands ui_a and ui_b. If this behavior is unanticipated, it may lead to an exploitable<br />

vulnerability.<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int udiff = ui_a - ui_b;<br />

/* ... */<br />

}<br />

5.1.2.2 Compliant Solution (Precondition Test)<br />

This compliant solution performs a precondition test of the unsigned operands of the subtraction<br />

operation to guarantee there is no possibility of unsigned wrap:<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int udiff;<br />

if (ui_a < ui_b){<br />

/* Handle error */<br />

} else {<br />

udiff = ui_a - ui_b;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 134<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

}<br />

/* ... */<br />

5.1.2.3 Compliant Solution (Postcondition Test)<br />

This compliant solution performs a postcondition test that the result of the unsigned subtraction<br />

operation udiff is not greater than the minuend:<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int udiff = ui_a - ui_b;<br />

if (udiff > ui_a) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

}<br />

5.1.3 Multiplication<br />

Multiplication is between two operands of arithmetic type.<br />

5.1.3.1 Noncompliant Code Example<br />

The Mozilla Foundation Security Advisory 2007-01 describes a heap buffer overflow vulnerability<br />

in the Mozilla Scalable Vector Graphics (SVG) viewer resulting from an unsigned integer<br />

wrap during the multiplication of the signed int value pen->num_vertices and the size_t<br />

value sizeof(cairo_pen_vertex_t) [VU#551436]. The signed int operand is converted<br />

to size_t prior to the multiplication operation so that the multiplication takes place between two<br />

size_t integers, which are unsigned. (See INT02-C. Understand integer conversion rules.)<br />

pen->num_vertices = _cairo_pen_vertices_needed(<br />

gstate->tolerance, radius, &gstate->ctm<br />

);<br />

pen->vertices = malloc(<br />

pen->num_vertices * sizeof(cairo_pen_vertex_t)<br />

);<br />

The unsigned integer wrap can result in allocating memory of insufficient size.<br />

5.1.3.2 Compliant Solution<br />

This compliant solution tests the operands of the multiplication to guarantee that there is no unsigned<br />

integer wrap:<br />

pen->num_vertices = _cairo_pen_vertices_needed(<br />

gstate->tolerance, radius, &gstate->ctm<br />

);<br />

if (pen->num_vertices > SIZE_MAX / sizeof(cairo_pen_vertex_t)) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 135<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

/* Handle error */<br />

}<br />

pen->vertices = malloc(<br />

pen->num_vertices * sizeof(cairo_pen_vertex_t)<br />

);<br />

5.1.4 Exceptions<br />

INT30-C-EX1: Unsigned integers can exhibit modulo behavior (wrapping) when necessary for<br />

the proper execution of the program. It is recommended that the variable declaration be clearly<br />

commented as supporting modulo behavior and that each operation on that integer also be clearly<br />

commented as supporting modulo behavior.<br />

INT30-C-EX2: Checks for wraparound can be omitted when it can be determined at compile time<br />

that wraparound will not occur. As such, the following operations on unsigned integers require no<br />

validation:<br />

• Operations on two compile-time constants<br />

• Operations on a variable and 0 (except division or remainder by 0)<br />

• Subtracting any variable from its type’s maximum; for example, any unsigned int may<br />

safely be subtracted from UINT_MAX<br />

• Multiplying any variable by 1<br />

• Division or remainder, as long as the divisor is nonzero<br />

• Right-shifting any type maximum by any number no larger than the type precision; for example,<br />

UINT_MAX >> x is valid as long as 0


Integers (INT) - INT30-C. Ensure that unsigned integer operations do not wrap<br />

5.1.5.1 Related Vulnerabilities<br />

CVE-2009-1385 results from a violation of this rule. The value performs an unchecked subtraction<br />

on the length of a buffer and then adds those many bytes of data to another buffer [xorl<br />

2009]. This can cause a buffer overflow, which allows an attacker to execute arbitrary code.<br />

A Linux Kernel vmsplice exploit, described by Rafal Wojtczuk [Wojtczuk 2008], documents a<br />

vulnerability and exploit arising from a buffer overflow (caused by unsigned integer wrapping).<br />

Don Bailey [Bailey 2014] describes an unsigned integer wrap vulnerability in the LZO compression<br />

algorithm, which can be exploited in some implementations.<br />

CVE-2014-4377 describes a vulnerability in iOS 7.1 resulting from a multiplication operation that<br />

wraps, producing an insufficiently small value to pass to a memory allocation routine, which is<br />

subsequently overflowed.<br />

5.1.6 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

MITRE CWE<br />

INT02-C. Understand integer conversion rules<br />

ARR30-C. Do not form or use out-of-bounds<br />

pointers or array subscripts<br />

ARR36-C. Do not subtract or compare two<br />

pointers that do not refer to the same array<br />

ARR37-C. Do not add or subtract an integer to<br />

a pointer to a non-array object<br />

CON08-C. Do not assume that a group of calls<br />

to independently atomic methods is atomic<br />

Arithmetic Wrap-Around Error [FIF]<br />

CWE-190, Integer Overflow or Wraparound<br />

5.1.7 Bibliography<br />

[Bailey 2014]<br />

[Dowd 2006]<br />

[ISO/IEC 9899:2011]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

[VU#551436]<br />

[Warren 2002]<br />

[Wojtczuk 2008]<br />

[xorl 2009]<br />

Raising Lazarus - The 20 Year Old Bug that<br />

Went to Mars<br />

Chapter 6, “C Language Issues” (“Arithmetic<br />

Boundary Conditions,” pp. 211–223)<br />

Subclause 6.2.5, “Types”<br />

Chapter 5, “Integer Security”<br />

Section 5.2.7, “Integer Overflow”<br />

Chapter 2, “Basics”<br />

“CVE-2009-1385: Linux Kernel E1000 Integer<br />

Underflow”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 137<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

5.2 INT31-C. Ensure that integer conversions do not result in lost or<br />

misinterpreted data<br />

Integer conversions, both implicit and explicit (using a cast), must be guaranteed not to result in<br />

lost or misinterpreted data. This rule is particularly true for integer values that originate from untrusted<br />

sources and are used in any of the following ways:<br />

• Integer operands of any pointer arithmetic, including array indexing<br />

• The assignment expression for the declaration of a variable length array<br />

• The postfix expression preceding square brackets [] or the expression in square brackets []<br />

of a subscripted designation of an element of an array object<br />

• Function arguments of type size_t or rsize_t (for example, an argument to a memory allocation<br />

function)<br />

This rule also applies to arguments passed to the following library functions that are converted to<br />

unsigned char:<br />

• memset()<br />

• memset_s()<br />

• fprintf() and related functions (For the length modifier c, if no l length modifier is present,<br />

the int argument is converted to an unsigned char, and the resulting character is<br />

written.)<br />

• fputc()<br />

• ungetc()<br />

• memchr()<br />

and to arguments to the following library functions that are converted to char:<br />

• strchr()<br />

• strrchr()<br />

• All of the functions listed in <br />

The only integer type conversions that are guaranteed to be safe for all data values and all possible<br />

conforming implementations are conversions of an integral value to a wider type of the same signedness.<br />

The C <strong>Standard</strong>, subclause 6.3.1.3 [ISO/IEC 9899:2011], says<br />

When a value with integer type is converted to another integer type other than _Bool, if<br />

the value can be represented by the new type, it is unchanged.<br />

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or<br />

subtracting one more than the maximum value that can be represented in the new type<br />

until the value is in the range of the new type.<br />

Otherwise, the new type is signed and the value cannot be represented in it; either the<br />

result is implementation-defined or an implementation-defined signal is raised.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 138<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

Typically, converting an integer to a smaller type results in truncation of the high-order bits.<br />

5.2.1 Noncompliant Code Example (Unsigned to Signed)<br />

Type range errors, including loss of data (truncation) and loss of sign (sign errors), can occur<br />

when converting from a value of an unsigned integer type to a value of a signed integer type. This<br />

noncompliant code example results in a truncation error on most implementations:<br />

#include <br />

void func(void) {<br />

unsigned long int u_a = ULONG_MAX;<br />

signed char sc;<br />

sc = (signed char)u_a; /* Cast eliminates warning */<br />

/* ... */<br />

}<br />

5.2.2 Compliant Solution (Unsigned to Signed)<br />

Validate ranges when converting from an unsigned type to a signed type. This compliant solution<br />

can be used to convert a value of unsigned long int type to a value of signed char type:<br />

#include <br />

void func(void) {<br />

unsigned long int u_a = ULONG_MAX;<br />

signed char sc;<br />

if (u_a


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

}<br />

/* ... */<br />

5.2.4 Compliant Solution (Signed to Unsigned)<br />

Validate ranges when converting from a signed type to an unsigned type. This compliant solution<br />

converts a value of a signed int type to a value of an unsigned int type:<br />

#include <br />

void func(void) {<br />

signed int si = INT_MIN;<br />

unsigned int ui;<br />

if (si < 0) {<br />

/* Handle error */<br />

} else {<br />

ui = (unsigned int)si; /* Cast eliminates warning */<br />

}<br />

/* ... */<br />

}<br />

Subclause 6.2.5, paragraph 9, of the C <strong>Standard</strong> [ISO/IEC 9899:2011] provides the necessary<br />

guarantees to ensure this solution works on a conforming implementation:<br />

The range of nonnegative values of a signed integer type is a subrange of the corresponding<br />

unsigned integer type, and the representation of the same value in each type<br />

is the same.<br />

5.2.5 Noncompliant Code Example (Signed, Loss of Precision)<br />

A loss of data (truncation) can occur when converting from a value of a signed integer type to a<br />

value of a signed type with less precision. This noncompliant code example results in a truncation<br />

error on most implementations:<br />

#include <br />

void func(void) {<br />

signed long int s_a = LONG_MAX;<br />

signed char sc = (signed char)s_a; /* Cast eliminates warning */<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 140<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

5.2.6 Compliant Solution (Signed, Loss of Precision)<br />

Validate ranges when converting from a signed type to a signed type with less precision. This<br />

compliant solution converts a value of a signed long int type to a value of a signed char<br />

type:<br />

#include <br />

void func(void) {<br />

signed long int s_a = LONG_MAX;<br />

signed char sc;<br />

if ((s_a < SCHAR_MIN) || (s_a > SCHAR_MAX)) {<br />

/* Handle error */<br />

} else {<br />

sc = (signed char)s_a; /* Use cast to eliminate warning */<br />

}<br />

/* ... */<br />

}<br />

Conversions from a value of a signed integer type to a value of a signed integer type with less precision<br />

requires that both the upper and lower bounds are checked.<br />

5.2.7 Noncompliant Code Example (Unsigned, Loss of Precision)<br />

A loss of data (truncation) can occur when converting from a value of an unsigned integer type to<br />

a value of an unsigned type with less precision. This noncompliant code example results in a truncation<br />

error on most implementations:<br />

#include <br />

void func(void) {<br />

unsigned long int u_a = ULONG_MAX;<br />

unsigned char uc = (unsigned char)u_a; /* Cast eliminates warning<br />

*/<br />

/* ... */<br />

}<br />

5.2.8 Compliant Solution (Unsigned, Loss of Precision)<br />

Validate ranges when converting a value of an unsigned integer type to a value of an unsigned integer<br />

type with less precision. This compliant solution converts a value of an unsigned long<br />

int type to a value of an unsigned char type:<br />

#include <br />

void func(void) {<br />

unsigned long int u_a = ULONG_MAX;<br />

unsigned char uc;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 141<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

}<br />

if (u_a > UCHAR_MAX) {<br />

/* Handle error */<br />

} else {<br />

uc = (unsigned char)u_a; /* Cast eliminates warning */<br />

}<br />

/* ... */<br />

Conversions from unsigned types with greater precision to unsigned types with less precision require<br />

only the upper bounds to be checked.<br />

5.2.9 Noncompliant Code Example (time_t Return Value)<br />

The time() function returns the value (time_t)(-1) to indicate that the calendar time is not<br />

available. The C <strong>Standard</strong> requires that the time_t type is only a real type capable of representing<br />

time. (The integer and real floating types are collectively called real types.) It is left to the implementor<br />

to decide the best real type to use to represent time. If time_t is implemented as an<br />

unsigned integer type with less precision than a signed int, the return value of time() will never<br />

compare equal to the integer literal -1.<br />

#include <br />

void func(void) {<br />

time_t now = time(NULL);<br />

if (now != -1) {<br />

/* Continue processing */<br />

}<br />

}<br />

5.2.10 Compliant Solution (time_t Return Value)<br />

To ensure the comparison is properly performed, the return value of time() should be compared<br />

against -1 cast to type time_t:<br />

#include <br />

void func(void) {<br />

time_t now = time(NULL);<br />

if (now != (time_t)-1) {<br />

/* Continue processing */<br />

}<br />

}<br />

This solution is in accordance with INT18-C. Evaluate integer expressions in a larger size before<br />

comparing or assigning to that size.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 142<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

5.2.11 Noncompliant Code Example (memset())<br />

For historical reasons, certain C <strong>Standard</strong> functions accept an argument of type int and convert it<br />

to either unsigned char or plain char. This conversion can result in unexpected behavior if the<br />

value cannot be represented in the smaller type. This noncompliant solution unexpectedly clears<br />

the array:<br />

#include <br />

#include <br />

int *init_memory(int *array, size_t n) {<br />

return memset(array, 4096, n);<br />

}<br />

5.2.12 Compliant Solution (memset())<br />

In general, the memset() function should not be used to initialize an integer array unless it is to<br />

set or clear all the bits, as in this compliant solution:<br />

#include <br />

#include <br />

int *init_memory(int *array, size_t n) {<br />

return memset(array, 0, n);<br />

}<br />

5.2.13 Exceptions<br />

INT31-C-EX1: The C <strong>Standard</strong> defines minimum ranges for standard integer types. For example,<br />

the minimum range for an object of type unsigned short int is 0 to 65,535, whereas the minimum<br />

range for int is −32,767 to +32,767. Consequently, it is not always possible to represent all<br />

possible values of an unsigned short int as an int. However, on the IA-32 architecture, for<br />

example, the actual integer range is from −2,147,483,648 to +2,147,483,647, meaning that it is<br />

quite possible to represent all the values of an unsigned short int as an int for this architecture.<br />

As a result, it is not necessary to provide a test for this conversion on IA-32. It is not possible<br />

to make assumptions about conversions without knowing the precision of the underlying types. If<br />

these tests are not provided, assumptions concerning precision must be clearly documented, as the<br />

resulting code cannot be safely ported to a system where these assumptions are invalid. A good<br />

way to document these assumptions is to use static assertions. (See DCL03-C. Use a static assertion<br />

to test the value of a constant expression.)<br />

INT31-C-EX2: Conversion from any integer type with a value between SCHAR_MIN and<br />

UCHAR_MAX to a character type is permitted provided the value represents a character and not an<br />

integer.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 143<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

Conversions to unsigned character types are well defined by C to have modular behavior. A character’s<br />

value is not misinterpreted by the loss of sign or conversion to a negative number. For example,<br />

the Euro symbol € is sometimes represented by bit pattern 0x80 which can have the numerical<br />

value 128 or −127 depending on the signedness of the type.<br />

Conversions to signed character types are more problematic. The C <strong>Standard</strong>, subclause 6.3.1.3,<br />

paragraph 3 [ISO/IEC 9899:2011], says, regarding conversions<br />

Otherwise, the new type is signed and the value cannot be represented in it; either the<br />

result is implementation-defined or an implementation-defined signal is raised.<br />

Furthermore, subclause 6.2.6.2, paragraph 2, says, regarding integer modifications<br />

If the sign bit is one, the value shall be modified in one of the following ways:<br />

• the corresponding value with sign bit 0 is negated (sign and magnitude)<br />

• the sign bit has the value −(2M ) (two’s complement);<br />

• the sign bit has the value −(2M − 1) (ones’ complement).<br />

Which of these applies is implementation-defined, as is whether the value with sign bit 1<br />

and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones’ complement),<br />

is a trap representation or a normal value. [See note.]<br />

NOTE: Two’s complement is shorthand for “radix complement in radix 2.” Ones’ complement is<br />

shorthand for “diminished radix complement in radix 2.”<br />

Consequently, the standard allows for this code to trap:<br />

int i = 128; /* 1000 0000 in binary */<br />

assert(SCHAR_MAX == 127);<br />

signed char c = i; /* can trap */<br />

However, platforms where this code traps or produces an unexpected value are rare. According to<br />

The New C <strong>Standard</strong>: An Economic and Cultural Commentary by Derek Jones [Jones 2008]<br />

Implementations with such trap representations are thought to have existed in the past.<br />

Your author was unable to locate any documents describing such processors.<br />

5.2.14 Risk Assessment<br />

Integer truncation errors can lead to buffer overflows and the execution of arbitrary code by an<br />

attacker.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT31-C High Probable High P6 L2<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 144<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

5.2.14.1 Related Vulnerabilities<br />

CVE-2009-1376 results from a violation of this rule. In version 2.5.5 of Pidgin, a size_t offset is<br />

set to the value of a 64-bit unsigned integer, which can lead to truncation [xorl 2009] on platforms<br />

where a size_t is implemented as a 32-bit unsigned integer. An attacker can execute arbitrary<br />

code by carefully choosing this value and causing a buffer overflow.<br />

5.2.15 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

DCL03-C. Use a static assertion to test the<br />

value of a constant expression<br />

INT18-C. Evaluate integer expressions in a<br />

larger size before comparing or assigning to<br />

that size<br />

FIO34-C. Distinguish between characters read<br />

from a file and EOF or WEOF<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java NUM12-J. Ensure conversions of numeric<br />

types to narrower types do not result in lost or<br />

misinterpreted data<br />

ISO/IEC TR 24772:2013<br />

MISRA C:2012<br />

MITRE CWE<br />

Numeric Conversion Errors [FLC]<br />

Rule 10.1 (required)<br />

Rule 10.3 (required)<br />

Rule 10.4 (required)<br />

Rule 10.6 (required)<br />

Rule 10.7 (required)<br />

CWE-192, Integer Coercion Error<br />

CWE-197, Numeric Truncation Error<br />

CWE-681, Incorrect Conversion between Numeric<br />

Types<br />

5.2.16 Bibliography<br />

[Dowd 2006]<br />

[ISO/IEC 9899:2011]<br />

[Jones 2008]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

Chapter 6, “C Language Issues” (“Type Conversions,”<br />

pp. 223–270)<br />

6.3.1.3, “Signed and Unsigned Integers”<br />

Section 6.2.6.2, “Integer Types”<br />

Chapter 5, “Integer Security”<br />

Section 5.2.9, “Truncation Error”<br />

Section 5.2.10, “Sign Extension Error”<br />

Section 5.2.11, “Signed to Unsigned Conversion<br />

Error”<br />

Section 5.2.12, “Unsigned to Signed Conversion<br />

Error”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 145<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data<br />

[Warren 2002]<br />

[xorl 2009]<br />

Chapter 2, “Basics”<br />

“CVE-2009-1376: Pidgin MSN SLP Integer<br />

Truncation”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 146<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

5.3 INT32-C. Ensure that operations on signed integers do not result in<br />

overflow<br />

Signed integer overflow is undefined behavior 36. Consequently, implementations have considerable<br />

latitude in how they deal with signed integer overflow. (See MSC15-C. Do not depend on<br />

undefined behavior.) An implementation that defines signed integer types as being modulo, for<br />

example, need not detect integer overflow. Implementations may also trap on signed arithmetic<br />

overflows, or simply assume that overflows will never happen and generate object code accordingly.<br />

It is also possible for the same conforming implementation to emit code that exhibits different<br />

behavior in different contexts. For example, an implementation may determine that a signed<br />

integer loop control variable declared in a local scope cannot overflow and may emit efficient<br />

code on the basis of that determination, while the same implementation may determine that a<br />

global variable used in a similar context will wrap.<br />

For these reasons, it is important to ensure that operations on signed integers do not result in overflow.<br />

Of particular importance are operations on signed integer values that originate from a<br />

tainted source and are used as<br />

• Integer operands of any pointer arithmetic, including array indexing<br />

• The assignment expression for the declaration of a variable length array<br />

• The postfix expression preceding square brackets [] or the expression in square brackets []<br />

of a subscripted designation of an element of an array object<br />

• Function arguments of type size_t or rsize_t (for example, an argument to a memory allocation<br />

function)<br />

Integer operations will overflow if the resulting value cannot be represented by the underlying<br />

representation of the integer. The following table indicates which operations can result in overflow.<br />

Operator Overflow Operator Overflow Operator Overflow Operator Overflow<br />

+ Yes -= Yes > No > No<br />

* Yes /= Yes & No >= No<br />

/ Yes %= Yes | No


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

rules before trying to implement secure arithmetic operations. (See INT02-C. Understand integer<br />

conversion rules.)<br />

5.3.1 Implementation Details<br />

GNU GCC invoked with the -fwrapv command-line option defines the same modulo arithmetic<br />

for both unsigned and signed integers.<br />

GNU GCC invoked with the -ftrapv command-line option causes a trap to be generated when a<br />

signed integer overflows, which will most likely abnormally exit. On a UNIX system, the result of<br />

such an event may be a signal sent to the process.<br />

GNU GCC invoked without either the -fwrapv or the -ftrapv option may simply assume that<br />

signed integers never overflow and may generate object code accordingly.<br />

5.3.2 Atomic Integers<br />

The C <strong>Standard</strong> defines the behavior of arithmetic on atomic signed integer types to use two’s<br />

complement representation with silent wraparound on overflow; there are no undefined results.<br />

Although defined, these results may be unexpected and therefore carry similar risks to unsigned<br />

integer wrapping. (See INT30-C. Ensure that unsigned integer operations do not wrap.) Consequently,<br />

signed integer overflow of atomic integer types should also be prevented or detected.<br />

5.3.3 Addition<br />

Addition is between two operands of arithmetic type or between a pointer to an object type and an<br />

integer type. This rule applies only to addition between two operands of arithmetic type. (See<br />

ARR37-C. Do not add or subtract an integer to a pointer to a non-array object and ARR30-C. Do<br />

not form or use out-of-bounds pointers or array subscripts.)<br />

Incrementing is equivalent to adding 1.<br />

5.3.3.1 Noncompliant Code Example<br />

This noncompliant code example can result in a signed integer overflow during the addition of the<br />

signed operands si_a and si_b:<br />

void func(signed int si_a, signed int si_b) {<br />

signed int sum = si_a + si_b;<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 148<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

5.3.3.2 Compliant Solution<br />

This compliant solution ensures that the addition operation cannot overflow, regardless of representation:<br />

#include <br />

void f(signed int si_a, signed int si_b) {<br />

signed int sum;<br />

if (((si_b > 0) && (si_a > (INT_MAX - si_b))) ||<br />

((si_b < 0) && (si_a < (INT_MIN - si_b)))) {<br />

/* Handle error */<br />

} else {<br />

sum = si_a + si_b;<br />

}<br />

/* ... */<br />

}<br />

5.3.4 Subtraction<br />

Subtraction is between two operands of arithmetic type, two pointers to qualified or unqualified<br />

versions of compatible object types, or a pointer to an object type and an integer type. This rule<br />

applies only to subtraction between two operands of arithmetic type. (See ARR36-C. Do not subtract<br />

or compare two pointers that do not refer to the same array, ARR37-C. Do not add or subtract<br />

an integer to a pointer to a non-array object, and ARR30-C. Do not form or use out-ofbounds<br />

pointers or array subscripts for information about pointer subtraction.)<br />

Decrementing is equivalent to subtracting 1.<br />

5.3.4.1 Noncompliant Code Example<br />

This noncompliant code example can result in a signed integer overflow during the subtraction of<br />

the signed operands si_a and si_b:<br />

void func(signed int si_a, signed int si_b) {<br />

signed int diff = si_a - si_b;<br />

/* ... */<br />

}<br />

5.3.4.2 Compliant Solution<br />

This compliant solution tests the operands of the subtraction to guarantee there is no possibility of<br />

signed overflow, regardless of representation:<br />

#include <br />

void func(signed int si_a, signed int si_b) {<br />

signed int diff;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 149<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

if ((si_b > 0 && si_a < INT_MIN + si_b) ||<br />

(si_b < 0 && si_a > INT_MAX + si_b)) {<br />

/* Handle error */<br />

} else {<br />

diff = si_a - si_b;<br />

}<br />

}<br />

/* ... */<br />

5.3.5 Multiplication<br />

Multiplication is between two operands of arithmetic type.<br />

5.3.5.1 Noncompliant Code Example<br />

This noncompliant code example can result in a signed integer overflow during the multiplication<br />

of the signed operands si_a and si_b:<br />

void func(signed int si_a, signed int si_b) {<br />

signed int result = si_a * si_b;<br />

/* ... */<br />

}<br />

5.3.5.2 Compliant Solution<br />

The product of two operands can always be represented using twice the number of bits than exist<br />

in the precision of the larger of the two operands. This compliant solution eliminates signed overflow<br />

on systems where long is at least twice the precision of int:<br />

#include <br />

#include <br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t);<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

void func(signed int si_a, signed int si_b) {<br />

signed int result;<br />

signed long tmp;<br />

assert(PRECISION(ULLONG_MAX) >= 2 * PRECISION(UINT_MAX));<br />

tmp = (signed long long)si_a * (signed long long)si_b;<br />

/*<br />

* If the product cannot be represented as a 32-bit integer,<br />

* handle as an error condition.<br />

*/<br />

if ((tmp > INT_MAX) || (tmp < INT_MIN)) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 150<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

}<br />

/* Handle error */<br />

} else {<br />

result = (int)tmp;<br />

}<br />

/* ... */<br />

The assertion fails if long long has less than twice the precision of int. The PRECISION()<br />

macro and popcount()function provide the correct precision for any integer type. (See INT35-<br />

C. Use correct integer precisions.)<br />

5.3.5.3 Compliant Solution<br />

The following portable compliant solution can be used with any conforming implementation, including<br />

those that do not have an integer type that is at least twice the precision of int:<br />

#include <br />

void func(signed int si_a, signed int si_b) {<br />

signed int result;<br />

if (si_a > 0) { /* si_a is positive */<br />

if (si_b > 0) { /* si_a and si_b are positive */<br />

if (si_a > (INT_MAX / si_b)) {<br />

/* Handle error */<br />

}<br />

} else { /* si_a positive, si_b nonpositive */<br />

if (si_b < (INT_MIN / si_a)) {<br />

/* Handle error */<br />

}<br />

} /* si_a positive, si_b nonpositive */<br />

} else { /* si_a is nonpositive */<br />

if (si_b > 0) { /* si_a is nonpositive, si_b is positive */<br />

if (si_a < (INT_MIN / si_b)) {<br />

/* Handle error */<br />

}<br />

} else { /* si_a and si_b are nonpositive */<br />

if ( (si_a != 0) && (si_b < (INT_MAX / si_a))) {<br />

/* Handle error */<br />

}<br />

} /* End if si_a and si_b are nonpositive */<br />

} /* End if si_a is nonpositive */<br />

}<br />

result = si_a * si_b;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 151<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

5.3.6 Division<br />

Division is between two operands of arithmetic type. Overflow can occur during two’s complement<br />

signed integer division when the dividend is equal to the minimum (negative) value for the<br />

signed integer type and the divisor is equal to −1. Division operations are also susceptible to divide-by-zero<br />

errors. (See INT33-C. Ensure that division and remainder operations do not result in<br />

divide-by-zero errors.)<br />

5.3.6.1 Noncompliant Code Example<br />

This noncompliant code example prevents divide-by-zero errors in compliance with INT33-C.<br />

Ensure that division and remainder operations do not result in divide-by-zero errors but does not<br />

prevent a signed integer overflow error in two’s-complement.<br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if (s_b == 0) {<br />

/* Handle error */<br />

} else {<br />

result = s_a / s_b;<br />

}<br />

/* ... */<br />

}<br />

5.3.6.2 Implementation Details<br />

On the x86-32 architecture, overflow results in a fault, which can be exploited as a denial-of-service<br />

attack.<br />

5.3.6.3 Compliant Solution<br />

This compliant solution eliminates the possibility of divide-by-zero errors or signed overflow:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_b == 0) || ((s_a == LONG_MIN) && (s_b == -1))) {<br />

/* Handle error */<br />

} else {<br />

result = s_a / s_b;<br />

}<br />

/* ... */<br />

}<br />

5.3.7 Remainder<br />

The remainder operator provides the remainder when two operands of integer type are divided.<br />

Because many platforms implement remainder and division in the same instruction, the remainder<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 152<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

operator is also susceptible to arithmetic overflow and division by zero. (See INT33-C. Ensure<br />

that division and remainder operations do not result in divide-by-zero errors.)<br />

5.3.7.1 Noncompliant Code Example<br />

Many hardware architectures implement remainder as part of the division operator, which can<br />

overflow. Overflow can occur during a remainder operation when the dividend is equal to the<br />

minimum (negative) value for the signed integer type and the divisor is equal to −1. It occurs even<br />

though the result of such a remainder operation is mathematically 0. This noncompliant code example<br />

prevents divide-by-zero errors in compliance with INT33-C. Ensure that division and remainder<br />

operations do not result in divide-by-zero errors but does not prevent integer overflow:<br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if (s_b == 0) {<br />

/* Handle error */<br />

} else {<br />

result = s_a % s_b;<br />

}<br />

/* ... */<br />

}<br />

5.3.7.2 Implementation Details<br />

On x86-32 platforms, the remainder operator for signed integers is implemented by the idiv instruction<br />

code, along with the divide operator. Because LONG_MIN / −1 overflows, it results in a<br />

software exception with LONG_MIN % −1 as well.<br />

5.3.7.3 Compliant Solution<br />

This compliant solution also tests the remainder operands to guarantee there is no possibility of an<br />

overflow:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_b == 0 ) || ((s_a == LONG_MIN) && (s_b == -1))) {<br />

/* Handle error */<br />

} else {<br />

result = s_a % s_b;<br />

}<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 153<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

5.3.8 Left-Shift Operator<br />

The left-shift operator takes two integer operands. The result of E1 = PRECISION(ULONG_MAX)) {<br />

/* Handle error */<br />

} else {<br />

result = si_a


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

extern size_t popcount(uintmax_t);<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

void func(signed long si_a, signed long si_b) {<br />

signed long result;<br />

if ((si_a < 0) || (si_b < 0) ||<br />

(si_b >= PRECISION(ULONG_MAX)) ||<br />

(si_a > (LONG_MAX >> si_b))) {<br />

/* Handle error */<br />

} else {<br />

result = si_a


Integers (INT) - INT32-C. Ensure that operations on signed integers do not result in overflow<br />

5.3.10 Risk Assessment<br />

Integer overflow can lead to buffer overflows and the execution of arbitrary code by an attacker.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT32-C High Likely High P9 L2<br />

5.3.11 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

INT02-C. Understand integer conversion rules<br />

INT35-C. Use correct integer precisions<br />

INT33-C. Ensure that division and remainder<br />

operations do not result in divide-by-zero errors<br />

INT34-C. Do not shift an expression by a negative<br />

number of bits or by greater than or equal<br />

to the number of bits that exist in the operand<br />

ARR30-C. Do not form or use out-of-bounds<br />

pointers or array subscripts<br />

ARR36-C. Do not subtract or compare two<br />

pointers that do not refer to the same array<br />

ARR37-C. Do not add or subtract an integer to<br />

a pointer to a non-array object<br />

MSC15-C. Do not depend on undefined behavior<br />

CON08-C. Do not assume that a group of calls<br />

to independently atomic methods is atomic<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java INT00-J. Perform explicit range checking to<br />

avoid integer overflow<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Arithmetic Wrap-Around Error [FIF]<br />

Overflowing signed integers [intoflow]<br />

CWE-129, Improper Validation of Array Index<br />

CWE-190, Integer Overflow or Wraparound<br />

5.3.12 Bibliography<br />

[Dowd 2006]<br />

[ISO/IEC 9899:2011]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

[Warren 2002]<br />

Chapter 6, “C Language Issues” (“Arithmetic<br />

Boundary Conditions,” pp. 211–223)<br />

Subclause 6.5.5, “Multiplicative Operators”<br />

Chapter 5, “Integer Security”<br />

Section 5.2.7, “Integer Overflow”<br />

Chapter 2, “Basics”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 156<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors<br />

5.4 INT33-C. Ensure that division and remainder operations do not<br />

result in divide-by-zero errors<br />

The C <strong>Standard</strong> identifies the following condition under which division and remainder operations<br />

result in undefined behavior (UB):<br />

UB<br />

Description<br />

45 The value of the second operand of the / or % operator<br />

is zero (6.5.5).<br />

Ensure that division and remainder operations do not result in divide-by-zero errors.<br />

5.4.1 Division<br />

The result of the / operator is the quotient from the division of the first arithmetic operand by the<br />

second arithmetic operand. Division operations are susceptible to divide-by-zero errors. Overflow<br />

can also occur during two’s complement signed integer division when the dividend is equal to the<br />

minimum (most negative) value for the signed integer type and the divisor is equal to −1. (See<br />

INT32-C. Ensure that operations on signed integers do not result in overflow.)<br />

5.4.1.1 Noncompliant Code Example<br />

This noncompliant code example prevents signed integer overflow in compliance with INT32-C.<br />

Ensure that operations on signed integers do not result in overflow but fails to prevent a divideby-zero<br />

error during the division of the signed operands s_a and s_b:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_a == LONG_MIN) && (s_b == -1)) {<br />

/* Handle error */<br />

} else {<br />

result = s_a / s_b;<br />

}<br />

/* ... */<br />

}<br />

5.4.1.2 Compliant Solution<br />

This compliant solution tests the division operation to guarantee there is no possibility of divideby-zero<br />

errors or signed overflow:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_b == 0) || ((s_a == LONG_MIN) && (s_b == -1))) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 157<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors<br />

}<br />

} else {<br />

result = s_a / s_b;<br />

}<br />

/* ... */<br />

5.4.2 Remainder<br />

The remainder operator provides the remainder when two operands of integer type are divided.<br />

5.4.2.1 Noncompliant Code Example<br />

This noncompliant code example prevents signed integer overflow in compliance with INT32-C.<br />

Ensure that operations on signed integers do not result in overflow but fails to prevent a divideby-zero<br />

error during the remainder operation on the signed operands s_a and s_b:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_a == LONG_MIN) && (s_b == -1)) {<br />

/* Handle error */<br />

} else {<br />

result = s_a % s_b;<br />

}<br />

/* ... */<br />

}<br />

5.4.2.2 Compliant Solution<br />

This compliant solution tests the remainder operand to guarantee there is no possibility of a divide-by-zero<br />

error or an overflow error:<br />

#include <br />

void func(signed long s_a, signed long s_b) {<br />

signed long result;<br />

if ((s_b == 0 ) || ((s_a == LONG_MIN) && (s_b == -1))) {<br />

/* Handle error */<br />

} else {<br />

result = s_a % s_b;<br />

}<br />

/* ... */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 158<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors<br />

5.4.3 Risk Assessment<br />

A divide-by-zero error can result in abnormal program termination and denial of service.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT33-C Low Likely Medium P6 L2<br />

5.4.4 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

INT32-C. Ensure that operations on signed integers<br />

do not result in overflow<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java NUM02-J. Ensure that division and remainder<br />

operations do not result in divide-by-zero errors<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Integer division errors [diverr]<br />

CWE-369, Divide By Zero<br />

5.4.5 Bibliography<br />

[Seacord 2013b]<br />

[Warren 2002]<br />

Chapter 5, “Integer Security”<br />

Chapter 2, “Basics”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 159<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

5.5 INT34-C. Do not shift an expression by a negative number of bits or<br />

by greater than or equal to the number of bits that exist in the<br />

operand<br />

Bitwise shifts include left-shift operations of the form shift-expressionadditive-expression. The standard integer promotions<br />

are first performed on the operands, each of which has an integer type. The type of the<br />

result is that of the promoted left operand. If the value of the right operand is negative or is greater<br />

than or equal to the width of the promoted left operand, the behavior is undefined. (See undefined<br />

behavior 51.)<br />

Do not shift an expression by a negative number of bits or by a number greater than or equal to<br />

the precision of the promoted left operand. The precision of an integer type is the number of bits it<br />

uses to represent values, excluding any sign and padding bits. For unsigned integer types, the<br />

width and the precision are the same; whereas for signed integer types, the width is one greater<br />

than the precision. This rule uses precision instead of width because, in almost every case, an attempt<br />

to shift by a number of bits greater than or equal to the precision of the operand indicates a<br />

bug (logic error). A logic error is different from overflow, in which there is simply a representational<br />

deficiency. In general, shifts should be performed only on unsigned operands. (See INT13-<br />

C. Use bitwise operators only on unsigned operands.)<br />

5.5.1 Noncompliant Code Example (Left Shift, Unsigned Type)<br />

The result of E1


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

}<br />

/* ... */<br />

5.5.2 Compliant Solution (Left Shift, Unsigned Type)<br />

This compliant solution eliminates the possibility of shifting by greater than or equal to the number<br />

of bits that exist in the precision of the left operand:<br />

#include <br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t);<br />

#define PRECISION(x) popcount(x)<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int uresult = 0;<br />

if (ui_b >= PRECISION(UINT_MAX)) {<br />

/* Handle error */<br />

} else {<br />

uresult = ui_a


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

}<br />

if (si_a > (LONG_MAX >> si_b)) {<br />

/* Handle error */<br />

} else {<br />

result = si_a = PRECISION(ULONG_MAX)) ||<br />

(si_a > (LONG_MAX >> si_b))) {<br />

/* Handle error */<br />

} else {<br />

result = si_a > E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1<br />

has a signed type and a nonnegative value, the value of the result is the integral part of the quotient<br />

of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined<br />

and can be either an arithmetic (signed) shift<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 162<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

or a logical (unsigned) shift<br />

This noncompliant code example fails to test whether the right operand is greater than or equal to<br />

the precision of the promoted left operand, allowing undefined behavior:<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int uresult = ui_a >> ui_b;<br />

/* ... */<br />

}<br />

When working with signed operands, making assumptions about whether a right shift is implemented<br />

as an arithmetic (signed) shift or a logical (unsigned) shift can also lead to vulnerabilities.<br />

(See INT13-C. Use bitwise operators only on unsigned operands.)<br />

5.5.6 Compliant Solution (Right Shift)<br />

This compliant solution eliminates the possibility of shifting by greater than or equal to the number<br />

of bits that exist in the precision of the left operand:<br />

#include <br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t);<br />

#define PRECISION(x) popcount(x)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 163<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

void func(unsigned int ui_a, unsigned int ui_b) {<br />

unsigned int uresult = 0;<br />

if (ui_b >= PRECISION(UINT_MAX)) {<br />

/* Handle error */<br />

} else {<br />

uresult = ui_a >> ui_b;<br />

}<br />

/* ... */<br />

}<br />

5.5.6.1 Implementation Details<br />

GCC has no options to handle shifts by negative amounts or by amounts outside the width of the<br />

type predictably or to trap on them; they are always treated as undefined. Processors may reduce<br />

the shift amount modulo the width of the type. For example, 32-bit right shifts are implemented<br />

using the following instruction on x86-32:<br />

sarl<br />

%cl, %eax<br />

The sarl instruction takes a bit mask of the least significant 5 bits from %cl to produce a value<br />

in the range [0, 31] and then shift %eax that many bits:<br />

// 64-bit right shifts on IA-32 platforms become<br />

shrdl %edx, %eax<br />

sarl %cl, %edx<br />

where %eax stores the least significant bits in the doubleword to be shifted, and %edx stores the<br />

most significant bits.<br />

5.5.7 Risk Assessment<br />

Although shifting a negative number of bits or shifting a number of bits greater than or equal to<br />

the width of the promoted left operand is undefined behavior in C, the risk is generally low because<br />

processors frequently reduce the shift amount modulo the width of the type.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT34-C Low Unlikely Medium P2 L3<br />

5.5.8 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

INT13-C. Use bitwise operators only on unsigned<br />

operands<br />

INT35-C. Use correct integer precisions<br />

INT32-C. Ensure that operations on signed integers<br />

do not result in overflow<br />

Arithmetic Wrap-Around Error [FIF]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 164<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number<br />

of bits that exist in the operand<br />

5.5.9 Bibliography<br />

[C99 Rationale 2003] 6.5.7, “Bitwise Shift Operators”<br />

[Dowd 2006]<br />

Chapter 6, “C Language Issues”<br />

[Seacord 2013b]<br />

Chapter 5, “Integer Security”<br />

[Viega 2005]<br />

Section 5.2.7, “Integer Overflow”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 165<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT35-C. Use correct integer precisions<br />

5.6 INT35-C. Use correct integer precisions<br />

Integer types in C have both a size and a precision. The size indicates the number of bytes used by<br />

an object and can be retrieved for any object or type using the sizeof operator. The precision of<br />

an integer type is the number of bits it uses to represent values, excluding any sign and padding<br />

bits.<br />

Padding bits contribute to the integer’s size, but not to its precision. Consequently, inferring the<br />

precision of an integer type from its size may result in too large a value, which can then lead to<br />

incorrect assumptions about the numeric range of these types. Programmers should use correct<br />

integer precisions in their code, and in particular, should not use the sizeof operator to compute<br />

the precision of an integer type on architectures that use padding bits or in strictly conforming<br />

(that is, portable) programs.<br />

5.6.1 Noncompliant Code Example<br />

This noncompliant code example illustrates a function that produces 2 raised to the power of the<br />

function argument. To prevent undefined behavior in compliance with INT34-C. Do not shift an<br />

expression by a negative number of bits or by greater than or equal to the number of bits that exist<br />

in the operand, the function ensures that the argument is less than the number of bits used to store<br />

a value of type unsigned int.<br />

#include <br />

unsigned int pow2(unsigned int exp) {<br />

if (exp >= sizeof(unsigned int) * CHAR_BIT) {<br />

/* Handle error */<br />

}<br />

return 1


Integers (INT) - INT35-C. Use correct integer precisions<br />

size_t precision = 0;<br />

while (num != 0) {<br />

if (num % 2 == 1) {<br />

precision++;<br />

}<br />

num >>= 1;<br />

}<br />

return precision;<br />

}<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

Implementations can replace the PRECISION() macro with a type-generic macro that returns an<br />

integer constant expression that is the precision of the specified type for that implementation. This<br />

return value can then be used anywhere an integer constant expression can be used, such as in a<br />

static assertion. (See DCL03-C. Use a static assertion to test the value of a constant expression.)<br />

The following type generic macro, for example, might be used for a specific implementation targeting<br />

the IA-32 architecture:<br />

#define PRECISION(value) _Generic(value, \<br />

unsigned char : 8, \<br />

unsigned short: 16, \<br />

unsigned int : 32, \<br />

unsigned long : 32, \<br />

unsigned long long : 64, \<br />

signed char : 7, \<br />

signed short : 15, \<br />

signed int : 31, \<br />

signed long : 31, \<br />

signed long long : 63)<br />

The revised version of the pow2() function uses the PRECISION() macro to determine the precision<br />

of the unsigned type:<br />

#include <br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t);<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

unsigned int pow2(unsigned int exp) {<br />

if (exp >= PRECISION(UINT_MAX)) {<br />

/* Handle error */<br />

}<br />

return 1


Integers (INT) - INT35-C. Use correct integer precisions<br />

5.6.2.1 Implementation Details<br />

Some platforms, such as the Cray Linux Environment (CLE; supported on Cray XT CNL compute<br />

nodes), provide a _popcnt instruction that can substitute for the popcount() function.<br />

#define PRECISION(umax_value) _popcnt(umax_value)<br />

5.6.3 Risk Assessment<br />

Mistaking an integer’s size for its precision can permit invalid precision arguments to operations<br />

such as bitwise shifts, resulting in undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT35-C Low Unlikely Medium P2 L3<br />

5.6.4 Related Guidelines<br />

MITRE CWE<br />

CWE-190, Integer Overflow or Wraparound<br />

5.6.5 Bibliography<br />

[Dowd 2006]<br />

Chapter 6, “C Language Issues”<br />

[C99 Rationale 2003] 6.5.7, “Bitwise Shift Operators”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 168<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT36-C. Converting a pointer to integer or integer to pointer<br />

5.7 INT36-C. Converting a pointer to integer or integer to pointer<br />

Although programmers often use integers and pointers interchangeably in C, pointer-to-integer<br />

and integer-to-pointer conversions are implementation-defined.<br />

Conversions between integers and pointers can have undesired consequences depending on the<br />

implementation. According to the C <strong>Standard</strong>, subclause 6.3.2.3 [ISO/IEC 9899:2011],<br />

An integer may be converted to any pointer type. Except as previously specified, the result<br />

is implementation-defined, might not be correctly aligned, might not point to an entity<br />

of the referenced type, and might be a trap representation.<br />

Any pointer type may be converted to an integer type. Except as previously specified,<br />

the result is implementation-defined. If the result cannot be represented in the integer<br />

type, the behavior is undefined. The result need not be in the range of values of any integer<br />

type.<br />

Do not convert an integer type to a pointer type if the resulting pointer is incorrectly aligned, does<br />

not point to an entity of the referenced type, or is a trap representation.<br />

Do not convert a pointer type to an integer type if the result cannot be represented in the integer<br />

type. (See undefined behavior 24.)<br />

The mapping between pointers and integers must be consistent with the addressing structure of<br />

the execution environment. Issues may arise, for example, on architectures that have a segmented<br />

memory model.<br />

5.7.1 Noncompliant Code Example<br />

The size of a pointer can be greater than the size of an integer, such as in an implementation<br />

where pointers are 64 bits and unsigned integers are 32 bits. This code example is noncompliant<br />

on such implementations because the result of converting the 64-bit ptr cannot be represented in<br />

the 32-bit integer type:<br />

void f(void) {<br />

char *ptr;<br />

/* ... */<br />

unsigned int number = (unsigned int)ptr;<br />

/* ... */<br />

}<br />

5.7.2 Compliant Solution<br />

Any valid pointer to void can be converted to intptr_t or uintptr_t and back with no<br />

change in value. (See INT36-EX2.) The C <strong>Standard</strong> guarantees that a pointer to void may be<br />

converted to or from a pointer to any object type and back again and that the result must compare<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 169<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT36-C. Converting a pointer to integer or integer to pointer<br />

equal to the original pointer. Consequently, converting directly from a char * pointer to a<br />

uintptr_t, as in this compliant solution, is allowed on implementations that support the<br />

uintptr_t type.<br />

#include <br />

void f(void) {<br />

char *ptr;<br />

/* ... */<br />

uintptr_t number = (uintptr_t)ptr;<br />

/* ... */<br />

}<br />

5.7.3 Noncompliant Code Example<br />

In this noncompliant code example, the pointer ptr is converted to an integer value. The highorder<br />

9 bits of the number are used to hold a flag value, and the result is converted back into a<br />

pointer. This example is noncompliant on an implementation where pointers are 64 bits and unsigned<br />

integers are 32 bits because the result of converting the 64-bit ptr cannot be represented in<br />

the 32-bit integer type.<br />

void func(unsigned int flag) {<br />

char *ptr;<br />

/* ... */<br />

unsigned int number = (unsigned int)ptr;<br />

number = (number & 0x7fffff) | (flag


Integers (INT) - INT36-C. Converting a pointer to integer or integer to pointer<br />

}<br />

ptrflag.flag = flag;<br />

5.7.5 Noncompliant Code Example<br />

It is sometimes necessary to access memory at a specific location, requiring a literal integer to<br />

pointer conversion. In this noncompliant code, a pointer is set directly to an integer constant,<br />

where it is unknown whether the result will be as intended:<br />

unsigned int *g(void) {<br />

unsigned int *ptr = 0xdeadbeef;<br />

/* ... */<br />

return ptr;<br />

}<br />

The result of this assignment is implementation-defined, might not be correctly aligned, might not<br />

point to an entity of the referenced type, and might be a trap representation.<br />

5.7.6 Compliant Solution<br />

Adding an explicit cast may help the compiler convert the integer value into a valid pointer. A<br />

common technique is to assign the integer to a volatile-qualified object of type intptr_t or<br />

uintptr_t and then assign the integer value to the pointer:<br />

unsigned int *g(void) {<br />

volatile uintptr_t iptr = 0xdeadbeef;<br />

unsigned int *ptr = (unsigned int *)iptr;<br />

/* ... */<br />

return ptr;<br />

}<br />

5.7.7 Exceptions<br />

INT36-C-EX1: A null pointer can be converted to an integer; it takes on the value 0. Likewise,<br />

the integer value 0 can be converted to a pointer; it becomes the null pointer.<br />

INT36-C-EX2: Any valid pointer to void can be converted to intptr_t or uintptr_t or their<br />

underlying types and back again with no change in value. Use of underlying types instead of<br />

intptr_t or uintptr_t is discouraged, however, because it limits portability.<br />

#include <br />

#include <br />

void h(void) {<br />

intptr_t i = (intptr_t)(void *)&i;<br />

uintptr_t j = (uintptr_t)(void *)&j;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 171<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Integers (INT) - INT36-C. Converting a pointer to integer or integer to pointer<br />

void *ip = (void *)i;<br />

void *jp = (void *)j;<br />

}<br />

assert(ip == &i);<br />

assert(jp == &j);<br />

5.7.8 Risk Assessment<br />

Converting from pointer to integer or vice versa results in code that is not portable and may create<br />

unexpected pointers to invalid memory locations.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

INT36-C Low Probable High P2 L3<br />

5.7.9 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

INT11-CPP. Take care when converting from<br />

pointer to integer or integer to pointer<br />

Pointer Casting and Pointer Type Changes<br />

[HFC]<br />

Converting a pointer to integer or integer to<br />

pointer [intptrconv]<br />

CWE-466, Return of Pointer Value Outside of<br />

Expected Range<br />

CWE-587, Assignment of a Fixed Address to a<br />

Pointer<br />

5.7.10 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.3.2.3, “Pointers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 172<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP30-C. Do not use floating-point variables as loop counters<br />

6 Floating Point (FLP)<br />

6.1 FLP30-C. Do not use floating-point variables as loop counters<br />

Because floating-point numbers represent real numbers, it is often mistakenly assumed that they<br />

can represent any simple fraction exactly. Floating-point numbers are subject to representational<br />

limitations just as integers are, and binary floating-point numbers cannot represent all real numbers<br />

exactly, even if they can be represented in a small number of decimal digits.<br />

In addition, because floating-point numbers can represent large values, it is often mistakenly assumed<br />

that they can represent all significant digits of those values. To gain a large dynamic range,<br />

floating-point numbers maintain a fixed number of precision bits (also called the significand) and<br />

an exponent, which limit the number of significant digits they can represent.<br />

Different implementations have different precision limitations, and to keep code portable, floating-point<br />

variables must not be used as the loop induction variable.<br />

6.1.1 Noncompliant Code Example<br />

In this noncompliant code example, a floating-point variable is used as a loop counter. The decimal<br />

number 0.1 is a repeating fraction in binary and cannot be exactly represented as a binary<br />

floating-point number. Depending on the implementation, the loop may iterate 9 or 10 times.<br />

void func(void) {<br />

for (float x = 0.1f; x


Floating Point (FLP) - FLP30-C. Do not use floating-point variables as loop counters<br />

}<br />

}<br />

6.1.3 Noncompliant Code Example<br />

In this noncompliant code example, a floating-point loop counter is incremented by an amount<br />

that is too small to change its value given its precision:<br />

void func(void) {<br />

for (float x = 100000001.0f; x


Floating Point (FLP) - FLP30-C. Do not use floating-point variables as loop counters<br />

6.1.7 Bibliography<br />

[Lockheed Martin 05] AV Rule 197<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 175<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

6.2 FLP32-C. Prevent or detect domain and range errors in math<br />

functions<br />

The C <strong>Standard</strong>, 7.12.1 [ISO/IEC 9899:2011], defines three types of errors that relate specifically<br />

to math functions in . Paragraph 2 states<br />

A domain error occurs if an input argument is outside the domain over which the mathematical<br />

function is defined.<br />

Paragraph 3 states<br />

A pole error (also known as a singularity or infinitary) occurs if the mathematical function<br />

has an exact infinite result as the finite input argument(s) are approached in the limit.<br />

Paragraph 4 states<br />

A range error occurs if the mathematical result of the function cannot be represented in<br />

an object of the specified type, due to extreme magnitude.<br />

An example of a domain error is the square root of a negative number, such as sqrt(-1.0),<br />

which has no meaning in real arithmetic. Contrastingly, 10 raised to the 1-millionth power,<br />

pow(10., 1e6), cannot be represented in many floating-point implementations because of the<br />

limited range of the type double and consequently constitutes a range error. In both cases, the<br />

function will return some value, but the value returned is not the correct result of the computation.<br />

An example of a pole error is log(0.0), which results in negative infinity.<br />

Programmers can prevent domain and pole errors by carefully bounds-checking the arguments before<br />

calling mathematical functions and taking alternative action if the bounds are violated.<br />

Range errors usually cannot be prevented because they are dependent on the implementation of<br />

floating-point numbers as well as on the function being applied. Instead of preventing range errors,<br />

programmers should attempt to detect them and take alternative action if a range error occurs.<br />

The following table lists the double forms of standard mathematical functions, along with checks<br />

that should be performed to ensure a proper input domain, and indicates whether they can also result<br />

in range or pole errors, as reported by the C <strong>Standard</strong>. Both float and long double forms<br />

of these functions also exist but are omitted from the table for brevity. If a function has a specific<br />

domain over which it is defined, the programmer must check its input values. The programmer<br />

must also check for range errors where they might occur. The standard math functions not listed<br />

in this table, such as fabs(), have no domain restrictions and cannot result in range or pole errors.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 176<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

Function Domain Range Pole<br />

acos(x) -1 0 || (x == 0 && y > 0) ||<br />

(x < 0 && y is an integer)<br />

sqrt(x) x >= 0 No No<br />

erf(x) None Yes No<br />

erfc(x) None Yes No<br />

lgamma(x),<br />

tgamma(x)<br />

Yes<br />

Yes<br />

x != 0 &&! (x < 0 && x is an integer) Yes Yes<br />

lrint(x), lround(x) None Yes No<br />

fmod(x, y),<br />

remainder(x, y),<br />

remquo(x, y, quo)<br />

nextafter(x, y),<br />

nexttoward(x, y)<br />

y != 0 Yes No<br />

None Yes No<br />

fdim(x,y) None Yes No<br />

fma(x,y,z) None Yes No<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 177<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

6.2.1 Domain and Pole Checking<br />

The most reliable way to handle domain and pole errors is to prevent them by checking arguments<br />

beforehand, as in the following exemplar:<br />

double safe_sqrt(double x) {<br />

if (x < 0) {<br />

fprintf(stderr, "sqrt requires a nonnegative argument");<br />

/* Handle domain / pole error */<br />

}<br />

return sqrt (x);<br />

}<br />

6.2.2 Range Checking<br />

Programmers usually cannot prevent range errors, so the most reliable way to handle them is to<br />

detect when they have occurred and act accordingly.<br />

The exact treatment of error conditions from math functions is tedious. The C <strong>Standard</strong>, 7.12.1<br />

[ISO/IEC 9899:2011], defines the following behavior for floating-point overflow:<br />

A floating result overflows if the magnitude of the mathematical result is finite but so<br />

large that the mathematical result cannot be represented without extraordinary roundoff<br />

error in an object of the specified type. If a floating result overflows and default rounding<br />

is in effect, then the function returns the value of the macro HUGE_VAL, HUGE_VALF, or<br />

HUGE_VALL according to the return type, with the same sign as the correct value of the<br />

function; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the<br />

integer expression errno acquires the value ERANGE; if the integer expression<br />

math_errhandling & MATH_ERREXCEPT is nonzero, the “overflow” floating-point exception<br />

is raised.<br />

It is preferable not to check for errors by comparing the returned value against HUGE_VAL or 0 for<br />

several reasons:<br />

• These are, in general, valid (albeit unlikely) data values.<br />

• Making such tests requires detailed knowledge of the various error returns for each math<br />

function.<br />

• Multiple results aside from HUGE_VAL and 0 are possible, and programmers must know<br />

which are possible in each case.<br />

• Different versions of the library have varied in their error-return behavior.<br />

It can be unreliable to check for math errors using errno because an implementation might not<br />

set errno. For real functions, the programmer determines if the implementation sets errno by<br />

checking whether math_errhandling & MATH_ERRNO is nonzero. For complex functions, the<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 178<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

C <strong>Standard</strong>, 7.3.2, paragraph 1, simply states that “an implementation may set errno but is not<br />

required to” [ISO/IEC 9899:2011].<br />

The obsolete System V Interface Definition (SVID3) [UNIX 1992] provides more control over the<br />

treatment of errors in the math library. The programmer can define a function named matherr()<br />

that is invoked if errors occur in a math function. This function can print diagnostics, terminate<br />

the execution, or specify the desired return value. The matherr() function has not been adopted<br />

by C or POSIX, so it is not generally portable.<br />

The following error-handing template uses C <strong>Standard</strong> functions for floating-point errors when<br />

the C macro math_errhandling is defined and indicates that they should be used; otherwise, it<br />

examines errno:<br />

#include <br />

#include <br />

#include <br />

/* ... */<br />

/* Use to call a math function and check errors */<br />

{<br />

#pragma STDC FENV_ACCESS ON<br />

if (math_errhandling & MATH_ERREXCEPT) {<br />

feclearexcept(FE_ALL_EXCEPT);<br />

}<br />

errno = 0;<br />

/* Call the math function */<br />

}<br />

if ((math_errhandling & MATH_ERRNO) && errno != 0) {<br />

/* Handle range error */<br />

} else if ((math_errhandling & MATH_ERREXCEPT) &&<br />

fetestexcept(FE_INVALID | FE_DIVBYZERO |<br />

FE_OVERFLOW | FE_UNDERFLOW) != 0) {<br />

/* Handle range error */<br />

}<br />

See FLP03-C. Detect and handle floating-point errors for more details on how to detect floatingpoint<br />

errors.<br />

6.2.3 Subnormal Numbers<br />

A subnormal number is a nonzero number that does not use all of its precision bits [IEEE 754<br />

2006]. These numbers can be used to represent values that are closer to 0 than the smallest normal<br />

number (one that uses all of its precision bits). However, the asin(), asinh(), atan(),<br />

atanh(), and erf() functions may produce range errors, specifically when passed a subnormal<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 179<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

number. When evaluated with a subnormal number, these functions can produce an inexact, subnormal<br />

value, which is an underflow error. The C <strong>Standard</strong>, 7.12.1, paragraph 6 [ISO/IEC<br />

9899:2011], defines the following behavior for floating-point underflow:<br />

The result underflows if the magnitude of the mathematical result is so small that the<br />

mathematical result cannot be represented, without extraordinary roundoff error, in an<br />

object of the specified type. If the result underflows, the function returns an implementation-defined<br />

value whose magnitude is no greater than the smallest normalized positive<br />

number in the specified type; if the integer expression math_errhandling &<br />

MATH_ERRNO is nonzero, whether errno acquires the value ERANGE is implementation-defined;<br />

if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero,<br />

whether the ‘‘underflow’’ floating-point exception is raised is implementation-defined.<br />

Implementations that support floating-point arithmetic but do not support subnormal numbers,<br />

such as IBM S/360 hex floating-point or nonconforming IEEE-754 implementations that skip subnormals<br />

(or support them by flushing them to zero), can return a range error when calling one of<br />

the following families of functions with the following arguments:<br />

• fmod((min+subnorm), min)<br />

• remainder((min+subnorm), min)<br />

• remquo((min+subnorm), min, quo)<br />

where min is the minimum value for the corresponding floating point type and subnorm is a subnormal<br />

value.<br />

If Annex F is supported and subnormal results are supported, the returned value is exact and a<br />

range error cannot occur. The C <strong>Standard</strong>, F.10.7.1 [ISO/IEC 9899:2011], specifies the following<br />

for the fmod(), remainder(), and remquo() functions:<br />

When subnormal results are supported, the returned value is exact and is independent<br />

of the current rounding direction mode.<br />

Annex F, subclause F.10.7.2, paragraph 2, and subclause F.10.7.3, paragraph 2, of the C <strong>Standard</strong><br />

identify when subnormal results are supported.<br />

6.2.4 Noncompliant Code Example (sqrt())<br />

This noncompliant code example determines the square root of x:<br />

#include <br />

void func(double x) {<br />

double result;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 180<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

}<br />

result = sqrt(x);<br />

However, this code may produce a domain error if x is negative.<br />

6.2.5 Compliant Solution (sqrt())<br />

Because this function has domain errors but no range errors, bounds checking can be used to prevent<br />

domain errors:<br />

#include <br />

void func(double x) {<br />

double result;<br />

if (isless(x, 0.0)) {<br />

/* Handle domain error */<br />

}<br />

}<br />

result = sqrt(x);<br />

6.2.6 Noncompliant Code Example (sinh(), Range Errors)<br />

This noncompliant code example determines the hyperbolic sine of x:<br />

#include <br />

void func(double x) {<br />

double result;<br />

result = sinh(x);<br />

}<br />

This code may produce a range error if x has a very large magnitude.<br />

6.2.7 Compliant Solution (sinh(), Range Errors)<br />

Because this function has no domain errors but may have range errors, the programmer must detect<br />

a range error and act accordingly:<br />

#include <br />

#include <br />

#include <br />

void func(double x) {<br />

double result;<br />

{<br />

#pragma STDC FENV_ACCESS ON<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 181<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

if (math_errhandling & MATH_ERREXCEPT) {<br />

feclearexcept(FE_ALL_EXCEPT);<br />

}<br />

errno = 0;<br />

result = sinh(x);<br />

}<br />

if ((math_errhandling & MATH_ERRNO) && errno != 0) {<br />

/* Handle range error */<br />

} else if ((math_errhandling & MATH_ERREXCEPT) &&<br />

fetestexcept(FE_INVALID | FE_DIVBYZERO |<br />

FE_OVERFLOW | FE_UNDERFLOW) != 0) {<br />

/* Handle range error */<br />

}<br />

}<br />

/* Use result... */<br />

6.2.8 Noncompliant Code Example (pow())<br />

This noncompliant code example raises x to the power of y:<br />

#include <br />

void func(double x, double y) {<br />

double result;<br />

result = pow(x, y);<br />

}<br />

This code may produce a domain error if x is negative and y is not an integer value or if x is 0 and<br />

y is 0. A domain error or pole error may occur if x is 0 and y is negative, and a range error may<br />

occur if the result cannot be represented as a double.<br />

6.2.9 Compliant Solution (pow())<br />

Because the pow() function can produce domain errors, pole errors, and range errors, the programmer<br />

must first check that x and y lie within the proper domain and do not generate a pole error<br />

and then detect whether a range error occurs and act accordingly:<br />

#include <br />

#include <br />

#include <br />

void func(double x, double y) {<br />

double result;<br />

if (((x == 0.0f) && islessequal(y, 0.0)) || isless(x, 0.0)) {<br />

/* Handle domain or pole error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 182<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

}<br />

{<br />

#pragma STDC FENV_ACCESS ON<br />

if (math_errhandling & MATH_ERREXCEPT) {<br />

feclearexcept(FE_ALL_EXCEPT);<br />

}<br />

errno = 0;<br />

result = pow(x, y);<br />

}<br />

if ((math_errhandling & MATH_ERRNO) && errno != 0) {<br />

/* Handle range error */<br />

} else if ((math_errhandling & MATH_ERREXCEPT) &&<br />

fetestexcept(FE_INVALID | FE_DIVBYZERO |<br />

FE_OVERFLOW | FE_UNDERFLOW) != 0) {<br />

/* Handle range error */<br />

}<br />

}<br />

/* Use result... */<br />

6.2.10 Noncompliant Code Example (asin(), Subnormal Number)<br />

This noncompliant code example determines the inverse sine of x:<br />

#include <br />

void func(float x) {<br />

float result = asin(x);<br />

/* ... */<br />

}<br />

6.2.11 Compliant Solution (asin(), Subnormal Number)<br />

Because this function has no domain errors but may have range errors, the programmer must detect<br />

a range error and act accordingly:<br />

#include <br />

#include <br />

#include <br />

void func(float x) {<br />

float result;<br />

{<br />

#pragma STDC FENV_ACCESS ON<br />

if (math_errhandling & MATH_ERREXCEPT) {<br />

feclearexcept(FE_ALL_EXCEPT);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 183<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP32-C. Prevent or detect domain and range errors in math functions<br />

}<br />

errno = 0;<br />

result = asin(x);<br />

}<br />

if ((math_errhandling & MATH_ERRNO) && errno != 0) {<br />

/* Handle range error */<br />

} else if ((math_errhandling & MATH_ERREXCEPT) &&<br />

fetestexcept(FE_INVALID | FE_DIVBYZERO |<br />

FE_OVERFLOW | FE_UNDERFLOW) != 0) {<br />

/* Handle range error */<br />

}<br />

}<br />

/* Use result... */<br />

6.2.12 Risk Assessment<br />

Failure to prevent or detect domain and range errors in math functions may cause unexpected results.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FLP32-C Medium Probable Medium P8 L2<br />

6.2.13 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

MITRE CWE<br />

FLP03-C. Detect and handle floating-point errors<br />

CWE-682, Incorrect Calculation<br />

6.2.14 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.3.2, “Conventions”<br />

7.12.1, “Treatment of Error Conditions”<br />

F.10.7, “Remainder Functions”<br />

[IEEE 754 2006]<br />

[Plum 1985] Rule 2-2<br />

[Plum 1989]<br />

Topic 2.10, “conv—Conversions and Overflow”<br />

[UNIX 1992]<br />

System V Interface Definition (SVID3)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 184<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP34-C. Ensure that floating-point conversions are within range of the new type<br />

6.3 FLP34-C. Ensure that floating-point conversions are within range<br />

of the new type<br />

If a floating-point value is to be converted to a floating-point value of a smaller range and precision<br />

or to an integer type, or if an integer type is to be converted to a floating-point type, the value<br />

must be representable in the destination type.<br />

The C <strong>Standard</strong>, 6.3.1.4, paragraph 1 [ISO/IEC 9899:2011], says,<br />

When a finite value of real floating type is converted to an integer type other than _Bool,<br />

the fractional part is discarded (i.e., the value is truncated toward zero). If the value of<br />

the integral part cannot be represented by the integer type, the behavior is undefined.<br />

Paragraph 2 of the same subclause says,<br />

When a value of integer type is converted to a real floating type, if the value being converted<br />

can be represented exactly in the new type, it is unchanged. If the value being<br />

converted is in the range of values that can be represented but cannot be represented<br />

exactly, the result is either the nearest higher or nearest lower representable value, chosen<br />

in an implementation-defined manner. If the value being converted is outside the<br />

range of values that can be represented, the behavior is undefined.<br />

And subclause 6.3.1.5, paragraph 1, says,<br />

When a value of real floating type is converted to a real floating type, if the value being<br />

converted can be represented exactly in the new type, it is unchanged. If the value being<br />

converted is in the range of values that can be represented but cannot be represented<br />

exactly, the result is either the nearest higher or nearest lower representable value, chosen<br />

in an implementation-defined manner. If the value being converted is outside the<br />

range of values that can be represented, the behavior is undefined.<br />

See undefined behaviors 17 and 18.<br />

This rule does not apply to demotions of floating-point types on implementations that support<br />

signed infinity, such as IEEE 754, as all values are within range.<br />

6.3.1 Noncompliant Code Example (float to int)<br />

This noncompliant code example leads to undefined behavior if the integral part of f_a cannot be<br />

represented as an integer:<br />

void func(float f_a) {<br />

int i_a;<br />

/* Undefined if the integral part of f_a cannot be represented.<br />

*/<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 185<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP34-C. Ensure that floating-point conversions are within range of the new type<br />

}<br />

i_a = f_a;<br />

6.3.2 Compliant Solution (float to int)<br />

This compliant solution tests to ensure that the float value will fit within the int variable before<br />

performing the assignment.<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t); /* See INT35-C */<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

void func(float f_a) {<br />

int i_a;<br />

}<br />

if (PRECISION(INT_MAX) < log2f(fabsf(f_a)) ||<br />

(f_a != 0.0F && fabsf(f_a) < FLT_MIN)) {<br />

/* Handle error */<br />

} else {<br />

i_a = f_a;<br />

}<br />

6.3.3 Noncompliant Code Example (Narrowing Conversion)<br />

This noncompliant code example attempts to perform conversions that may result in truncating<br />

values outside the range of the destination types:<br />

void func(double d_a, long double big_d) {<br />

double d_b = (float)big_d;<br />

float f_a = (float)d_a;<br />

float f_b = (float)big_d;<br />

}<br />

As a result of these conversions, it is possible that d_a is outside the range of values that can be<br />

represented by a float or that big_d is outside the range of values that can be represented as either<br />

a float or a double. If this is the case, the result is undefined on implementations that do not<br />

support Annex F, “IEC 60559 Floating-Point Arithmetic.”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 186<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP34-C. Ensure that floating-point conversions are within range of the new type<br />

6.3.4 Compliant Solution (Narrowing Conversion)<br />

This compliant solution checks whether the values to be stored can be represented in the new<br />

type:<br />

#include <br />

#include <br />

void func(double d_a, long double big_d) {<br />

double d_b;<br />

float f_a;<br />

float f_b;<br />

}<br />

if (isgreater(fabs(d_a), FLT_MAX) ||<br />

isless(fabs(d_a), FLT_MIN)) {<br />

/* Handle error */<br />

} else {<br />

f_a = (float)d_a;<br />

}<br />

if (isgreater(fabsl(big_d), FLT_MAX) ||<br />

isless(fabsl(big_d), FLT_MIN)) {<br />

/* Handle error */<br />

} else {<br />

f_b = (float)big_d;<br />

}<br />

if (isgreater(fabsl(big_d), DBL_MAX) ||<br />

isless(fabsl(big_d), DBL_MIN)) {<br />

/* Handle error */<br />

} else {<br />

d_b = (double)big_d;<br />

}<br />

6.3.5 Risk Assessment<br />

Converting a floating-point value to a floating-point value of a smaller range and precision or to<br />

an integer type, or converting an integer type to a floating-point type, can result in a value that is<br />

not representable in the destination type and is undefined behavior on implementations that do not<br />

support Annex F.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FLP34-C Low Unlikely Low P3 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 187<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP34-C. Ensure that floating-point conversions are within range of the new type<br />

6.3.6 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java NUM12-J. Ensure conversions of numeric<br />

types to narrower types do not result in lost or<br />

misinterpreted data<br />

ISO/IEC TR 24772:2013<br />

MITRE CWE<br />

Numeric Conversion Errors [FLC]<br />

CWE-681, Incorrect Conversion between Numeric<br />

Types<br />

6.3.7 Bibliography<br />

[IEEE 754 2006]<br />

[ISO/IEC 9899:2011]<br />

Subclause 6.3.1.4, “Real Floating and Integer”<br />

Subclause 6.3.1.5, “Real Floating Types”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 188<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP36-C. Preserve precision when converting integral values to floating-point type<br />

6.4 FLP36-C. Preserve precision when converting integral values to<br />

floating-point type<br />

Narrower arithmetic types can be cast to wider types without any effect on the magnitude of numeric<br />

values. However, whereas integer types represent exact values, floating-point types have<br />

limited precision. The C <strong>Standard</strong>, 6.3.1.4 paragraph 2 [ISO/IEC 9899:2011], states<br />

When a value of integer type is converted to a real floating type, if the value being converted<br />

can be represented exactly in the new type, it is unchanged. If the value being<br />

converted is in the range of values that can be represented but cannot be represented<br />

exactly, the result is either the nearest higher or nearest lower representable value, chosen<br />

in an implementation-defined manner. If the value being converted is outside the<br />

range of values that can be represented, the behavior is undefined. Results of some implicit<br />

conversions may be represented in greater range and precision than that required<br />

by the new type (see 6.3.1.8 and 6.8.6.4).<br />

Conversion from integral types to floating-point types without sufficient precision can lead to loss<br />

of precision (loss of least significant bits). No runtime exception occurs despite the loss.<br />

6.4.1 Noncompliant Code Example<br />

In this noncompliant example, a large value of type long int is converted to a value of type<br />

float without ensuring it is representable in the type:<br />

#include <br />

int main(void) {<br />

long int big = 1234567890;<br />

float approx = big;<br />

printf("%ld\n", (big - (long int)approx));<br />

return 0;<br />

}<br />

For most floating-point hardware, the value closest to 1234567890 that is representable in type<br />

float is 1234567844; consequently, this program prints the value -46.<br />

6.4.2 Compliant Solution<br />

This compliant solution replaces the type float with a double. Furthermore, it uses an assertion<br />

to guarantee that the double type can represent any long int without loss of precision. (See<br />

INT35-C. Use correct integer precisions and MSC11-C. Incorporate diagnostic tests using assertions.)<br />

#include <br />

#include <br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 189<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP36-C. Preserve precision when converting integral values to floating-point type<br />

#include <br />

#include <br />

extern size_t popcount(uintmax_t); /* See INT35-C */<br />

#define PRECISION(umax_value) popcount(umax_value)<br />

int main(void) {<br />

assert(PRECISION(LONG_MAX)


Floating Point (FLP) - FLP37-C. Do not use object representations to compare floating-point values<br />

6.5 FLP37-C. Do not use object representations to compare floatingpoint<br />

values<br />

The object representation for floating-point values is implementation defined. However, an implementation<br />

that defines the __STDC_IEC_559__ macro shall conform to the IEC 60559 floatingpoint<br />

standard and uses what is frequently referred to as IEEE 754 floating-point arithmetic<br />

[ISO/IEC 9899:2011]. The floating-point object representation used by IEC 60559 is one of the<br />

most common floating-point object representations in use today.<br />

All floating-point object representations use specific bit patterns to encode the value of the floating-point<br />

number being represented. However, equivalence of floating-point values is not encoded<br />

solely by the bit pattern used to represent the value. For instance, if the floating-point format supports<br />

negative zero values (as IEC 60559 does), the values -0.0 and 0.0 are equivalent and will<br />

compare as equal, but the bit patterns used in the object representation are not identical. Similarly,<br />

if two floating-point values are both (the same) NaN, they will not compare as equal, despite the<br />

bit patterns being identical, because they are not equivalent.<br />

Do not compare floating-point object representations directly, such as by calling memcmp() or its<br />

moral equivalents. Instead, the equality operators (== and !=) should be used to determine if two<br />

floating-point values are equivalent.<br />

6.5.1 Noncompliant Code Example<br />

In this noncompliant code example, memcmp() is used to compare two structures for equality.<br />

However, since the structure contains a floating-point object, this code may not behave as the programmer<br />

intended.<br />

#include <br />

#include <br />

struct S {<br />

int i;<br />

float f;<br />

};<br />

bool are_equal(const struct S *s1, const struct S *s2) {<br />

if (!s1 && !s2)<br />

return true;<br />

else if (!s1 || !s2)<br />

return false;<br />

return 0 == memcmp(s1, s2, sizeof(struct S));<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 191<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Floating Point (FLP) - FLP37-C. Do not use object representations to compare floating-point values<br />

6.5.2 Compliant Solution<br />

In this compliant solution, the structure members are compared individually:<br />

#include <br />

#include <br />

struct S {<br />

int i;<br />

float f;<br />

};<br />

bool are_equal(const struct S *s1, const struct S *s2) {<br />

if (!s1 && !s2)<br />

return true;<br />

else if (!s1 || !s2)<br />

return false;<br />

return s1->i == s2->i &&<br />

s1->f == s2->f;<br />

}<br />

6.5.3 Risk Assessment<br />

Using the object representation of a floating-point value for comparisons can lead to incorrect<br />

equality results, which can lead to unexpected behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FLP37-C Low Unlikely Medium P2 L3<br />

6.5.4 Related Guidelines<br />

6.5.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Annex F, “IEC 60559 floating-point arithmetic”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 192<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

7 Array (ARR)<br />

7.1 ARR30-C. Do not form or use out-of-bounds pointers or array<br />

subscripts<br />

The C <strong>Standard</strong> identifies the following distinct situations in which undefined behavior (UB) can<br />

arise as a result of invalid pointer operations:<br />

UB Description Example Code<br />

46 Addition or subtraction of a pointer<br />

into, or just beyond, an array object<br />

and an integer type produces<br />

a result that does not point into, or<br />

just beyond, the same array object.<br />

47 Addition or subtraction of a pointer<br />

into, or just beyond, an array object<br />

and an integer type produces<br />

a result that points just beyond the<br />

array object and is used as the operand<br />

of a unary * operator that is<br />

evaluated.<br />

49 An array subscript is out of range,<br />

even if an object is apparently accessible<br />

with the given subscript,<br />

for example, in the lvalue expression<br />

a [1] [7] given the declaration<br />

int a [4] [5]).<br />

62 An attempt is made to access, or<br />

generate a pointer to just past, a<br />

flexible array member of a structure<br />

when the referenced object<br />

provides no elements for that array.<br />

Forming Out-of-Bounds Pointer,<br />

Null Pointer Arithmetic<br />

Dereferencing Past the End<br />

Pointer, Using Past the End Index<br />

Apparently Accessible Out-of-<br />

Range Index<br />

Pointer Past Flexible Array Member<br />

7.1.1 Noncompliant Code Example (Forming Out-of-Bounds Pointer)<br />

In this noncompliant code example, the function f() attempts to validate the index before using<br />

it as an offset to the statically allocated table of integers. However, the function fails to reject<br />

negative index values. When index is less than zero, the behavior of the addition expression in<br />

the return statement of the function is undefined behavior 46. On some implementations, the addition<br />

alone can trigger a hardware trap. On other implementations, the addition may produce a result<br />

that when dereferenced triggers a hardware trap. Other implementations still may produce a<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 193<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

dereferenceable pointer that points to an object distinct from table. Using such a pointer to access<br />

the object may lead to information exposure or cause the wrong object to be modified.<br />

enum { TABLESIZE = 100 };<br />

static int table[TABLESIZE];<br />

int *f(int index) {<br />

if (index < TABLESIZE) {<br />

return table + index;<br />

}<br />

return NULL;<br />

}<br />

7.1.2 Compliant Solution<br />

One compliant solution is to detect and reject invalid values of index if using them in pointer<br />

arithmetic would result in an invalid pointer:<br />

enum { TABLESIZE = 100 };<br />

static int table[TABLESIZE];<br />

int *f(int index) {<br />

if (index >= 0 && index < TABLESIZE) {<br />

return table + index;<br />

}<br />

return NULL;<br />

}<br />

7.1.3 Compliant Solution<br />

Another slightly simpler and potentially more efficient compliant solution is to use an unsigned<br />

type to avoid having to check for negative values while still rejecting out-of-bounds positive values<br />

of index:<br />

#include <br />

enum { TABLESIZE = 100 };<br />

static int table[TABLESIZE];<br />

int *f(size_t index) {<br />

if (index < TABLESIZE) {<br />

return table + index;<br />

}<br />

return NULL;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 194<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

7.1.4 Noncompliant Code Example (Dereferencing Past-the-End Pointer)<br />

This noncompliant code example shows the flawed logic in the Windows Distributed Component<br />

Object Model (DCOM) Remote Procedure Call (RPC) interface that was exploited by the<br />

W32.Blaster.Worm. The error is that the while loop in the GetMachineName() function (used<br />

to extract the host name from a longer string) is not sufficiently bounded. When the character array<br />

pointed to by pwszTemp does not contain the backslash character among the first<br />

MAX_COMPUTERNAME_LENGTH_FQDN + 1 elements, the final valid iteration of the loop will<br />

dereference past the end pointer, resulting in exploitable undefined behavior 47. In this case, the<br />

actual exploit allowed the attacker to inject executable code into a running program. Economic<br />

damage from the Blaster worm has been estimated to be at least $525 million [Pethia 2003].<br />

For a discussion of this programming error in the Common Weakness Enumeration database, see<br />

CWE-119, “Improper Restriction of Operations within the Bounds of a Memory Buffer,” and<br />

CWE-121, “Stack-based Buffer Overflow” [MITRE 2013].<br />

error_status_t _RemoteActivation(<br />

/* ... */, WCHAR *pwszObjectName, ... ) {<br />

*phr = GetServerPath(<br />

pwszObjectName, &pwszObjectName);<br />

/* ... */<br />

}<br />

HRESULT GetServerPath(<br />

WCHAR *pwszPath, WCHAR **pwszServerPath ){<br />

WCHAR *pwszFinalPath = pwszPath;<br />

WCHAR wszMachineName[MAX_COMPUTERNAME_LENGTH_FQDN+1];<br />

hr = GetMachineName(pwszPath, wszMachineName);<br />

*pwszServerPath = pwszFinalPath;<br />

}<br />

HRESULT GetMachineName(<br />

WCHAR *pwszPath,<br />

WCHAR wszMachineName[MAX_COMPUTERNAME_LENGTH_FQDN+1])<br />

{<br />

pwszServerName = wszMachineName;<br />

LPWSTR pwszTemp = pwszPath + 2;<br />

while (*pwszTemp != L'\\')<br />

*pwszServerName++ = *pwszTemp++;<br />

/* ... */<br />

}<br />

7.1.5 Compliant Solution<br />

In this compliant solution, the while loop in the GetMachineName() function is bounded so<br />

that the loop terminates when a backslash character is found, the null-termination character<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 195<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

(L'\0') is discovered, or the end of the buffer is reached. This code does not result in a buffer<br />

overflow even if no backslash character is found in wszMachineName.<br />

HRESULT GetMachineName(<br />

wchar_t *pwszPath,<br />

wchar_t wszMachineName[MAX_COMPUTERNAME_LENGTH_FQDN+1])<br />

{<br />

wchar_t *pwszServerName = wszMachineName;<br />

wchar_t *pwszTemp = pwszPath + 2;<br />

wchar_t *end_addr<br />

= pwszServerName + MAX_COMPUTERNAME_LENGTH_FQDN;<br />

while ( (*pwszTemp != L'\\')<br />

&& ((*pwszTemp != L'\0'))<br />

&& (pwszServerName < end_addr) )<br />

{<br />

*pwszServerName++ = *pwszTemp++;<br />

}<br />

}<br />

/* ... */<br />

This compliant solution is for illustrative purposes and is not necessarily the solution implemented<br />

by Microsoft. This particular solution may not be correct because there is no guarantee that a<br />

backslash is found.<br />

7.1.6 Noncompliant Code Example (Using Past-the-End Index)<br />

Similar to the dereferencing-past-the-end-pointer error, the function insert_in_table() in this<br />

noncompliant code example uses an otherwise valid index to attempt to store a value in an element<br />

just past the end of an array.<br />

First, the function incorrectly validates the index pos against the size of the buffer. When pos is<br />

initially equal to size, the function attempts to store value in a memory location just past the<br />

end of the buffer.<br />

Second, when the index is greater than size, the function modifies size before growing the size<br />

of the buffer. If the call to realloc() fails to increase the size of the buffer, the next call to the<br />

function with a value of pos equal to or greater than the original value of size will again attempt<br />

to store value in a memory location just past the end of the buffer or beyond.<br />

Third, the function violates INT30-C. Ensure that unsigned integer operations do not wrap, which<br />

could lead to wrapping when 1 is added to pos or when size is multiplied by the size of int.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 196<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

For a discussion of this programming error in the Common Weakness Enumeration database, see<br />

CWE-122, “Heap-based Buffer Overflow,” and CWE-129, “Improper Validation of Array Index”<br />

[MITRE 2013].<br />

#include <br />

static int *table = NULL;<br />

static size_t size = 0;<br />

int insert_in_table(size_t pos, int value) {<br />

if (size < pos) {<br />

int *tmp;<br />

size = pos + 1;<br />

tmp = (int *)realloc(table, sizeof(*table) * size);<br />

if (tmp == NULL) {<br />

return -1; /* Failure */<br />

}<br />

table = tmp;<br />

}<br />

}<br />

table[pos] = value;<br />

return 0;<br />

7.1.7 Compliant Solution<br />

This compliant solution correctly validates the index pos by using the


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

}<br />

table = tmp;<br />

}<br />

table[pos] = value;<br />

return 0;<br />

7.1.8 Noncompliant Code Example (Apparently Accessible Out-of-Range Index)<br />

This noncompliant code example declares matrix to consist of 7 rows and 5 columns in row-major<br />

order. The function init_matrix iterates over all 35 elements in an attempt to initialize each<br />

to the value given by the function argument x. However, because multidimensional arrays are declared<br />

in C in row-major order, the function iterates over the elements in column-major order, and<br />

when the value of j reaches the value COLS during the first iteration of the outer loop, the function<br />

attempts to access element matrix[0][5]. Because the type of matrix is int[7][5], the<br />

j subscript is out of range, and the access has undefined behavior 49.<br />

#include <br />

#define COLS 5<br />

#define ROWS 7<br />

static int matrix[ROWS][COLS];<br />

void init_matrix(int x) {<br />

for (size_t i = 0; i < COLS; i++) {<br />

for (size_t j = 0; j < ROWS; j++) {<br />

matrix[i][j] = x;<br />

}<br />

}<br />

}<br />

7.1.9 Compliant Solution<br />

This compliant solution avoids using out-of-range indices by initializing matrix elements in the<br />

same row-major order as multidimensional objects are declared in C:<br />

#include <br />

#define COLS 5<br />

#define ROWS 7<br />

static int matrix[ROWS][COLS];<br />

void init_matrix(int x) {<br />

for (size_t i = 0; i < ROWS; i++) {<br />

for (size_t j = 0; j < COLS; j++) {<br />

matrix[i][j] = x;<br />

}<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 198<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

7.1.10 Noncompliant Code Example (Pointer Past Flexible Array Member)<br />

In this noncompliant code example, the function find() attempts to iterate over the elements of<br />

the flexible array member buf, starting with the second element. However, because function g()<br />

does not allocate any storage for the member, the expression first++ in find() attempts to<br />

form a pointer just past the end of buf when there are no elements. This attempt is undefined behavior<br />

62. (See MSC21-C. Use robust loop termination conditions for more information.)<br />

#include <br />

struct S {<br />

size_t len;<br />

char buf[]; /* Flexible array member */<br />

};<br />

const char *find(const struct S *s, int c) {<br />

const char *first = s->buf;<br />

const char *last = s->buf + s->len;<br />

}<br />

while (first++ != last) { /* Undefined behavior */<br />

if (*first == (unsigned char)c) {<br />

return first;<br />

}<br />

}<br />

return NULL;<br />

void g(void) {<br />

struct S *s = (struct S *)malloc(sizeof(struct S));<br />

if (s == NULL) {<br />

/* Handle error */<br />

}<br />

s->len = 0;<br />

find(s, 'a');<br />

}<br />

7.1.11 Compliant Solution<br />

This compliant solution avoids incrementing the pointer unless a value past the pointer's current<br />

value is known to exist:<br />

#include <br />

struct S {<br />

size_t len;<br />

char buf[]; /* Flexible array member */<br />

};<br />

const char *find(const struct S *s, int c) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 199<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

const char *first = s->buf;<br />

const char *last = s->buf + s->len;<br />

}<br />

while (first != last) { /* Avoid incrementing here */<br />

if (*++first == (unsigned char)c) {<br />

return first;<br />

}<br />

}<br />

return NULL;<br />

void g(void) {<br />

struct S *s = (struct S *)malloc(sizeof(struct S));<br />

if (s == NULL) {<br />

/* Handle error */<br />

}<br />

s->len = 0;<br />

find(s, 'a');<br />

}<br />

7.1.12 Noncompliant Code Example (Null Pointer Arithmetic)<br />

This noncompliant code example is similar to an Adobe Flash Player vulnerability that was first<br />

exploited in 2008. This code allocates a block of memory and initializes it with some data. The<br />

data does not belong at the beginning of the block, which is left uninitialized. Instead, it is placed<br />

offset bytes within the block. The function ensures that the data fits within the allocated block.<br />

#include <br />

#include <br />

char *init_block(size_t block_size, size_t offset,<br />

char *data, size_t data_size) {<br />

char *buffer = malloc(block_size);<br />

if (data_size > block_size || block_size - data_size < offset) {<br />

/* Data won't fit in buffer, handle error */<br />

}<br />

memcpy(buffer + offset, data, data_size);<br />

return buffer;<br />

}<br />

This function fails to check if the allocation succeeds, which is a violation of ERR33-C. Detect<br />

and handle standard library errors. If the allocation fails, then malloc() returns a null pointer.<br />

The null pointer is added to offset and passed as the destination argument to memcpy(). Because<br />

a null pointer does not point to a valid object, the result of the pointer arithmetic is undefined<br />

behavior 46.<br />

An attacker who can supply the arguments to this function can exploit it to execute arbitrary code.<br />

This can be accomplished by providing an overly large value for block_size, which causes<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 200<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

malloc() to fail and return a null pointer. The offset argument will then serve as the destination<br />

address to the call to memcpy(). The attacker can specify the data and data_size arguments<br />

to provide the address and length of the address, respectively, that the attacker wishes to<br />

write into the memory referenced by offset. The overall result is that the call to memcpy() can<br />

be exploited by an attacker to overwrite an arbitrary memory location with an attacker-supplied<br />

address, typically resulting in arbitrary code execution.<br />

7.1.13 Compliant Solution (Null Pointer Arithmetic)<br />

This compliant solution ensures that the call to malloc() succeeds:<br />

#include <br />

#include <br />

char *init_block(size_t block_size, size_t offset,<br />

char *data, size_t data_size) {<br />

char *buffer = malloc(block_size);<br />

if (NULL == buffer) {<br />

/* Handle error */<br />

}<br />

if (data_size > block_size || block_size - data_size < offset) {<br />

/* Data won't fit in buffer, handle error */<br />

}<br />

memcpy(buffer + offset, data, data_size);<br />

return buffer;<br />

}<br />

7.1.14 Risk Assessment<br />

Writing to out-of-range pointers or array subscripts can result in a buffer overflow and the execution<br />

of arbitrary code with the permissions of the vulnerable process. Reading from out-of-range<br />

pointers or array subscripts can result in unintended information disclosure.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR30-C High Likely High P9 L2<br />

7.1.14.1 Related Vulnerabilities<br />

CVE-2008-1517 results from a violation of this rule. Before Mac OSX version 10.5.7, the XNU<br />

kernel accessed an array at an unverified user-input index, allowing an attacker to execute arbitrary<br />

code by passing an index greater than the length of the array and therefore accessing outside<br />

memory [xorl 2009].<br />

7.1.15 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

Arithmetic Wrap-Around Error [FIF]<br />

Unchecked Array Indexing [XYZ]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 201<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR30-C. Do not form or use out-of-bounds pointers or array subscripts<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

MISRA C:2012<br />

Forming or using out-of-bounds pointers or array<br />

subscripts [invptr]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-122, Heap-based Buffer Overflow<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-129, Improper Validation of Array Index<br />

CWE-788, Access of Memory Location after<br />

End of Buffer<br />

Rule 18.1 (required)<br />

7.1.16 Bibliography<br />

[Finlay 2003]<br />

[Microsoft 2003]<br />

[Pethia 2003]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

[xorl 2009 ]<br />

Chapter 1, “Running with Scissors”<br />

Section 5.2.13, “Unchecked Array Indexing”<br />

“CVE-2008-1517: Apple Mac OS X (XNU)<br />

Missing Array Index Validation”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 202<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR32-C. Ensure size arguments for variable length arrays are in a valid range<br />

7.2 ARR32-C. Ensure size arguments for variable length arrays are in a<br />

valid range<br />

Variable length arrays (VLAs), a conditionally supported language feature, are essentially the<br />

same as traditional C arrays except that they are declared with a size that is not a constant integer<br />

expression and can be declared only at block scope or function prototype scope and no linkage.<br />

When supported, a variable length array can be declared<br />

{ /* Block scope */<br />

char vla[size];<br />

}<br />

where the integer expression size and the declaration of vla are both evaluated at runtime. If the<br />

size argument supplied to a variable length array is not a positive integer value, the behavior is<br />

undefined. (See undefined behavior 75.) Additionally, if the magnitude of the argument is excessive,<br />

the program may behave in an unexpected way. An attacker may be able to leverage this behavior<br />

to overwrite critical program data [Griffiths 2006]. The programmer must ensure that size<br />

arguments to variable length arrays, especially those derived from untrusted data, are in a valid<br />

range.<br />

Because variable length arrays are a conditionally supported feature of C11, their use in portable<br />

code should be guarded by testing the value of the macro __STDC_NO_VLA__. Implementations<br />

that do not support variable length arrays indicate it by setting __STDC_NO_VLA__ to the integer<br />

constant 1.<br />

7.2.1 Noncompliant Code Example<br />

In this noncompliant code example, a variable length array of size is declared. The size is declared<br />

as size_t in compliance with INT01-C. Use rsize_t or size_t for all integer values representing<br />

the size of an object.<br />

#include <br />

extern void do_work(int *array, size_t size);<br />

void func(size_t size) {<br />

int vla[size];<br />

do_work(vla, size);<br />

}<br />

However, the value of size may be zero or excessive, potentially giving rise to a security vulnerability.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 203<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR32-C. Ensure size arguments for variable length arrays are in a valid range<br />

7.2.2 Compliant Solution<br />

This compliant solution ensures the size argument used to allocate vla is in a valid range (between<br />

1 and a programmer-defined maximum); otherwise, it uses an algorithm that relies on dynamic<br />

memory allocation. The solution also avoids unsigned integer wrapping that, given a sufficiently<br />

large value of size, would cause malloc to allocate insufficient storage for the array.<br />

#include <br />

#include <br />

enum { MAX_ARRAY = 1024 };<br />

extern void do_work(int *array, size_t size);<br />

void func(size_t size) {<br />

if (0 == size || SIZE_MAX / sizeof(int) < size) {<br />

/* Handle error */<br />

return;<br />

}<br />

if (size < MAX_ARRAY) {<br />

int vla[size];<br />

do_work(vla, size);<br />

} else {<br />

int *array = (int *)malloc(size * sizeof(int));<br />

if (array == NULL) {<br />

/* Handle error */<br />

}<br />

do_work(array, size);<br />

free(array);<br />

}<br />

}<br />

7.2.3 Noncompliant Code Example (sizeof)<br />

The following noncompliant code example defines A to be a variable length array and then uses<br />

the sizeof operator to compute its size at runtime. When the function is called with an argument<br />

greater than SIZE_MAX / (N1 * sizeof (int)), the runtime sizeof expression may wrap<br />

around, yielding a result that is smaller than the mathematical product N1 * n2 * sizeof<br />

(int). The call to malloc(), when successful, will then allocate storage for fewer than n2 elements<br />

of the array, causing one or more of the final memset() calls in the for loop to write past<br />

the end of that storage.<br />

#include <br />

#include <br />

enum { N1 = 4096 };<br />

void *func(size_t n2) {<br />

typedef int A[n2][N1];<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 204<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR32-C. Ensure size arguments for variable length arrays are in a valid range<br />

A *array = malloc(sizeof(A));<br />

if (!array) {<br />

/* Handle error */<br />

return NULL;<br />

}<br />

for (size_t i = 0; i != n2; ++i) {<br />

memset(array[i], 0, N1 * sizeof(int));<br />

}<br />

}<br />

return array;<br />

7.2.4 Compliant Solution (sizeof)<br />

This compliant solution prevents sizeof wrapping by detecting the condition before it occurs<br />

and avoiding the subsequent computation when the condition is detected.<br />

#include <br />

#include <br />

#include <br />

enum { N1 = 4096 };<br />

void *func(size_t n2) {<br />

if (n2 > SIZE_MAX / (N1 * sizeof(int))) {<br />

/* Prevent sizeof wrapping */<br />

return NULL;<br />

}<br />

typedef int A[n2][N1];<br />

A *array = malloc(sizeof(A));<br />

if (!array) {<br />

/* Handle error */<br />

return NULL;<br />

}<br />

}<br />

for (size_t i = 0; i != n2; ++i) {<br />

memset(array[i], 0, N1 * sizeof(int));<br />

}<br />

return array;<br />

7.2.4.1 Implementation Details<br />

7.2.4.1.1 Microsoft<br />

Variable length arrays are not supported by Microsoft compilers.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 205<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR32-C. Ensure size arguments for variable length arrays are in a valid range<br />

7.2.5 Risk Assessment<br />

Failure to properly specify the size of a variable length array may allow arbitrary code execution<br />

or result in stack exhaustion.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR32-C High Probable High P6 L2<br />

7.2.6 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

INT01-C. Use rsize_t or size_t for all integer<br />

values representing the size of an object<br />

Unchecked Array Indexing [XYZ]<br />

Tainted, potentially mutilated, or out-of-domain<br />

integer values are used in a restricted sink<br />

[taintsink]<br />

7.2.7 Bibliography<br />

[Griffiths 2006]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 206<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR36-C. Do not subtract or compare two pointers that do not refer to the same array<br />

7.3 ARR36-C. Do not subtract or compare two pointers that do not<br />

refer to the same array<br />

When two pointers are subtracted, both must point to elements of the same array object or just one<br />

past the last element of the array object (C <strong>Standard</strong>, 6.5.6 [ISO/IEC 9899:2011]); the result is the<br />

difference of the subscripts of the two array elements. Otherwise, the operation is undefined behavior.<br />

(See undefined behavior 48.)<br />

Similarly, comparing pointers using the relational operators gives the positions of<br />

the pointers relative to each other. Subtracting or comparing pointers that do not refer to the same<br />

array is undefined behavior. (See undefined behavior 48 and undefined behavior 53.)<br />

Comparing pointers using the equality operators == and != has well-defined semantics regardless<br />

of whether or not either of the pointers is null, points into the same object, or points one past the<br />

last element of an array object or function.<br />

7.3.1 Noncompliant Code Example<br />

In this noncompliant code example, pointer subtraction is used to determine how many free elements<br />

are left in the nums array:<br />

#include <br />

enum { SIZE = 32 };<br />

void func(void) {<br />

int nums[SIZE];<br />

int end;<br />

int *next_num_ptr = nums;<br />

size_t free_elements;<br />

/* Increment next_num_ptr as array fills */<br />

}<br />

free_elements = &end - next_num_ptr;<br />

This program incorrectly assumes that the nums array is adjacent to the end variable in memory.<br />

A compiler is permitted to insert padding bits between these two variables or even reorder them in<br />

memory.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 207<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR36-C. Do not subtract or compare two pointers that do not refer to the same array<br />

7.3.2 Compliant Solution<br />

In this compliant solution, the number of free elements is computed by subtracting<br />

next_num_ptr from the address of the pointer past the nums array. While this pointer may not<br />

be dereferenced, it may be used in pointer arithmetic.<br />

#include <br />

enum { SIZE = 32 };<br />

void func(void) {<br />

int nums[SIZE];<br />

int *next_num_ptr = nums;<br />

size_t free_elements;<br />

/* Increment next_num_ptr as array fills */<br />

}<br />

free_elements = &(nums[SIZE]) - next_num_ptr;<br />

7.3.3 Exceptions<br />

ARR36-C-EX1: Comparing two pointers to distinct members of the same struct object is allowed.<br />

Pointers to structure members declared later in the structure compare greater-than pointers<br />

to members declared earlier in the structure.<br />

7.3.4 Risk Assessment<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR36-C Medium Probable Medium P8 L2<br />

7.3.5 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

CTR54-CPP. Do not subtract iterators that do<br />

not refer to the same container<br />

Subtracting or comparing two pointers that do<br />

not refer to the same array [ptrobj]<br />

CWE-469, Use of Pointer Subtraction to Determine<br />

Size<br />

7.3.6 Bibliography<br />

[Banahan 2003]<br />

[ISO/IEC 9899:2011]<br />

Section 5.3, “Pointers”<br />

Section 5.7, “Expressions Involving Pointers”<br />

6.5.6, “Additive Operators”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 208<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR37-C. Do not add or subtract an integer to a pointer to a non-array object<br />

7.4 ARR37-C. Do not add or subtract an integer to a pointer to a nonarray<br />

object<br />

Pointer arithmetic must be performed only on pointers that reference elements of array objects.<br />

The C <strong>Standard</strong>, 6.5.6 [ISO/IEC 9899:2011], states the following about pointer arithmetic:<br />

When an expression that has integer type is added to or subtracted from a pointer, the<br />

result has the type of the pointer operand. If the pointer operand points to an element of<br />

an array object, and the array is large enough, the result points to an element offset from<br />

the original element such that the difference of the subscripts of the resulting and original<br />

array elements equals the integer expression.<br />

7.4.1 Noncompliant Code Example<br />

This noncompliant code example attempts to access structure members using pointer arithmetic.<br />

This practice is dangerous because structure members are not guaranteed to be contiguous.<br />

struct numbers {<br />

short num_a, num_b, num_c;<br />

};<br />

int sum_numbers(const struct numbers *numb){<br />

int total = 0;<br />

const short *numb_ptr;<br />

for (numb_ptr = &numb->num_a;<br />

numb_ptr num_c;<br />

numb_ptr++) {<br />

total += *(numb_ptr);<br />

}<br />

}<br />

return total;<br />

int main(void) {<br />

struct numbers my_numbers = { 1, 2, 3 };<br />

sum_numbers(&my_numbers);<br />

return 0;<br />

}<br />

7.4.2 Compliant Solution<br />

It is possible to use the -> operator to dereference each structure member:<br />

total = numb->num_a + numb->num_b + numb->num_c;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 209<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR37-C. Do not add or subtract an integer to a pointer to a non-array object<br />

However, this solution results in code that is hard to write and hard to maintain (especially if there<br />

are many more structure members), which is exactly what the author of the noncompliant code<br />

example was likely trying to avoid.<br />

7.4.3 Compliant Solution<br />

A better solution is to define the structure to contain an array member to store the numbers in an<br />

array rather than a structure, as in this compliant solution:<br />

#include <br />

struct numbers {<br />

short a[3];<br />

};<br />

int sum_numbers(const short *numb, size_t dim) {<br />

int total = 0;<br />

for (size_t i = 0; i < dim; ++i) {<br />

total += numb[i];<br />

}<br />

}<br />

return total;<br />

int main(void) {<br />

struct numbers my_numbers = { .a[0]= 1, .a[1]= 2, .a[2]= 3};<br />

sum_numbers(<br />

my_numbers.a,<br />

sizeof(my_numbers.a)/sizeof(my_numbers.a[0])<br />

);<br />

return 0;<br />

}<br />

Array elements are guaranteed to be contiguous in memory, so this solution is completely portable.<br />

7.4.4 Exceptions<br />

ARR37-C-EX1: Any non-array object in memory can be considered an array consisting of one<br />

element. Adding one to a pointer to such an object yields a pointer one element past the array, and<br />

subtracting one from that pointer yields the original pointer. This allows for code such as the following:<br />

#include <br />

#include <br />

struct s {<br />

char *c_str;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 210<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR37-C. Do not add or subtract an integer to a pointer to a non-array object<br />

/* Other members */<br />

};<br />

struct s *create_s(const char *c_str) {<br />

struct s *ret;<br />

size_t len = strlen(c_str) + 1;<br />

}<br />

ret = (struct s *)malloc(sizeof(struct s) + len);<br />

if (ret != NULL) {<br />

ret->c_str = (char *)(ret + 1);<br />

memcpy(ret + 1, c_str, len);<br />

}<br />

return ret;<br />

A more general and safer solution to this problem is to use a flexible array member that guarantees<br />

the array that follows the structure is properly aligned by inserting padding, if necessary, between<br />

it and the member that immediately precedes it.<br />

7.4.5 Risk Assessment<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR37-C Medium Probable Medium P8 L2<br />

7.4.6 Related Guidelines<br />

MITRE CWE<br />

CWE-469, Use of Pointer Subtraction to Determine<br />

Size<br />

7.4.7 Bibliography<br />

[Banahan 2003]<br />

[ISO/IEC 9899:2011]<br />

[VU#162289]<br />

Section 5.3, “Pointers”<br />

Section 5.7, “Expressions Involving Pointers”<br />

6.5.6, “Additive Operators”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 211<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

7.5 ARR38-C. Guarantee that library functions do not form invalid<br />

pointers<br />

C library functions that make changes to arrays or objects take at least two arguments: a pointer to<br />

the array or object and an integer indicating the number of elements or bytes to be manipulated.<br />

For the purposes of this rule, the element count of a pointer is the size of the object to which it<br />

points, expressed by the number of elements that are valid to access. Supplying arguments to such<br />

a function might cause the function to form a pointer that does not point into or just past the end<br />

of the object, resulting in undefined behavior.<br />

Annex J of the C <strong>Standard</strong> [ISO/IEC 9899:2011] states that it is undefined behavior if the “pointer<br />

passed to a library function array parameter does not have a value such that all address computations<br />

and object accesses are valid.” (See undefined behavior 109.)<br />

In the following code,<br />

int arr[5];<br />

int *p = arr;<br />

unsigned char *p2 = (unsigned char *)arr;<br />

unsigned char *p3 = arr + 2;<br />

void *p4 = arr;<br />

the element count of the pointer p is sizeof(arr) / sizeof(arr[0]), that is, 5. The element<br />

count of the pointer p2 is sizeof(arr), that is, 20, on implementations where sizeof(int)<br />

== 4. The element count of the pointer p3 is 12 on implementations where sizeof(int) == 4,<br />

because p3 points two elements past the start of the array arr. The element count of p4 is treated<br />

as though it were unsigned char * instead of void *, so it is the same as p2.<br />

7.5.1 Pointer + Integer<br />

The following standard library functions take a pointer argument and a size argument, with the<br />

constraint that the pointer must point to a valid memory object of at least the number of elements<br />

indicated by the size argument.<br />

fgets() fgetws() mbstowcs() 2 wcstombs() 2<br />

mbrtoc16() 3 mbrtoc32() 3 mbsrtowcs() 2 wcsrtombs() 2<br />

mbtowc() 3 mbrtowc() 2 mblen() mbrlen()<br />

memchr() wmemchr() memset() wmemset()<br />

strftime() wcsftime() strxfrm() 2 wcsxfrm() 2<br />

______________________<br />

2<br />

Takes two pointers and an integer, but the integer specifies the element count only of the output buffer, not of<br />

the input buffer.<br />

3<br />

Takes two pointers and an integer, but the integer specifies the element count only of the input buffer, not of the<br />

output buffer.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 212<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

strncat() 3 wcsncat() 3 snprintf() vsnprintf()<br />

swprintf() vswprintf() setvbuf() tmpnam_s()<br />

snprintf_s() sprintf_s() vsnprintf_s() vsprintf_s()<br />

gets_s() getenv_s() wctomb_s() mbstowcs_s() 4<br />

wcstombs_s() 4 memcpy_s() 4 memmove_s() 4 strncpy_s() 4<br />

strncat_s() 4 strtok_s() 3 strerror_s() strnlen_s()<br />

asctime_s() ctime_s() snwprintf_s() swprintf_s()<br />

vsnwprintf_s() vswprintf_s() wcsncpy_s() 4 wmemcpy_s() 4<br />

wmemmove_s() 4 wcsncat_s() 4 wcstok_s() 3 wcsnlen_s()<br />

wcrtomb_s() mbsrtowcs_s() 4 wcsrtombs_s() 4 memset_s() 5<br />

For calls that take a pointer and an integer size, the given size should not be greater than the element<br />

count of the pointer.<br />

7.5.1.1 Noncompliant Code Example (Element Count)<br />

In this noncompliant code example, the incorrect element count is used in a call to wmemcpy().<br />

The sizeof operator returns the size expressed in bytes, but wmemcpy() uses an element count<br />

based on wchar_t *.<br />

#include <br />

#include <br />

static const char str[] = "Hello world";<br />

static const wchar_t w_str[] = L"Hello world";<br />

void func(void) {<br />

char buffer[32];<br />

wchar_t w_buffer[32];<br />

memcpy(buffer, str, sizeof(str)); /* Compliant */<br />

wmemcpy(w_buffer, w_str, sizeof(w_str)); /* Noncompliant */<br />

}<br />

7.5.1.2 Compliant Solution (Element Count)<br />

When using functions that operate on pointed-to regions, programmers must always express the<br />

integer size in terms of the element count expected by the function. For example, memcpy() expects<br />

the element count expressed in terms of void *, but wmemcpy() expects the element count<br />

expressed in terms of wchar_t *. Instead of the sizeof operator, functions that return the number<br />

of elements in the string are called, which matches the expected element count for the copy<br />

______________________<br />

4<br />

Takes two pointers and two integers; each integer corresponds to the element count of one of the pointers.<br />

5<br />

Takes a pointer and two size-related integers; the first size-related integer parameter specifies the number of<br />

bytes available in the buffer; the second size-related integer parameter specifies the number of bytes to write<br />

within the buffer.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 213<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

functions. In the case of this compliant solution, where the argument is an array A of type T, the<br />

expression sizeof(A) / sizeof(T), or equivalently sizeof(A) / sizeof(*A), can be<br />

used to compute the number of elements in the array.<br />

#include <br />

#include <br />

static const char str[] = "Hello world";<br />

static const wchar_t w_str[] = L"Hello world";<br />

void func(void) {<br />

char buffer[32];<br />

wchar_t w_buffer[32];<br />

memcpy(buffer, str, strlen(str) + 1);<br />

wmemcpy(w_buffer, w_str, wcslen(w_str) + 1);<br />

}<br />

7.5.1.3 Noncompliant Code Example (Pointer + Integer)<br />

This noncompliant code example assigns a value greater than the number of bytes of available<br />

memory to n, which is then passed to memset():<br />

#include <br />

#include <br />

void f1(size_t nchars) {<br />

char *p = (char *)malloc(nchars);<br />

/* ... */<br />

const size_t n = nchars + 1;<br />

/* ... */<br />

memset(p, 0, n);<br />

}<br />

7.5.1.4 Compliant Solution (Pointer + Integer)<br />

This compliant solution ensures that the value of n is not greater than the number of bytes of the<br />

dynamic memory pointed to by the pointer p:<br />

#include <br />

#include <br />

void f1(size_t nchars) {<br />

char *p = (char *)malloc(nchars);<br />

/* ... */<br />

const size_t n = nchars;<br />

/* ... */<br />

memset(p, 0, n);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 214<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

7.5.1.5 Noncompliant Code Example (Pointer + Integer)<br />

In this noncompliant code example, the element count of the array a is ARR_SIZE elements. Because<br />

memset() expects a byte count, the size of the array is scaled incorrectly by sizeof(int)<br />

instead of sizeof(long), which can form an invalid pointer on architectures where<br />

sizeof(int) != sizeof(long).<br />

#include <br />

void f2(void) {<br />

const size_t ARR_SIZE = 4;<br />

long a[ARR_SIZE];<br />

const size_t n = sizeof(int) * ARR_SIZE;<br />

void *p = a;<br />

}<br />

memset(p, 0, n);<br />

7.5.1.6 Compliant Solution (Pointer + Integer)<br />

In this compliant solution, the element count required by memset() is properly calculated without<br />

resorting to scaling:<br />

#include <br />

void f2(void) {<br />

const size_t ARR_SIZE = 4;<br />

long a[ARR_SIZE];<br />

const size_t n = sizeof(a);<br />

void *p = a;<br />

}<br />

memset(p, 0, n);<br />

7.5.2 Two Pointers + One Integer<br />

The following standard library functions take two pointer arguments and a size argument, with the<br />

constraint that both pointers must point to valid memory objects of at least the number of elements<br />

indicated by the size argument.<br />

memcpy() wmemcpy() memmove() wmemmove()<br />

strncpy() wcsncpy() memcmp() wmemcmp()<br />

strncmp() wcsncmp() strcpy_s() wcscpy_s()<br />

strcat_s()<br />

wcscat_s()<br />

For calls that take two pointers and an integer size, the given size should not be greater than the<br />

element count of either pointer.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 215<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

7.5.2.1 Noncompliant Code Example (Two Pointers + One Integer)<br />

In this noncompliant code example, the value of n is incorrectly computed, allowing a read past<br />

the end of the object referenced by q:<br />

#include <br />

void f4() {<br />

char p[40];<br />

const char *q = "Too short";<br />

size_t n = sizeof(p);<br />

memcpy(p, q, n);<br />

}<br />

7.5.2.2 Compliant Solution (Two Pointers + One Integer)<br />

This compliant solution ensures that n is equal to the size of the character array:<br />

#include <br />

void f4() {<br />

char p[40];<br />

const char *q = "Too short";<br />

size_t n = sizeof(p) < strlen(q) + 1 ? sizeof(p) : strlen(q) + 1;<br />

memcpy(p, q, n);<br />

}<br />

7.5.3 One Pointer + Two Integers<br />

The following standard library functions take a pointer argument and two size arguments, with the<br />

constraint that the pointer must point to a valid memory object containing at least as many bytes<br />

as the product of the two size arguments.<br />

bsearch() bsearch_s() qsort() qsort_s()<br />

fread()<br />

fwrite()<br />

For calls that take a pointer and two integers, one integer represents the number of bytes required<br />

for an individual object, and a second integer represents the number of elements in the array. The<br />

resulting product of the two integers should not be greater than the element count of the pointer<br />

were it expressed as an unsigned char *.<br />

7.5.3.1 Noncompliant Code Example (One Pointer + Two Integers)<br />

This noncompliant code example allocates a variable number of objects of type struct obj.<br />

The function checks that num_objs is small enough to prevent wrapping, in compliance with<br />

INT30-C. Ensure that unsigned integer operations do not wrap. The size of struct obj is assumed<br />

to be 16 bytes to account for padding to achieve the assumed alignment of long long.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 216<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

However, the padding typically depends on the target architecture, so this object size may be incorrect,<br />

resulting in an incorrect element count.<br />

#include <br />

#include <br />

struct obj {<br />

char c;<br />

long long i;<br />

};<br />

void func(FILE *f, struct obj *objs, size_t num_objs) {<br />

const size_t obj_size = 16;<br />

if (num_objs > (SIZE_MAX / obj_size) ||<br />

num_objs != fwrite(objs, obj_size, num_objs, f)) {<br />

/* Handle error */<br />

}<br />

}<br />

7.5.3.2 Compliant Solution (One Pointer + Two Integers)<br />

This compliant solution uses the sizeof operator to correctly provide the object size and<br />

num_objs to provide the element count:<br />

#include <br />

#include <br />

struct obj {<br />

char c;<br />

long long i;<br />

};<br />

void func(FILE *f, struct obj *objs, size_t num_objs) {<br />

const size_t obj_size = sizeof *objs;<br />

if (num_objs > (SIZE_MAX / obj_size) ||<br />

num_objs != fwrite(objs, obj_size, num_objs, f)) {<br />

/* Handle error */<br />

}<br />

}<br />

7.5.3.3 Noncompliant Code Example (One Pointer + Two Integers)<br />

In this noncompliant code example, the function f() calls fread() to read nitems of type<br />

wchar_t, each size bytes in size, into an array of BUFFER_SIZE elements, wbuf. However, the<br />

expression used to compute the value of nitems fails to account for the fact that, unlike the size<br />

of char, the size of wchar_t may be greater than 1. Consequently, fread() could attempt to<br />

form pointers past the end of wbuf and use them to assign values to nonexistent elements of the<br />

array. Such an attempt is undefined behavior. (See undefined behavior 109.) A likely consequence<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 217<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

of this undefined behavior is a buffer overflow. For a discussion of this programming error in the<br />

Common Weakness Enumeration database, see CWE-121, “Stack-based Buffer Overflow,” and<br />

CWE-805, “Buffer Access with Incorrect Length Value.”<br />

#include <br />

#include <br />

void f(FILE *file) {<br />

enum { BUFFER_SIZE = 1024 };<br />

wchar_t wbuf[BUFFER_SIZE];<br />

const size_t size = sizeof(*wbuf);<br />

const size_t nitems = sizeof(wbuf);<br />

}<br />

size_t nread = fread(wbuf, size, nitems, file);<br />

/* ... */<br />

7.5.3.4 Compliant Solution (One Pointer + Two Integers)<br />

This compliant solution correctly computes the maximum number of items for fread() to read<br />

from the file:<br />

#include <br />

#include <br />

void f(FILE *file) {<br />

enum { BUFFER_SIZE = 1024 };<br />

wchar_t wbuf[BUFFER_SIZE];<br />

const size_t size = sizeof(*wbuf);<br />

const size_t nitems = sizeof(wbuf) / size;<br />

}<br />

size_t nread = fread(wbuf, size, nitems, file);<br />

/* ... */<br />

7.5.3.5 Noncompliant Code Example (Heartbleed)<br />

<strong>CERT</strong> vulnerability 720951 describes a vulnerability in OpenSSL versions 1.0.1 through 1.0.1f,<br />

popularly known as “Heartbleed.” This vulnerability allows an attacker to steal information that<br />

under normal conditions would be protected by Secure Socket Layer/Transport Layer Security<br />

(SSL/TLS) encryption.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 218<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

Despite the seriousness of the vulnerability, Heartbleed is the result of a common programming<br />

error and an apparent lack of awareness of secure coding principles. Following is the vulnerable<br />

code:<br />

int dtls1_process_heartbeat(SSL *s) {<br />

unsigned char *p = &s->s3->rrec.data[0], *pl;<br />

unsigned short hbtype;<br />

unsigned int payload;<br />

unsigned int padding = 16; /* Use minimum padding */<br />

/* Read type and payload length first */<br />

hbtype = *p++;<br />

n2s(p, payload);<br />

pl = p;<br />

/* ... More code ... */<br />

if (hbtype == TLS1_HB_REQUEST) {<br />

unsigned char *buffer, *bp;<br />

int r;<br />

/*<br />

* Allocate memory for the response; size is 1 byte<br />

* message type, plus 2 bytes payload length, plus<br />

* payload, plus padding.<br />

*/<br />

buffer = OPENSSL_malloc(1 + 2 + payload + padding);<br />

bp = buffer;<br />

/* Enter response type, length, and copy payload */<br />

*bp++ = TLS1_HB_RESPONSE;<br />

s2n(payload, bp);<br />

memcpy(bp, pl, payload);<br />

}<br />

/* ... More code ... */<br />

}<br />

/* ... More code ... */<br />

This code processes a “heartbeat” packet from a client. As specified in RFC 6520, when the program<br />

receives a heartbeat packet, it must echo the packet’s data back to the client. In addition to<br />

the data, the packet contains a length field that conventionally indicates the number of bytes in the<br />

packet data, but there is nothing to prevent a malicious packet from lying about its data length.<br />

The p pointer, along with payload and p1, contains data from a packet. The code allocates a<br />

buffer sufficient to contain payload bytes, with some overhead, then copies payload bytes<br />

starting at p1 into this buffer and sends it to the client. Notably absent from this code are any<br />

checks that the payload integer variable extracted from the heartbeat packet corresponds to the<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 219<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

size of the packet data. Because the client can specify an arbitrary value of payload, an attacker<br />

can cause the server to read and return the contents of memory beyond the end of the packet data,<br />

which violates INT04-C. Enforce limits on integer values originating from tainted sources. The<br />

resulting call to memcpy() can then copy the contents of memory past the end of the packet data<br />

and the packet itself, potentially exposing sensitive data to the attacker. This call to memcpy() violates<br />

cba927fd45b4. A version of ARR38-C also appears in ISO/IEC TS 17961:2013, “Forming<br />

invalid pointers by library functions [libptr].” This rule would require a conforming analyzer to<br />

diagnose the Heartbleed vulnerability.<br />

7.5.3.6 Compliant Solution (Heartbleed)<br />

OpenSSL version 1.0.1g contains the following patch, which guarantees that payload is within a<br />

valid range. The range is limited by the size of the input record.<br />

int dtls1_process_heartbeat(SSL *s) {<br />

unsigned char *p = &s->s3->rrec.data[0], *pl;<br />

unsigned short hbtype;<br />

unsigned int payload;<br />

unsigned int padding = 16; /* Use minimum padding */<br />

/* ... More code ... */<br />

/* Read type and payload length first */<br />

if (1 + 2 + 16 > s->s3->rrec.length)<br />

return 0; /* Silently discard */<br />

hbtype = *p++;<br />

n2s(p, payload);<br />

if (1 + 2 + payload + 16 > s->s3->rrec.length)<br />

return 0; /* Silently discard per RFC 6520 */<br />

pl = p;<br />

/* ... More code ... */<br />

if (hbtype == TLS1_HB_REQUEST) {<br />

unsigned char *buffer, *bp;<br />

int r;<br />

/*<br />

* Allocate memory for the response; size is 1 byte<br />

* message type, plus 2 bytes payload length, plus<br />

* payload, plus padding.<br />

*/<br />

buffer = OPENSSL_malloc(1 + 2 + payload + padding);<br />

bp = buffer;<br />

/* Enter response type, length, and copy payload */<br />

*bp++ = TLS1_HB_RESPONSE;<br />

s2n(payload, bp);<br />

memcpy(bp, pl, payload);<br />

/* ... More code ... */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 220<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR38-C. Guarantee that library functions do not form invalid pointers<br />

}<br />

}<br />

/* ... More code ... */<br />

7.5.4 Risk Assessment<br />

Depending on the library function called, an attacker may be able to use a heap or stack overflow<br />

vulnerability to run arbitrary code.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR38-C High Likely Medium P18 L1<br />

7.5.5 Related Guidelines<br />

C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

ISO/IEC TR 24772:2013<br />

MITRE CWE<br />

API00-C. Functions should validate their parameters<br />

ARR01-C. Do not apply the sizeof operator to<br />

a pointer when taking the size of an array<br />

INT30-C. Ensure that unsigned integer operations<br />

do not wrap<br />

Forming invalid pointers by library functions<br />

[libptr]<br />

Buffer Boundary Violation (Buffer Overflow)<br />

[HCB]<br />

Unchecked Array Copying [XYW]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-121, Stack-based Buffer Overflow<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-805, Buffer Access with Incorrect<br />

Length Value<br />

7.5.6 Bibliography<br />

[Cassidy 2014]<br />

[IETF: RFC 6520]<br />

[ISO/IEC TS 17961:2013]<br />

[VU#720951]<br />

Existential Type Crisis : Diagnosis of the<br />

OpenSSL Heartbleed Bug<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 221<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR39-C. Do not add or subtract a scaled integer to a pointer<br />

7.6 ARR39-C. Do not add or subtract a scaled integer to a pointer<br />

Pointer arithmetic is appropriate only when the pointer argument refers to an array, including an<br />

array of bytes. (See ARR37-C. Do not add or subtract an integer to a pointer to a non-array object.)<br />

When performing pointer arithmetic, the size of the value to add to or subtract from a<br />

pointer is automatically scaled to the size of the type of the referenced array object. Adding or<br />

subtracting a scaled integer value to or from a pointer is invalid because it may yield a pointer that<br />

does not point to an element within or one past the end of the array. (See ARR30-C. Do not form<br />

or use out-of-bounds pointers or array subscripts.)<br />

Adding a pointer to an array of a type other than character to the result of the sizeof operator or<br />

offsetof macro, which returns a size and an offset, respectively, violates this rule. However,<br />

adding an array pointer to the number of array elements, for example, by using the<br />

arr[sizeof(arr)/sizeof(arr[0])] idiom, is allowed provided that arr refers to an array<br />

and not a pointer.<br />

7.6.1 Noncompliant Code Example<br />

In this noncompliant code example, sizeof(buf) is added to the array buf. This example is<br />

noncompliant because sizeof(buf) is scaled by int and then scaled again when added to buf.<br />

enum { INTBUFSIZE = 80 };<br />

extern int getdata(void);<br />

int buf[INTBUFSIZE];<br />

void func(void) {<br />

int *buf_ptr = buf;<br />

}<br />

while (buf_ptr < (buf + sizeof(buf))) {<br />

*buf_ptr++ = getdata();<br />

}<br />

7.6.2 Compliant Solution<br />

This compliant solution uses an unscaled integer to obtain a pointer to the end of the array:<br />

enum { INTBUFSIZE = 80 };<br />

extern int getdata(void);<br />

int buf[INTBUFSIZE];<br />

void func(void) {<br />

int *buf_ptr = buf;<br />

while (buf_ptr < (buf + INTBUFSIZE)) {<br />

*buf_ptr++ = getdata();<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 222<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR39-C. Do not add or subtract a scaled integer to a pointer<br />

}<br />

}<br />

7.6.3 Noncompliant Code Example<br />

In this noncompliant code example, skip is added to the pointer s. However, skip represents the<br />

byte offset of ull_b in struct big. When added to s, skip is scaled by the size of struct<br />

big.<br />

#include <br />

#include <br />

#include <br />

struct big {<br />

unsigned long long ull_a;<br />

unsigned long long ull_b;<br />

unsigned long long ull_c;<br />

int si_e;<br />

int si_f;<br />

};<br />

void func(void) {<br />

size_t skip = offsetof(struct big, ull_b);<br />

struct big *s = (struct big *)malloc(sizeof(struct big));<br />

if (s == NULL) {<br />

/* Handle malloc() error */<br />

}<br />

}<br />

memset(s + skip, 0, sizeof(struct big) - skip);<br />

/* ... */<br />

free(s);<br />

s = NULL;<br />

7.6.4 Compliant Solution<br />

This compliant solution uses an unsigned char * to calculate the offset instead of using a<br />

struct big *, which would result in scaled arithmetic:<br />

#include <br />

#include <br />

#include <br />

struct big {<br />

unsigned long long ull_a;<br />

unsigned long long ull_b;<br />

unsigned long long ull_c;<br />

int si_d;<br />

int si_e;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 223<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR39-C. Do not add or subtract a scaled integer to a pointer<br />

};<br />

void func(void) {<br />

size_t skip = offsetof(struct big, ull_b);<br />

unsigned char *ptr = (unsigned char *)malloc(<br />

sizeof(struct big)<br />

);<br />

if (ptr == NULL) {<br />

/* Handle malloc() error */<br />

}<br />

}<br />

memset(ptr + skip, 0, sizeof(struct big) - skip);<br />

/* ... */<br />

free(ptr);<br />

ptr = NULL;<br />

7.6.5 Noncompliant Code Example<br />

In this noncompliant code example, wcslen(error_msg) * sizeof(wchar_t) bytes are<br />

scaled by the size of wchar_t when added to error_msg:<br />

#include <br />

#include <br />

enum { WCHAR_BUF = 128 };<br />

void func(void) {<br />

wchar_t error_msg[WCHAR_BUF];<br />

}<br />

wcscpy(error_msg, L"Error: ");<br />

fgetws(error_msg + wcslen(error_msg) * sizeof(wchar_t),<br />

WCHAR_BUF - 7, stdin);<br />

/* ... */<br />

7.6.6 Compliant Solution<br />

This compliant solution does not scale the length of the string; wcslen() returns the number of<br />

characters and the addition to error_msg is scaled:<br />

#include <br />

#include <br />

enum { WCHAR_BUF = 128 };<br />

const wchar_t ERROR_PREFIX[7] = L"Error: ";<br />

void func(void) {<br />

const size_t prefix_len = wcslen(ERROR_PREFIX);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 224<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Array (ARR) - ARR39-C. Do not add or subtract a scaled integer to a pointer<br />

wchar_t error_msg[WCHAR_BUF];<br />

}<br />

wcscpy(error_msg, ERROR_PREFIX);<br />

fgetws(error_msg + prefix_len,<br />

WCHAR_BUF - prefix_len, stdin);<br />

/* ... */<br />

7.6.7 Risk Assessment<br />

Failure to understand and properly use pointer arithmetic can allow an attacker to execute arbitrary<br />

code.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ARR39-C High Probable High P6 L2<br />

7.6.8 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

MISRA C:2012<br />

MITRE CWE<br />

ARR30-C. Do not form or use out-of-bounds<br />

pointers or array subscripts<br />

ARR37-C. Do not add or subtract an integer to<br />

a pointer to a non-array object<br />

Pointer Casting and Pointer Type Changes<br />

[HFC]<br />

Pointer Arithmetic [RVG]<br />

Rule 18.1 (required)<br />

Rule 18.2 (required)<br />

Rule 18.3 (required)<br />

Rule 18.4 (advisory)<br />

CWE 468, Incorrect Pointer Scaling<br />

7.6.9 Bibliography<br />

[Dowd 2006]<br />

[Murenin 07]<br />

Chapter 6, “C Language Issues”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 225<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR30-C. Do not attempt to modify string literals<br />

8 Characters and Strings (STR)<br />

8.1 STR30-C. Do not attempt to modify string literals<br />

According to the C <strong>Standard</strong>, 6.4.5, paragraph 3 [ISO/IEC 9899:2011]:<br />

A character string literal is a sequence of zero or more multibyte characters enclosed in<br />

double-quotes, as in “xyz.” A UTF−8 string literal is the same, except prefixed by u8. A<br />

wide string literal is the same, except prefixed by the letter L, u, or U.<br />

At compile time, string literals are used to create an array of static storage duration of sufficient<br />

length to contain the character sequence and a terminating null character. String literals are usually<br />

referred to by a pointer to (or array of) characters. Ideally, they should be assigned only to<br />

pointers to (or arrays of) const char or const wchar_t. It is unspecified whether these arrays<br />

of string literals are distinct from each other. The behavior is undefined if a program attempts to<br />

modify any portion of a string literal. Modifying a string literal frequently results in an access violation<br />

because string literals are typically stored in read-only memory. (See undefined behavior<br />

33.)<br />

Avoid assigning a string literal to a pointer to non-const or casting a string literal to a pointer to<br />

non-const. For the purposes of this rule, a pointer to (or array of) const characters must be<br />

treated as a string literal. Similarly, the returned value of the following library functions must be<br />

treated as a string literal if the first argument is a string literal:<br />

• strpbrk(), strchr(), strrchr(), strstr()<br />

• wcspbrk(), wcschr(), wcsrchr(), wcsstr()<br />

• memchr(), wmemchr()<br />

This rule is a specific instance of EXP40-C. Do not modify constant objects.<br />

8.1.1 Noncompliant Code Example<br />

In this noncompliant code example, the char pointer p is initialized to the address of a string literal.<br />

Attempting to modify the string literal is undefined behavior:<br />

char *p = "string literal";<br />

p[0] = 'S';<br />

8.1.2 Compliant Solution<br />

As an array initializer, a string literal specifies the initial values of characters in an array as well as<br />

the size of the array. (See STR11-C. Do not specify the bound of a character array initialized with<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 226<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR30-C. Do not attempt to modify string literals<br />

a string literal.) This code creates a copy of the string literal in the space allocated to the character<br />

array a. The string stored in a can be modified safely.<br />

char a[] = "string literal";<br />

a[0] = 'S';<br />

8.1.3 Noncompliant Code Example (POSIX)<br />

In this noncompliant code example, a string literal is passed to the (pointer to non-const) parameter<br />

of the POSIX function mkstemp(), which then modifies the characters of the string literal:<br />

#include <br />

void func(void) {<br />

mkstemp("/tmp/edXXXXXX");<br />

}<br />

The behavior of mkstemp() is described in more detail in FIO21-C. Do not create temporary<br />

files in shared directories.<br />

8.1.4 Compliant Solution (POSIX)<br />

This compliant solution uses a named array instead of passing a string literal:<br />

#include <br />

void func(void) {<br />

static char fname[] = "/tmp/edXXXXXX";<br />

mkstemp(fname);<br />

}<br />

8.1.5 Noncompliant Code Example (Result of strrchr())<br />

In this noncompliant example, the char * result of the strrchr() function is used to modify<br />

the object pointed to by pathname. Because the argument to strrchr() points to a string literal,<br />

the effects of the modification are undefined.<br />

#include <br />

#include <br />

const char *get_dirname(const char *pathname) {<br />

char *slash;<br />

slash = strrchr(pathname, '/');<br />

if (slash) {<br />

*slash = '\0'; /* Undefined behavior */<br />

}<br />

return pathname;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 227<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR30-C. Do not attempt to modify string literals<br />

}<br />

int main(void) {<br />

puts(get_dirname(__FILE__));<br />

return 0;<br />

}<br />

8.1.6 Compliant Solution (Result of strrchr())<br />

This compliant solution avoids modifying a const object, even if it is possible to obtain a nonconst<br />

pointer to such an object by calling a standard C library function, such as strrchr(). To<br />

reduce the risk to callers of get_dirname(), a buffer and length for the directory name are<br />

passed into the function. It is insufficient to change pathname to require a char * instead of a<br />

const char * because conforming compilers are not required to diagnose passing a string literal<br />

to a function accepting a char *.<br />

#include <br />

#include <br />

#include <br />

char *get_dirname(const char *pathname, char *dirname, size_t size)<br />

{<br />

const char *slash;<br />

slash = strrchr(pathname, '/');<br />

if (slash) {<br />

ptrdiff_t slash_idx = slash - pathname;<br />

if ((size_t)slash_idx < size) {<br />

memcpy(dirname, pathname, slash_idx);<br />

dirname[slash_idx] = '\0';<br />

return dirname;<br />

}<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

char dirname[260];<br />

if (get_dirname(__FILE__, dirname, sizeof(dirname))) {<br />

puts(dirname);<br />

}<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 228<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR30-C. Do not attempt to modify string literals<br />

8.1.7 Risk Assessment<br />

Modifying string literals can lead to abnormal program termination and possibly denial-of-service<br />

attacks.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR30-C Low Likely Low P9 L2<br />

8.1.8 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

EXP05-C. Do not cast away a const qualification<br />

STR11-C. Do not specify the bound of a character<br />

array initialized with a string literal<br />

Modifying string literals [strmod]<br />

8.1.9 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.4.5, “String Literals”<br />

[Plum 1991]<br />

Topic 1.26, “Strings—String Literals”<br />

[Summit 1995] comp.lang.c FAQ List, Question 1.32<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 229<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2 STR31-C. Guarantee that storage for strings has sufficient space<br />

for character data and the null terminator<br />

Copying data to a buffer that is not large enough to hold that data results in a buffer overflow.<br />

Buffer overflows occur frequently when manipulating strings [Seacord 2013b]. To prevent such<br />

errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient<br />

size to hold the character data to be copied and the null-termination character. (See STR03-<br />

C. Do not inadvertently truncate a string.)<br />

When strings live on the heap, this rule is a specific instance of MEM35-C. Allocate sufficient<br />

memory for an object. Because strings are represented as arrays of characters, this rule is related<br />

to both ARR30-C. Do not form or use out-of-bounds pointers or array subscripts and ARR38-C.<br />

Guarantee that library functions do not form invalid pointers.<br />

8.2.1 Noncompliant Code Example (Off-by-One Error)<br />

This noncompliant code example demonstrates an off-by-one error [Dowd 2006]. The loop copies<br />

data from src to dest. However, because the loop does not account for the null-termination character,<br />

it may be incorrectly written 1 byte past the end of dest.<br />

#include <br />

void copy(size_t n, char src[n], char dest[n]) {<br />

size_t i;<br />

}<br />

for (i = 0; src[i] && (i < n); ++i) {<br />

dest[i] = src[i];<br />

}<br />

dest[i] = '\0';<br />

8.2.2 Compliant Solution (Off-by-One Error)<br />

In this compliant solution, the loop termination condition is modified to account for the null-termination<br />

character that is appended to dest:<br />

#include <br />

void copy(size_t n, char src[n], char dest[n]) {<br />

size_t i;<br />

}<br />

for (i = 0; src[i] && (i < n - 1); ++i) {<br />

dest[i] = src[i];<br />

}<br />

dest[i] = '\0';<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 230<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2.3 Noncompliant Code Example (gets())<br />

The gets() function, which was deprecated in the C99 Technical Corrigendum 3 and removed<br />

from C11, is inherently unsafe and should never be used because it provides no way to control<br />

how much data is read into a buffer from stdin. This noncompliant code example assumes that<br />

gets() will not read more than BUFFER_SIZE - 1 characters from stdin. This is an invalid<br />

assumption, and the resulting operation can result in a buffer overflow.<br />

The gets() function reads characters from the stdin into a destination array until end-of-file is<br />

encountered or a newline character is read. Any newline character is discarded, and a null character<br />

is written immediately after the last character read into the array.<br />

#include <br />

#define BUFFER_SIZE 1024<br />

void func(void) {<br />

char buf[BUFFER_SIZE];<br />

if (gets(buf) == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

See also MSC24-C. Do not use deprecated or obsolescent functions.<br />

8.2.4 Compliant Solution (fgets())<br />

The fgets() function reads, at most, one less than the specified number of characters from a<br />

stream into an array. This solution is compliant because the number of characters copied from<br />

stdin to buf cannot exceed the allocated memory:<br />

#include <br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

void func(void) {<br />

char buf[BUFFERSIZE];<br />

int ch;<br />

if (fgets(buf, sizeof(buf), stdin)) {<br />

/* fgets() succeeded; scan for newline character */<br />

char *p = strchr(buf, '\n');<br />

if (p) {<br />

*p = '\0';<br />

} else {<br />

/* Newline not found; flush stdin to end of line */<br />

while ((ch = getchar()) != '\n' && ch != EOF)<br />

;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 231<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

}<br />

if (ch == EOF && !feof(stdin) && !ferror(stdin)) {<br />

/* Character resembles EOF; handle error */<br />

}<br />

}<br />

} else {<br />

/* fgets() failed; handle error */<br />

}<br />

The fgets() function is not a strict replacement for the gets() function because fgets() retains<br />

the newline character (if read) and may also return a partial line. It is possible to use<br />

fgets() to safely process input lines too long to store in the destination array, but this is not recommended<br />

for performance reasons. Consider using one of the following compliant solutions<br />

when replacing gets().<br />

8.2.5 Compliant Solution (gets_s())<br />

The gets_s() function reads, at most, one less than the number of characters specified from the<br />

stream pointed to by stdin into an array.<br />

The C <strong>Standard</strong>, Annex K [ISO/IEC 9899:2011], states<br />

No additional characters are read after a new-line character (which is discarded) or after<br />

end-of-file. The discarded new-line character does not count towards number of characters<br />

read. A null character is written immediately after the last character read into the array.<br />

If end-of-file is encountered and no characters have been read into the destination array, or if a<br />

read error occurs during the operation, then the first character in the destination array is set to the<br />

null character and the other elements of the array take unspecified values:<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

void func(void) {<br />

char buf[BUFFERSIZE];<br />

}<br />

if (gets_s(buf, sizeof(buf)) == NULL) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 232<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2.6 Compliant Solution (getline(), POSIX)<br />

The getline() function is similar to the fgets() function but can dynamically allocate<br />

memory for the input buffer. If passed a null pointer, getline() dynamically allocates a buffer<br />

of sufficient size to hold the input. If passed a pointer to dynamically allocated storage that is too<br />

small to hold the contents of the string, the getline() function resizes the buffer, using realloc(),<br />

rather than truncating the input. If successful, the getline() function returns the number<br />

of characters read, which can be used to determine if the input has any null characters before the<br />

newline. The getline() function works only with dynamically allocated buffers. Allocated<br />

memory must be explicitly deallocated by the caller to avoid memory leaks. (See MEM31-C. Free<br />

dynamically allocated memory when no longer needed.)<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

int ch;<br />

size_t buffer_size = 32;<br />

char *buffer = malloc(buffer_size);<br />

if (!buffer) {<br />

/* Handle error */<br />

return;<br />

}<br />

}<br />

if ((ssize_t size = getline(&buffer, &buffer_size, stdin))<br />

== -1) {<br />

/* Handle error */<br />

} else {<br />

char *p = strchr(buffer, '\n');<br />

if (p) {<br />

*p = '\0';<br />

} else {<br />

/* Newline not found; flush stdin to end of line */<br />

while ((ch = getchar()) != '\n' && ch != EOF)<br />

;<br />

if (ch == EOF && !feof(stdin) && !ferror(stdin)) {<br />

/* Character resembles EOF; handle error */<br />

}<br />

}<br />

}<br />

free (buffer);<br />

The getline() function uses an in-band error indicator, in violation of ERR02-C. Avoid in-band<br />

error indicators.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 233<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2.7 Noncompliant Code Example (getchar())<br />

Reading one character at a time provides more flexibility in controlling behavior, though with additional<br />

performance overhead. This noncompliant code example uses the getchar() function to<br />

read one character at a time from stdin instead of reading the entire line at once. The stdin<br />

stream is read until end-of-file is encountered or a newline character is read. Any newline character<br />

is discarded, and a null character is written immediately after the last character read into the<br />

array. Similar to the noncompliant code example that invokes gets(), there are no guarantees<br />

that this code will not result in a buffer overflow.<br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

void func(void) {<br />

char buf[BUFFERSIZE];<br />

char *p;<br />

int ch;<br />

p = buf;<br />

while ((ch = getchar()) != '\n' && ch != EOF) {<br />

*p++ = (char)ch;<br />

}<br />

*p++ = 0;<br />

if (ch == EOF) {<br />

/* Handle EOF or error */<br />

}<br />

}<br />

After the loop ends, if ch == EOF, the loop has read through to the end of the stream without encountering<br />

a newline character, or a read error occurred before the loop encountered a newline<br />

character. To conform to FIO34-C. Distinguish between characters read from a file and EOF or<br />

WEOF, the error-handling code must verify that an end-of-file or error has occurred by calling<br />

feof() or ferror().<br />

8.2.8 Compliant Solution (getchar())<br />

In this compliant solution, characters are no longer copied to buf once index == BUFFERSIZE<br />

- 1, leaving room to null-terminate the string. The loop continues to read characters until the end<br />

of the line, the end of the file, or an error is encountered. When chars_read > index, the input<br />

string has been truncated.<br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

void func(void) {<br />

char buf[BUFFERSIZE];<br />

int ch;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 234<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

size_t index = 0;<br />

size_t chars_read = 0;<br />

}<br />

while ((ch = getchar()) != '\n' && ch != EOF) {<br />

if (index < sizeof(buf) - 1) {<br />

buf[index++] = (char)ch;<br />

}<br />

chars_read++;<br />

}<br />

buf[index] = '\0'; /* Terminate string */<br />

if (ch == EOF) {<br />

/* Handle EOF or error */<br />

}<br />

if (chars_read > index) {<br />

/* Handle truncation */<br />

}<br />

8.2.9 Noncompliant Code Example (fscanf())<br />

In this noncompliant example, the call to fscanf() can result in a write outside the character array<br />

buf:<br />

#include <br />

enum { BUF_LENGTH = 1024 };<br />

void get_data(void) {<br />

char buf[BUF_LENGTH];<br />

if (1 != fscanf(stdin, "%s", buf)) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Rest of function */<br />

8.2.10 Compliant Solution (fscanf())<br />

In this compliant solution, the call to fscanf() is constrained not to overflow buf:<br />

#include <br />

enum { BUF_LENGTH = 1024 };<br />

void get_data(void) {<br />

char buf[BUF_LENGTH];<br />

if (1 != fscanf(stdin, "%1023s", buf)) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 235<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

}<br />

/* Rest of function */<br />

8.2.11 Noncompliant Code Example (argv)<br />

In a hosted environment, arguments read from the command line are stored in process memory.<br />

The function main(), called at program startup, is typically declared as follows when the program<br />

accepts command-line arguments:<br />

int main(int argc, char *argv[]) { /* ... */ }<br />

Command-line arguments are passed to main() as pointers to strings in the array members<br />

argv[0] through argv[argc - 1]. If the value of argc is greater than 0, the string pointed to<br />

by argv[0] is, by convention, the program name. If the value of argc is greater than 1, the<br />

strings referenced by argv[1] through argv[argc - 1] are the program arguments.<br />

Vulnerabilities can occur when inadequate space is allocated to copy a command-line argument or<br />

other program input. In this noncompliant code example, an attacker can manipulate the contents<br />

of argv[0] to cause a buffer overflow:<br />

#include <br />

int main(int argc, char *argv[]) {<br />

/* Ensure argv[0] is not null */<br />

const char *const name = (argc && argv[0]) ? argv[0] : "";<br />

char prog_name[128];<br />

strcpy(prog_name, name);<br />

}<br />

return 0;<br />

8.2.12 Compliant Solution (argv)<br />

The strlen() function can be used to determine the length of the strings referenced by argv[0]<br />

through argv[argc - 1] so that adequate memory can be dynamically allocated.<br />

#include <br />

#include <br />

int main(int argc, char *argv[]) {<br />

/* Ensure argv[0] is not null */<br />

const char *const name = (argc && argv[0]) ? argv[0] : "";<br />

char *prog_name = (char *)malloc(strlen(name) + 1);<br />

if (prog_name != NULL) {<br />

strcpy(prog_name, name);<br />

} else {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 236<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

}<br />

/* Handle error */<br />

}<br />

free(prog_name);<br />

return 0;<br />

Remember to add a byte to the destination string size to accommodate the null-termination character.<br />

8.2.13 Compliant Solution (argv)<br />

The strcpy_s() function provides additional safeguards, including accepting the size of the destination<br />

buffer as an additional argument. (See STR07-C. Use the bounds-checking interfaces for<br />

string manipulation.)<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

#include <br />

int main(int argc, char *argv[]) {<br />

/* Ensure argv[0] is not null */<br />

const char *const name = (argc && argv[0]) ? argv[0] : "";<br />

char *prog_name;<br />

size_t prog_size;<br />

prog_size = strlen(name) + 1;<br />

prog_name = (char *)malloc(prog_size);<br />

}<br />

if (prog_name != NULL) {<br />

if (strcpy_s(prog_name, prog_size, name)) {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

free(prog_name);<br />

return 0;<br />

The strcpy_s() function can be used to copy data to or from dynamically allocated memory or<br />

a statically allocated array. If insufficient space is available, strcpy_s() returns an error.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 237<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2.14 Compliant Solution (argv)<br />

If an argument will not be modified or concatenated, there is no reason to make a copy of the<br />

string. Not copying a string is the best way to prevent a buffer overflow and is also the most efficient<br />

solution. Care must be taken to avoid assuming that argv[0] is non-null.<br />

int main(int argc, char *argv[]) {<br />

/* Ensure argv[0] is not null */<br />

const char * const prog_name = (argc && argv[0]) ? argv[0] : "";<br />

/* ... */<br />

return 0;<br />

}<br />

8.2.15 Noncompliant Code Example (getenv())<br />

According to the C <strong>Standard</strong>, 7.22.4.6 [ISO/IEC 9899:2011]:<br />

The getenv function searches an environment list, provided by the host environment,<br />

for a string that matches the string pointed to by name. The set of environment names<br />

and the method for altering the environment list are implementation defined.<br />

Environment variables can be arbitrarily large, and copying them into fixed-length arrays without<br />

first determining the size and allocating adequate storage can result in a buffer overflow.<br />

#include <br />

#include <br />

void func(void) {<br />

char buff[256];<br />

char *editor = getenv("EDITOR");<br />

if (editor == NULL) {<br />

/* EDITOR environment variable not set */<br />

} else {<br />

strcpy(buff, editor);<br />

}<br />

}<br />

8.2.16 Compliant Solution (getenv())<br />

Environmental variables are loaded into process memory when the program is loaded. As a result,<br />

the length of these strings can be determined by calling the strlen() function, and the resulting<br />

length can be used to allocate adequate dynamic memory:<br />

#include <br />

#include <br />

void func(void) {<br />

char *buff;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 238<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

}<br />

char *editor = getenv("EDITOR");<br />

if (editor == NULL) {<br />

/* EDITOR environment variable not set */<br />

} else {<br />

size_t len = strlen(editor) + 1;<br />

buff = (char *)malloc(len);<br />

if (buff == NULL) {<br />

/* Handle error */<br />

}<br />

memcpy(buff, editor, len);<br />

free(buff);<br />

}<br />

8.2.17 Noncompliant Code Example (sprintf())<br />

In this noncompliant code example, name refers to an external string; it could have originated<br />

from user input, the file system, or the network. The program constructs a file name from the<br />

string in preparation for opening the file.<br />

#include <br />

void func(const char *name) {<br />

char filename[128];<br />

sprintf(filename, "%s.txt", name);<br />

}<br />

Because the sprintf() function makes no guarantees regarding the length of the generated<br />

string, a sufficiently long string in name could generate a buffer overflow.<br />

8.2.18 Compliant Solution (sprintf())<br />

The buffer overflow in the preceding noncompliant example can be prevented by adding a precision<br />

to the %s conversion specification. If the precision is specified, no more than that many bytes<br />

are written. The precision 123 in this compliant solution ensures that filename can contain the<br />

first 123 characters of name, the .txt extension, and the null terminator.<br />

#include <br />

void func(const char *name) {<br />

char filename[128];<br />

sprintf(filename, "%.123s.txt", name);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 239<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

8.2.19 Compliant Solution (snprintf())<br />

A more general solution is to use the snprintf() function:<br />

#include <br />

void func(const char *name) {<br />

char filename[128];<br />

snprintf(filename, sizeof(filename), "%s.txt", name);<br />

}<br />

8.2.20 Risk Assessment<br />

Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers<br />

can exploit this condition to execute arbitrary code with the permissions of the vulnerable<br />

process.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR31-C High Likely Medium P18 L1<br />

8.2.20.1 Related Vulnerabilities<br />

CVE-2009-1252 results from a violation of this rule. The Network Time Protocol daemon<br />

(NTPd), before versions 4.2.4p7 and 4.2.5p74, contained calls to sprintf that allow an attacker<br />

to execute arbitrary code by overflowing a character array [xorl 2009].<br />

CVE-2009-0587 results from a violation of this rule. Before version 2.24.5, Evolution Data Server<br />

performed unchecked arithmetic operations on the length of a user-input string and used the value<br />

to allocate space for a new buffer. An attacker could thereby execute arbitrary code by inputting a<br />

long string, resulting in incorrect allocation and buffer overflow [xorl 2009].<br />

8.2.21 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

STR03-C. Do not inadvertently truncate a<br />

string<br />

STR07-C. Use the bounds-checking interfaces<br />

for remediation of existing string manipulation<br />

code<br />

MSC24-C. Do not use deprecated or obsolescent<br />

functions<br />

MEM00-C. Allocate and free memory in the<br />

same module, at the same level of abstraction<br />

FIO34-C. Distinguish between characters read<br />

from a file and EOF or WEOF<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 240<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR31-C. Guarantee that storage for strings has sufficient space for character data and the<br />

null terminator<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

String Termination [CJM]<br />

Buffer Boundary Violation (Buffer Overflow)<br />

[HCB]<br />

Unchecked Array Copying [XYW]<br />

Using a tainted value to write to an object using<br />

a formatted input or output function [taintformatio]<br />

Tainted strings are passed to a string copying<br />

function [taintstrcpy]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-120, Buffer Copy without Checking Size<br />

of Input (“Classic Buffer Overflow”)<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-193, Off-by-one Error<br />

8.2.22 Bibliography<br />

[Dowd 2006]<br />

[Drepper 2006]<br />

[ISO/IEC 9899:2011]<br />

[Lai 2006]<br />

[NIST 2006]<br />

[Seacord 2013b]<br />

[xorl 2009]<br />

Chapter 7, “Program Building Blocks” (“Loop<br />

Constructs,” pp. 327–336)<br />

Section 2.1.1, “Respecting Memory Bounds”<br />

K.3.5.4.1, “The gets_s Function”<br />

SAMATE Reference Dataset Test Case ID<br />

000-000-088<br />

Chapter 2, “Strings”<br />

FreeBSD-SA-09:11: NTPd Remote Stack<br />

Based Buffer Overflows<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 241<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR32-C. Do not pass a non-null-terminated character sequence to a library function that<br />

expects a string<br />

8.3 STR32-C. Do not pass a non-null-terminated character sequence to<br />

a library function that expects a string<br />

Many library functions accept a string or wide string argument with the constraint that the string<br />

they receive is properly null-terminated. Passing a character sequence or wide character sequence<br />

that is not null-terminated to such a function can result in accessing memory that is outside the<br />

bounds of the object. Do not pass a character sequence or wide character sequence that is not nullterminated<br />

to a library function that expects a string or wide string argument.<br />

8.3.1 Noncompliant Code Example<br />

This code example is noncompliant because the character sequence c_str will not be null-terminated<br />

when passed as an argument to printf(). (See STR11-C. Do not specify the bound of a<br />

character array initialized with a string literal on how to properly initialize character arrays.)<br />

#include <br />

void func(void) {<br />

char c_str[3] = "abc";<br />

printf("%s\n", c_str);<br />

}<br />

8.3.2 Compliant Solution<br />

This compliant solution does not specify the bound of the character array in the array declaration.<br />

If the array bound is omitted, the compiler allocates sufficient storage to store the entire string literal,<br />

including the terminating null character.<br />

#include <br />

void func(void) {<br />

char c_str[] = "abc";<br />

printf("%s\n", c_str);<br />

}<br />

8.3.3 Noncompliant Code Example<br />

This code example is noncompliant because the wide character sequence cur_msg will not be<br />

null-terminated when passed to wcslen(). This will occur if lessen_memory_usage() is invoked<br />

while cur_msg_size still has its initial value of 1024.<br />

#include <br />

#include <br />

wchar_t *cur_msg = NULL;<br />

size_t cur_msg_size = 1024;<br />

size_t cur_msg_len = 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 242<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR32-C. Do not pass a non-null-terminated character sequence to a library function that<br />

expects a string<br />

void lessen_memory_usage(void) {<br />

wchar_t *temp;<br />

size_t temp_size;<br />

/* ... */<br />

if (cur_msg != NULL) {<br />

temp_size = cur_msg_size / 2 + 1;<br />

temp = realloc(cur_msg, temp_size * sizeof(wchar_t));<br />

/* temp &and cur_msg may no longer be null-terminated */<br />

if (temp == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

}<br />

cur_msg = temp;<br />

cur_msg_size = temp_size;<br />

cur_msg_len = wcslen(cur_msg);<br />

8.3.4 Compliant Solution<br />

In this compliant solution, cur_msg will always be null-terminated when passed to wcslen():<br />

#include <br />

#include <br />

wchar_t *cur_msg = NULL;<br />

size_t cur_msg_size = 1024;<br />

size_t cur_msg_len = 0;<br />

void lessen_memory_usage(void) {<br />

wchar_t *temp;<br />

size_t temp_size;<br />

/* ... */<br />

if (cur_msg != NULL) {<br />

temp_size = cur_msg_size / 2 + 1;<br />

temp = realloc(cur_msg, temp_size * sizeof(wchar_t));<br />

/* temp and cur_msg may no longer be null-terminated */<br />

if (temp == NULL) {<br />

/* Handle error */<br />

}<br />

cur_msg = temp;<br />

/* Properly null-terminate cur_msg */<br />

cur_msg[temp_size - 1] = L'\0';<br />

cur_msg_size = temp_size;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 243<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR32-C. Do not pass a non-null-terminated character sequence to a library function that<br />

expects a string<br />

}<br />

}<br />

cur_msg_len = wcslen(cur_msg);<br />

8.3.5 Noncompliant Code Example (strncpy())<br />

Although the strncpy() function takes a string as input, it does not guarantee that the resulting<br />

value is still null-terminated. In the following noncompliant code example, if no null character is<br />

contained in the first n characters of the source array, the result will not be null-terminated.<br />

Passing a non-null-terminated character sequence to strlen() is undefined behavior.<br />

#include <br />

enum { STR_SIZE = 32 };<br />

size_t func(const char *source) {<br />

char c_str[STR_SIZE];<br />

size_t ret = 0;<br />

}<br />

if (source) {<br />

c_str[sizeof(c_str) - 1] = '\0';<br />

strncpy(c_str, source, sizeof(c_str));<br />

ret = strlen(c_str);<br />

} else {<br />

/* Handle null pointer */<br />

}<br />

return ret;<br />

8.3.6 Compliant Solution (Truncation)<br />

This compliant solution is correct if the programmer’s intent is to truncate the string:<br />

#include <br />

enum { STR_SIZE = 32 };<br />

size_t func(const char *source) {<br />

char c_str[STR_SIZE];<br />

size_t ret = 0;<br />

if (source) {<br />

strncpy(c_str, source, sizeof(c_str) - 1);<br />

c_str[sizeof(c_str) - 1] = '\0';<br />

ret = strlen(c_str);<br />

} else {<br />

/* Handle null pointer */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 244<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR32-C. Do not pass a non-null-terminated character sequence to a library function that<br />

expects a string<br />

}<br />

return ret;<br />

8.3.7 Compliant Solution (Truncation, strncpy_s())<br />

The C <strong>Standard</strong>, Annex K strncpy_s() function can also be used to copy with truncation. The<br />

strncpy_s() function copies up to n characters from the source array to a destination array. If<br />

no null character was copied from the source array, then the n th position in the destination array is<br />

set to a null character, guaranteeing that the resulting string is null-terminated.<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

enum { STR_SIZE = 32 };<br />

size_t func(const char *source) {<br />

char a[STR_SIZE];<br />

size_t ret = 0;<br />

}<br />

if (source) {<br />

errno_t err = strncpy_s(<br />

a, sizeof(a), source, strlen(source)<br />

);<br />

if (err != 0) {<br />

/* Handle error */<br />

} else {<br />

ret = strnlen_s(a, sizeof(a));<br />

}<br />

} else {<br />

/* Handle null pointer */<br />

}<br />

return ret;<br />

8.3.8 Compliant Solution (Copy without Truncation)<br />

If the programmer’s intent is to copy without truncation, this compliant solution copies the data<br />

and guarantees that the resulting array is null-terminated. If the string cannot be copied, it is handled<br />

as an error condition.<br />

#include <br />

enum { STR_SIZE = 32 };<br />

size_t func(const char *source) {<br />

char c_str[STR_SIZE];<br />

size_t ret = 0;<br />

if (source) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 245<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR32-C. Do not pass a non-null-terminated character sequence to a library function that<br />

expects a string<br />

}<br />

if (strlen(source) < sizeof(c_str)) {<br />

strcpy(c_str, source);<br />

ret = strlen(c_str);<br />

} else {<br />

/* Handle string-too-large */<br />

}<br />

} else {<br />

/* Handle null pointer */<br />

}<br />

return ret;<br />

8.3.9 Risk Assessment<br />

Failure to properly null-terminate a character sequence that is passed to a library function that expects<br />

a string can result in buffer overflows and the execution of arbitrary code with the permissions<br />

of the vulnerable process. Null-termination errors can also result in unintended information<br />

disclosure.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR32-C High Probable Medium P12 L1<br />

8.3.10 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

String Termination [CMJ]<br />

Passing a non-null-terminated character sequence<br />

to a library function that expects a<br />

string [strmod]<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-170, Improper Null Termination<br />

8.3.11 Bibliography<br />

[Seacord 2013]<br />

[Viega 2005]<br />

Chapter 2, “Strings”<br />

Section 5.2.14, “Miscalculated NULL Termination”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 246<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR34-C. Cast characters to unsigned char before converting to larger integer sizes<br />

8.4 STR34-C. Cast characters to unsigned char before converting to<br />

larger integer sizes<br />

Signed character data must be converted to unsigned char before being assigned or converted<br />

to a larger signed type. This rule applies to both signed char and (plain) char characters on<br />

implementations where char is defined to have the same range, representation, and behaviors as<br />

signed char.<br />

However, this rule is applicable only in cases where the character data may contain values that<br />

can be interpreted as negative numbers. For example, if the char type is represented by a two’s<br />

complement 8-bit value, any character value greater than +127 is interpreted as a negative value.<br />

This rule is a generalization of STR37-C. Arguments to character-handling functions must be representable<br />

as an unsigned char.<br />

8.4.1 Noncompliant Code Example<br />

This noncompliant code example is taken from a vulnerability in bash versions 1.14.6 and earlier<br />

that led to the release of <strong>CERT</strong> Advisory CA-1996-22. This vulnerability resulted from the sign<br />

extension of character data referenced by the c_str pointer in the yy_string_get() function<br />

in the parse.y module of the bash source code:<br />

static int yy_string_get(void) {<br />

register char *c_str;<br />

register int c;<br />

c_str = bash_input.location.string;<br />

c = EOF;<br />

}<br />

/* If the string doesn't exist or is empty, EOF found */<br />

if (c_str && *c_str) {<br />

c = *c_str++;<br />

bash_input.location.string = c_str;<br />

}<br />

return (c);<br />

The c_str variable is used to traverse the character string containing the command line to be<br />

parsed. As characters are retrieved from this pointer, they are stored in a variable of type int. For<br />

implementations in which the char type is defined to have the same range, representation, and<br />

behavior as signed char, this value is sign-extended when assigned to the int variable. For<br />

character code 255 decimal (−1 in two’s complement form), this sign extension results in the<br />

value −1 being assigned to the integer, which is indistinguishable from EOF.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 247<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR34-C. Cast characters to unsigned char before converting to larger integer sizes<br />

8.4.2 Noncompliant Code Example<br />

This problem can be repaired by explicitly declaring the c_str variable as unsigned char:<br />

static int yy_string_get(void) {<br />

register unsigned char *c_str;<br />

register int c;<br />

c_str = bash_input.location.string;<br />

c = EOF;<br />

}<br />

/* If the string doesn't exist or is empty, EOF found */<br />

if (c_str && *c_str) {<br />

c = *c_str++;<br />

bash_input.location.string = c_str;<br />

}<br />

return (c);<br />

This example, however, violates STR04-C. Use plain char for characters in the basic character set.<br />

8.4.3 Compliant Solution<br />

In this compliant solution, the result of the expression *c_str++ is cast to unsigned char before<br />

assignment to the int variable c:<br />

static int yy_string_get(void) {<br />

register char *c_str;<br />

register int c;<br />

c_str = bash_input.location.string;<br />

c = EOF;<br />

/* If the string doesn't exist or is empty, EOF found */<br />

if (c_str && *c_str) {<br />

/* Cast to unsigned type */<br />

c = (unsigned char)*c_str++;<br />

bash_input.location.string = c_str;<br />

}<br />

return (c);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 248<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR34-C. Cast characters to unsigned char before converting to larger integer sizes<br />

8.4.4 Noncompliant Code Example<br />

In this noncompliant code example, the cast of *s to unsigned int can result in a value in excess<br />

of UCHAR_MAX because of integer promotions, a violation of ARR30-C. Do not form or use<br />

out-of-bounds pointers or array subscripts:<br />

#include <br />

#include <br />

static const char table[UCHAR_MAX] = { 'a' /* ... */ };<br />

ptrdiff_t first_not_in_table(const char *c_str) {<br />

for (const char *s = c_str; *s; ++s) {<br />

if (table[(unsigned int)*s] != *s) {<br />

return s - c_str;<br />

}<br />

}<br />

return -1;<br />

}<br />

8.4.5 Compliant Solution<br />

This compliant solution casts the value of type char to unsigned char before the implicit promotion<br />

to a larger type:<br />

#include <br />

#include <br />

static const char table[UCHAR_MAX] = { 'a' /* ... */ };<br />

ptrdiff_t first_not_in_table(const char *c_str) {<br />

for (const char *s = c_str; *s; ++s) {<br />

if (table[(unsigned char)*s] != *s) {<br />

return s - c_str;<br />

}<br />

}<br />

return -1;<br />

}<br />

8.4.6 Risk Assessment<br />

Conversion of character data resulting in a value in excess of UCHAR_MAX is an often-missed error<br />

that can result in a disturbingly broad range of potentially severe vulnerabilities.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR34-C Medium Probable Medium P8 L2<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 249<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR34-C. Cast characters to unsigned char before converting to larger integer sizes<br />

8.4.6.1 Related Vulnerabilities<br />

CVE-2009-0887 results from a violation of this rule. In Linux PAM (up to version 1.0.3), the<br />

libpam implementation of strtok() casts a (potentially signed) character to an integer for use<br />

as an index to an array. An attacker can exploit this vulnerability by inputting a string with non-<br />

ASCII characters, causing the cast to result in a negative index and accessing memory outside of<br />

the array [xorl 2009].<br />

8.4.6.2 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

MISRA-C<br />

MITRE CWE<br />

STR37-C. Arguments to character-handling<br />

functions must be representable as an unsigned<br />

char<br />

STR04-C. Use plain char for characters in the<br />

basic character set<br />

ARR30-C. Do not form or use out-of-bounds<br />

pointers or array subscripts<br />

Conversion of signed characters to wider integer<br />

types before a check for EOF [signconv]<br />

Rule 10.1 through Rule 10.4 (required)<br />

CWE-704, Incorrect Type Conversion or Cast<br />

8.4.7 Bibliography<br />

[xorl 2009]<br />

CVE-2009-0887: Linux-PAM Signedness Issue<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 250<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR37-C. Arguments to character-handling functions must be representable as an unsigned<br />

char<br />

8.5 STR37-C. Arguments to character-handling functions must be<br />

representable as an unsigned char<br />

According to the C <strong>Standard</strong>, 7.4 [ISO/IEC 9899:2011],<br />

The header declares several functions useful for classifying and mapping<br />

characters. In all cases the argument is an int, the value of which shall be representable<br />

as an unsigned char or shall equal the value of the macro EOF. If the argument<br />

has any other value, the behavior is undefined.<br />

See also undefined behavior 113.<br />

This rule is applicable only to code that runs on platforms where the char data type is defined to<br />

have the same range, representation, and behavior as signed char.<br />

Following are the character classification functions that this rule addresses:<br />

isalnum() isalpha() isascii() XSI isblank()<br />

iscntrl() isdigit() isgraph() islower()<br />

isprint() ispunct() isspace() isupper()<br />

isxdigit() toascii() XSI toupper() tolower()<br />

XSI denotes an X/Open System Interfaces Extension to ISO/IEC 9945—POSIX. These functions<br />

are not defined by the C <strong>Standard</strong>.<br />

This rule is a specific instance of STR34-C. Cast characters to unsigned char before converting to<br />

larger integer sizes.<br />

8.5.1 Noncompliant Code Example<br />

On implementations where plain char is signed, this code example is noncompliant because the<br />

parameter to isspace(), *t, is defined as a const char *, and this value might not be representable<br />

as an unsigned char:<br />

#include <br />

#include <br />

size_t count_preceding_whitespace(const char *s) {<br />

const char *t = s;<br />

size_t length = strlen(s) + 1;<br />

while (isspace(*t) && (t - s < length)) {<br />

++t;<br />

}<br />

return t - s;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 251<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR37-C. Arguments to character-handling functions must be representable as an unsigned<br />

char<br />

The argument to isspace() must be EOF or representable as an unsigned char; otherwise, the<br />

result is undefined.<br />

8.5.2 Compliant Solution<br />

This compliant solution casts the character to unsigned char before passing it as an argument<br />

to the isspace() function:<br />

#include <br />

#include <br />

size_t count_preceding_whitespace(const char *s) {<br />

const char *t = s;<br />

size_t length = strlen(s) + 1;<br />

while (isspace((unsigned char)*t) && (t - s < length)) {<br />

++t;<br />

}<br />

return t - s;<br />

}<br />

8.5.3 Risk Assessment<br />

Passing values to character handling functions that cannot be represented as an unsigned char<br />

to character handling functions is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR37-C Low Unlikely Low P3 L3<br />

8.5.4 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

STR34-C. Cast characters to unsigned char before<br />

converting to larger integer sizes<br />

Passing arguments to character-handling functions<br />

that are not representable as unsigned<br />

char [chrsgnext]<br />

CWE-704, Incorrect Type Conversion or Cast<br />

CWE-686, Function Call with Incorrect Argument<br />

Type<br />

8.5.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Kettlewell 2002]<br />

7.4, “Character Handling ”<br />

Section 1.1, “ and Characters<br />

Types”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 252<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR38-C. Do not confuse narrow and wide character strings and functions<br />

8.6 STR38-C. Do not confuse narrow and wide character strings and<br />

functions<br />

Passing narrow string arguments to wide string functions or wide string arguments to narrow<br />

string functions can lead to unexpected and undefined behavior. Scaling problems are likely because<br />

of the difference in size between wide and narrow characters. (See ARR39-C. Do not add or<br />

subtract a scaled integer to a pointer.) Because wide strings are terminated by a null wide character<br />

and can contain null bytes, determining the length is also problematic.<br />

Because wchar_t and char are distinct types, many compilers will produce a warning diagnostic<br />

if an inappropriate function is used. (See MSC00-C. Compile cleanly at high warning levels.)<br />

8.6.1 Noncompliant Code Example (Wide Strings with Narrow String Functions)<br />

This noncompliant code example incorrectly uses the strncpy() function in an attempt to copy<br />

up to 10 wide characters. However, because wide characters can contain null bytes, the copy operation<br />

may end earlier than anticipated, resulting in the truncation of the wide string.<br />

#include <br />

#include <br />

void func(void) {<br />

wchar_t wide_str1[] = L"0123456789";<br />

wchar_t wide_str2[] = L"0000000000";<br />

}<br />

strncpy(wide_str2, wide_str1, 10);<br />

8.6.2 Noncompliant Code Example (Narrow Strings with Wide String Functions)<br />

This noncompliant code example incorrectly invokes the wcsncpy() function to copy up to 10<br />

wide characters from narrow_str1 to narrow_str2. Because narrow_str2 is a narrow<br />

string, it has insufficient memory to store the result of the copy and the copy will result in a buffer<br />

overflow.<br />

#include <br />

void func(void) {<br />

char narrow_str1[] = "01234567890123456789";<br />

char narrow_str2[] = "0000000000";<br />

}<br />

wcsncpy(narrow_str2, narrow_str1, 10);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 253<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR38-C. Do not confuse narrow and wide character strings and functions<br />

8.6.3 Compliant Solution<br />

This compliant solution uses the proper-width functions. Using wcsncpy() for wide character<br />

strings and strncpy() for narrow character strings ensures that data is not truncated and buffer<br />

overflow does not occur.<br />

#include <br />

#include <br />

void func(void) {<br />

wchar_t wide_str1[] = L"0123456789";<br />

wchar_t wide_str2[] = L"0000000000";<br />

/* Use of proper-width function */<br />

wcsncpy(wide_str2, wide_str1, 10);<br />

}<br />

char narrow_str1[] = "0123456789";<br />

char narrow_str2[] = "0000000000";<br />

/* Use of proper-width function */<br />

strncpy(narrow_str2, narrow_str1, 10);<br />

8.6.4 Noncompliant Code Example (strlen())<br />

In this noncompliant code example, the strlen() function is used to determine the size of a<br />

wide character string:<br />

#include <br />

#include <br />

void func(void) {<br />

wchar_t wide_str1[] = L"0123456789";<br />

wchar_t *wide_str2 = (wchar_t*)malloc(strlen(wide_str1) + 1);<br />

if (wide_str2 == NULL) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

free(wide_str2);<br />

wide_str2 = NULL;<br />

}<br />

The strlen() function determines the number of characters that precede the terminating null<br />

character. However, wide characters can contain null bytes, particularly when expressing characters<br />

from the ASCII character set, as in this example. As a result, the strlen() function will return<br />

the number of bytes preceding the first null byte in the wide string.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 254<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Characters and Strings (STR) - STR38-C. Do not confuse narrow and wide character strings and functions<br />

8.6.5 Compliant Solution<br />

This compliant solution correctly calculates the number of bytes required to contain a copy of the<br />

wide string, including the terminating null wide character:<br />

#include <br />

#include <br />

void func(void) {<br />

wchar_t wide_str1[] = L"0123456789";<br />

wchar_t *wide_str2 = (wchar_t *)malloc(<br />

(wcslen(wide_str1) + 1) * sizeof(wchar_t));<br />

if (wide_str2 == NULL) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

}<br />

free(wide_str2);<br />

wide_str2 = NULL;<br />

8.6.6 Risk Assessment<br />

Confusing narrow and wide character strings can result in buffer overflows, data truncation, and<br />

other defects.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

STR38-C High Likely Low P27 L1<br />

8.6.7 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.24.2.4, “The strncpy Function”<br />

7.29.4.2.2, “The wcsncpy Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 255<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

9 Memory Management (MEM)<br />

9.1 MEM30-C. Do not access freed memory<br />

Evaluating a pointer—including dereferencing the pointer, using it as an operand of an arithmetic<br />

operation, type casting it, and using it as the right-hand side of an assignment—into memory that<br />

has been deallocated by a memory management function is undefined behavior. Pointers to<br />

memory that has been deallocated are called dangling pointers. Accessing a dangling pointer can<br />

result in exploitable vulnerabilities.<br />

According to the C <strong>Standard</strong>, using the value of a pointer that refers to space deallocated by a call<br />

to the free() or realloc() function is undefined behavior. (See undefined behavior 177.)<br />

Reading a pointer to deallocated memory is undefined behavior because the pointer value is indeterminate<br />

and might be a trap representation. Fetching a trap representation might perform a hardware<br />

trap (but is not required to).<br />

It is at the memory manager’s discretion when to reallocate or recycle the freed memory. When<br />

memory is freed, all pointers into it become invalid, and its contents might either be returned to<br />

the operating system, making the freed space inaccessible, or remain intact and accessible. As a<br />

result, the data at the freed location can appear to be valid but change unexpectedly. Consequently,<br />

memory must not be written to or read from once it is freed.<br />

9.1.1 Noncompliant Code Example<br />

This example from Brian Kernighan and Dennis Ritchie [Kernighan 1988] shows both the incorrect<br />

and correct techniques for freeing the memory associated with a linked list. In their (intentionally)<br />

incorrect example, p is freed before p->next is executed, so that p->next reads<br />

memory that has already been freed.<br />

#include <br />

struct node {<br />

int value;<br />

struct node *next;<br />

};<br />

void free_list(struct node *head) {<br />

for (struct node *p = head; p != NULL; p = p->next) {<br />

free(p);<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 256<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

9.1.2 Compliant Solution<br />

Kernighan and Ritchie correct this error by storing a reference to p->next in q before freeing p:<br />

#include <br />

struct node {<br />

int value;<br />

struct node *next;<br />

};<br />

void free_list(struct node *head) {<br />

struct node *q;<br />

for (struct node *p = head; p != NULL; p = q) {<br />

q = p->next;<br />

free(p);<br />

}<br />

}<br />

9.1.3 Noncompliant Code Example<br />

In this noncompliant code example, buf is written to after it has been freed. Write-after-free vulnerabilities<br />

can be exploited to run arbitrary code with the permissions of the vulnerable process.<br />

Typically, allocations and frees are far removed, making it difficult to recognize and diagnose<br />

these problems.<br />

#include <br />

#include <br />

int main(int argc, char *argv[]) {<br />

char *return_val = 0;<br />

const size_t bufsize = strlen(argv[0]) + 1;<br />

char *buf = (char *)malloc(bufsize);<br />

if (!buf) {<br />

return EXIT_FAILURE;<br />

}<br />

/* ... */<br />

free(buf);<br />

/* ... */<br />

strcpy(buf, argv[0]);<br />

/* ... */<br />

return EXIT_SUCCESS;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 257<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

9.1.4 Compliant Solution<br />

In this compliant solution, the memory is freed after its final use:<br />

#include <br />

#include <br />

int main(int argc, char *argv[]) {<br />

char *return_val = 0;<br />

const size_t bufsize = strlen(argv[0]) + 1;<br />

char *buf = (char *)malloc(bufsize);<br />

if (!buf) {<br />

return EXIT_FAILURE;<br />

}<br />

/* ... */<br />

strcpy(buf, argv[0]);<br />

/* ... */<br />

free(buf);<br />

return EXIT_SUCCESS;<br />

}<br />

9.1.5 Noncompliant Code Example<br />

In this noncompliant example, realloc() may free c_str1 when it returns a null pointer, resulting<br />

in c_str1 being freed twice. The C <strong>Standard</strong>s Committee's proposed response to Defect<br />

Report #400 makes it implementation-defined whether or not the old object is deallocated when<br />

size is zero and memory for the new object is not allocated. The current implementation of realloc()<br />

in the GNU C Library and Microsoft Visual Studio's Runtime Library will free c_str1<br />

and return a null pointer for zero byte allocations. Freeing a pointer twice can result in a potentially<br />

exploitable vulnerability commonly referred to as a double-free vulnerability [Seacord<br />

2013b].<br />

#include <br />

void f(char *c_str1, size_t size) {<br />

char *c_str2 = (char *)realloc(c_str1, size);<br />

if (c_str2 == NULL) {<br />

free(c_str1);<br />

}<br />

}<br />

9.1.6 Compliant Solution<br />

This compliant solution does not pass a size argument of zero to the realloc() function, eliminating<br />

the possibility of c_str1 being freed twice:<br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 258<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

void f(char *c_str1, size_t size) {<br />

if (size != 0) {<br />

char *c_str2 = (char *)realloc(c_str1, size);<br />

if (c_str2 == NULL) {<br />

free(c_str1);<br />

}<br />

}<br />

else {<br />

free(c_str1);<br />

}<br />

}<br />

If the intent of calling f() is to reduce the size of the object, then doing nothing when the size is<br />

zero would be unexpected; instead, this compliant solution frees the object.<br />

9.1.7 Noncompliant Code Example<br />

In this noncompliant example (CVE-2009-1364) from libwmf version 0.2.8.4, the return value of<br />

gdRealloc (a simple wrapper around realloc() that reallocates space pointed to by im-<br />

>clip->list) is set to more. However, the value of im->clip->list is used directly afterwards<br />

in the code, and the C <strong>Standard</strong> specifies that if realloc() moves the area pointed to, then<br />

the original block is freed. An attacker can then execute arbitrary code by forcing a reallocation<br />

(with a sufficient im->clip->count) and accessing freed memory [xorl 2009].<br />

void gdClipSetAdd(gdImagePtr im, gdClipRectanglePtr rect) {<br />

gdClipRectanglePtr more;<br />

if (im->clip == 0) {<br />

/* ... */<br />

}<br />

if (im->clip->count == im->clip->max) {<br />

more = gdRealloc (im->clip->list,(im->clip->max + 8) *<br />

sizeof (gdClipRectangle));<br />

/*<br />

* If the realloc fails, then we have not lost the<br />

* im->clip->list value.<br />

*/<br />

if (more == 0) return;<br />

im->clip->max += 8;<br />

}<br />

im->clip->list[im->clip->count] = *rect;<br />

im->clip->count++;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 259<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

9.1.8 Compliant Solution<br />

This compliant solution simply reassigns im->clip->list to the value of more after the call to<br />

realloc():<br />

void gdClipSetAdd(gdImagePtr im, gdClipRectanglePtr rect) {<br />

gdClipRectanglePtr more;<br />

if (im->clip == 0) {<br />

/* ... */<br />

}<br />

if (im->clip->count == im->clip->max) {<br />

more = gdRealloc (im->clip->list,(im->clip->max + 8) *<br />

sizeof (gdClipRectangle));<br />

if (more == 0) return;<br />

im->clip->max += 8;<br />

im->clip->list = more;<br />

}<br />

im->clip->list[im->clip->count] = *rect;<br />

im->clip->count++;<br />

}<br />

9.1.9 Risk Assessment<br />

Reading memory that has already been freed can lead to abnormal program termination and denial-of-service<br />

attacks. Writing memory that has already been freed can additionally lead to the<br />

execution of arbitrary code with the permissions of the vulnerable process.<br />

Freeing memory multiple times has similar consequences to accessing memory after it is freed.<br />

Reading a pointer to deallocated memory is undefined behavior because the pointer value is indeterminate<br />

and might be a trap representation. When reading from or writing to freed memory does<br />

not cause a trap, it may corrupt the underlying data structures that manage the heap in a manner<br />

that can be exploited to execute arbitrary code. Alternatively, writing to memory after it has been<br />

freed might modify memory that has been reallocated.<br />

Programmers should be wary when freeing memory in a loop or conditional statement; if coded<br />

incorrectly, these constructs can lead to double-free vulnerabilities. It is also a common error to<br />

misuse the realloc() function in a manner that results in double-free vulnerabilities. (See<br />

MEM04-C. Beware of zero-length allocations.)<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MEM30-C High Likely Medium P18 L1<br />

9.1.9.1 Related Vulnerabilities<br />

VU#623332 describes a double-free vulnerability in the MIT Kerberos 5 function<br />

krb5_recvauth().<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 260<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM30-C. Do not access freed memory<br />

9.1.10 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MISRA C:2012<br />

MITRE CWE<br />

MEM01-C. Store a new value in pointers immediately<br />

after free()<br />

MEM50-CPP. Do not access freed memory<br />

Dangling References to Stack Frames [DCM]<br />

Dangling Reference to Heap [XYK]<br />

Accessing freed memory [accfree]<br />

Freeing memory multiple times [dblfree]<br />

Rule 18.6 (required)<br />

CWE-415, Double Free<br />

CWE-416, Use After Free<br />

9.1.11 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Kernighan 1988]<br />

[OWASP Freed Memory]<br />

[MIT 2005]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

[VU#623332]<br />

[xorl 2009]<br />

7.22.3, “Memory Management Functions”<br />

Section 7.8.5, “Storage Management”<br />

Chapter 4, “Dynamic Memory Management”<br />

Section 5.2.19, “Using Freed Memory”<br />

CVE-2009-1364: LibWMF Pointer Use after<br />

free()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 261<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM31-C. Free dynamically allocated memory when no longer needed<br />

9.2 MEM31-C. Free dynamically allocated memory when no longer<br />

needed<br />

Before the lifetime of the last pointer that stores the return value of a call to a standard memory<br />

allocation function has ended, it must be matched by a call to free() with that pointer value.<br />

9.2.1 Noncompliant Code Example<br />

In this noncompliant example, the object allocated by the call to malloc() is not freed before the<br />

end of the lifetime of the last pointer text_buffer referring to the object:<br />

#include <br />

enum { BUFFER_SIZE = 32 };<br />

int f(void) {<br />

char *text_buffer = (char *)malloc(BUFFER_SIZE);<br />

if (text_buffer == NULL) {<br />

return -1;<br />

}<br />

return 0;<br />

}<br />

9.2.2 Compliant Solution<br />

In this compliant solution, the pointer is deallocated with a call to free():<br />

#include <br />

enum { BUFFER_SIZE = 32 };<br />

int f(void) {<br />

char *text_buffer = (char *)malloc(BUFFER_SIZE);<br />

if (text_buffer == NULL) {<br />

return -1;<br />

}<br />

}<br />

free(text_buffer);<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 262<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM31-C. Free dynamically allocated memory when no longer needed<br />

9.2.3 Exceptions<br />

MEM31-C-EX1: Allocated memory does not need to be freed if it is assigned to a pointer with<br />

static storage duration whose lifetime is the entire execution of a program. The following code example<br />

illustrates a pointer that stores the return value from malloc() in a static variable:<br />

#include <br />

enum { BUFFER_SIZE = 32 };<br />

int f(void) {<br />

static char *text_buffer = NULL;<br />

if (text_buffer == NULL) {<br />

text_buffer = (char *)malloc(BUFFER_SIZE);<br />

if (text_buffer == NULL) {<br />

return -1;<br />

}<br />

}<br />

return 0;<br />

}<br />

9.2.4 Risk Assessment<br />

Failing to free memory can result in the exhaustion of system memory resources, which can lead<br />

to a denial-of-service attack.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MEM31-C Medium Probable Medium P8 L2<br />

9.2.5 Related Guidelines<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

Memory Leak [XYL]<br />

Failing to close files or free dynamic memory<br />

when they are no longer needed [fileclose]<br />

CWE-401, Improper Release of Memory Before<br />

Removing Last Reference (“Memory<br />

Leak”)<br />

9.2.6 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.22.3, “Memory Management<br />

Functions”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 263<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM33-C. Allocate and copy structures containing a flexible array member dynamically<br />

9.3 MEM33-C. Allocate and copy structures containing a flexible array<br />

member dynamically<br />

The C <strong>Standard</strong>, 6.7.2.1, paragraph 18 [ISO/IEC 9899:2011], says<br />

As a special case, the last element of a structure with more than one named member<br />

may have an incomplete array type; this is called a flexible array member. In most situations,<br />

the flexible array member is ignored. In particular, the size of the structure is as if<br />

the flexible array member were omitted except that it may have more trailing padding<br />

than the omission would imply.<br />

The following is an example of a structure that contains a flexible array member:<br />

struct flex_array_struct {<br />

int num;<br />

int data[];<br />

};<br />

This definition means that when computing the size of such a structure, only the first member,<br />

num, is considered. Unless the appropriate size of the flexible array member has been explicitly<br />

added when allocating storage for an object of the struct, the result of accessing the member<br />

data of a variable of nonpointer type struct flex_array_struct is undefined. DCL38-C.<br />

Use the correct syntax when declaring a flexible array member describes the correct way to declare<br />

a struct with a flexible array member.<br />

To avoid the potential for undefined behavior, structures that contain a flexible array member<br />

should always be allocated dynamically. Flexible array structures must<br />

• Have dynamic storage duration (be allocated via malloc() or another dynamic allocation<br />

function)<br />

• Be dynamically copied using memcpy() or a similar function and not by assignment<br />

• When used as an argument to a function, be passed by pointer and not copied by value<br />

9.3.1 Noncompliant Code Example (Storage Duration)<br />

This noncompliant code example uses automatic storage for a structure containing a flexible array<br />

member:<br />

#include <br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void func(void) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 264<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM33-C. Allocate and copy structures containing a flexible array member dynamically<br />

struct flex_array_struct flex_struct;<br />

size_t array_size = 4;<br />

/* Initialize structure */<br />

flex_struct.num = array_size;<br />

}<br />

for (size_t i = 0; i < array_size; ++i) {<br />

flex_struct.data[i] = 0;<br />

}<br />

Because the memory for flex_struct is reserved on the stack, no space is reserved for the<br />

data member. Accessing the data member is undefined behavior.<br />

9.3.2 Compliant Solution (Storage Duration)<br />

This compliant solution dynamically allocates storage for flex_array_struct:<br />

#include <br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void func(void) {<br />

struct flex_array_struct *flex_struct;<br />

size_t array_size = 4;<br />

}<br />

/* Dynamically allocate memory for the struct */<br />

flex_struct = (struct flex_array_struct *)malloc(<br />

sizeof(struct flex_array_struct)<br />

+ sizeof(int) * array_size);<br />

if (flex_sruct == NULL) {<br />

/* Handle error */<br />

}<br />

/* Initialize structure */<br />

flex_struct->num = array_size;<br />

for (size_t i = 0; i < array_size; ++i) {<br />

flex_struct->data[i] = 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 265<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM33-C. Allocate and copy structures containing a flexible array member dynamically<br />

9.3.3 Noncompliant Code Example (Copying)<br />

This noncompliant code example attempts to copy an instance of a structure containing a flexible<br />

array member (struct flex_array_struct) by assignment:<br />

#include <br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void func(struct flex_array_struct *struct_a,<br />

struct flex_array_struct *struct_b) {<br />

*struct_b = *struct_a;<br />

}<br />

When the structure is copied, the size of the flexible array member is not considered, and only the<br />

first member of the structure, num, is copied, leaving the array contents untouched.<br />

9.3.4 Compliant Solution (Copying)<br />

This compliant solution uses memcpy() to properly copy the content of struct_a into<br />

struct_b:<br />

#include <br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void func(struct flex_array_struct *struct_a,<br />

struct flex_array_struct *struct_b) {<br />

if (struct_a->num > struct_b->num) {<br />

/* Insufficient space; handle error */<br />

return;<br />

}<br />

memcpy(struct_b, struct_a,<br />

sizeof(struct flex_array_struct) + (sizeof(int)<br />

* struct_a->num));<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 266<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM33-C. Allocate and copy structures containing a flexible array member dynamically<br />

9.3.5 Noncompliant Code Example (Function Arguments)<br />

In this noncompliant code example, the flexible array structure is passed by value to a function<br />

that prints the array elements:<br />

#include <br />

#include <br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void print_array(struct flex_array_struct struct_p) {<br />

puts("Array is: ");<br />

for (size_t i = 0; i < struct_p.num; ++i) {<br />

printf("%d ", struct_p.data[i]);<br />

}<br />

putchar('\n');<br />

}<br />

void func(void) {<br />

struct flex_array_struct *struct_p;<br />

size_t array_size = 4;<br />

/* Space is allocated for the struct */<br />

struct_p = (struct flex_array_struct *)malloc(<br />

sizeof(struct flex_array_struct)<br />

+ sizeof(int) * array_size);<br />

if (struct_p == NULL) {<br />

/* Handle error */<br />

}<br />

struct_p->num = array_size;<br />

}<br />

for (size_t i = 0; i < array_size; ++i) {<br />

struct_p->data[i] = i;<br />

}<br />

print_array(*struct_p);<br />

Because the argument is passed by value, the size of the flexible array member is not considered<br />

when the structure is copied, and only the first member of the structure, num, is copied.<br />

9.3.6 Compliant Solution (Function Arguments)<br />

In this compliant solution, the structure is passed by reference and not by value:<br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 267<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM33-C. Allocate and copy structures containing a flexible array member dynamically<br />

struct flex_array_struct {<br />

size_t num;<br />

int data[];<br />

};<br />

void print_array(struct flex_array_struct *struct_p) {<br />

puts("Array is: ");<br />

for (size_t i = 0; i < struct_p->num; ++i) {<br />

printf("%d ", struct_p->data[i]);<br />

}<br />

putchar('\n');<br />

}<br />

void func(void) {<br />

struct flex_array_struct *struct_p;<br />

size_t array_size = 4;<br />

/* Space is allocated for the struct and initialized... */<br />

}<br />

print_array(struct_p);<br />

9.3.7 Risk Assessment<br />

Failure to use structures with flexible array members correctly can result in undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MEM33-C Low Unlikely Low P3 L3<br />

9.3.8 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

DCL38-C. Use the correct syntax when declaring<br />

a flexible array member<br />

9.3.9 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[JTC1/SC22/WG14 N791]<br />

Subclause 6.7.2.1, “Structure and Union Specifiers”<br />

Solving the Struct Hack Problem<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 268<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM34-C. Only free memory allocated dynamically<br />

9.4 MEM34-C. Only free memory allocated dynamically<br />

The C <strong>Standard</strong>, Annex J [ISO/IEC 9899:2011], states that the behavior of a program is undefined<br />

when<br />

The pointer argument to the free or realloc function does not match a pointer earlier<br />

returned by a memory management function, or the space has been deallocated by a<br />

call to free or realloc.<br />

See also undefined behavior 179.<br />

Freeing memory that is not allocated dynamically can result in heap corruption and other serious<br />

errors. Do not call free() on a pointer other than one returned by a standard memory allocation<br />

function, such as malloc(), calloc(), realloc(), or aligned_alloc().<br />

A similar situation arises when realloc() is supplied a pointer to non-dynamically allocated<br />

memory. The realloc() function is used to resize a block of dynamic memory. If realloc()<br />

is supplied a pointer to memory not allocated by a standard memory allocation function, the behavior<br />

is undefined. One consequence is that the program may terminate abnormally.<br />

This rule does not apply to null pointers. The C <strong>Standard</strong> guarantees that if free() is passed a<br />

null pointer, no action occurs.<br />

9.4.1 Noncompliant Code Example<br />

This noncompliant code example sets c_str to reference either dynamically allocated memory or<br />

a statically allocated string literal depending on the value of argc. In either case, c_str is passed<br />

as an argument to free(). If anything other than dynamically allocated memory is referenced by<br />

c_str, the call to free(c_str) is erroneous.<br />

#include <br />

#include <br />

#include <br />

enum { MAX_ALLOCATION = 1000 };<br />

int main(int argc, const char *argv[]) {<br />

char *c_str = NULL;<br />

size_t len;<br />

if (argc == 2) {<br />

len = strlen(argv[1]) + 1;<br />

if (len > MAX_ALLOCATION) {<br />

/* Handle error */<br />

}<br />

c_str = (char *)malloc(len);<br />

if (c_str == NULL) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 269<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM34-C. Only free memory allocated dynamically<br />

}<br />

}<br />

strcpy(c_str, argv[1]);<br />

} else {<br />

c_str = "usage: $>a.exe [string]";<br />

printf("%s\n", c_str);<br />

}<br />

free(c_str);<br />

return 0;<br />

9.4.2 Compliant Solution<br />

This compliant solution eliminates the possibility of c_str referencing memory that is not allocated<br />

dynamically when passed to free():<br />

#include <br />

#include <br />

#include <br />

enum { MAX_ALLOCATION = 1000 };<br />

int main(int argc, const char *argv[]) {<br />

char *c_str = NULL;<br />

size_t len;<br />

}<br />

if (argc == 2) {<br />

len = strlen(argv[1]) + 1;<br />

if (len > MAX_ALLOCATION) {<br />

/* Handle error */<br />

}<br />

c_str = (char *)malloc(len);<br />

if (c_str == NULL) {<br />

/* Handle error */<br />

}<br />

strcpy(c_str, argv[1]);<br />

} else {<br />

printf("%s\n", "usage: $>a.exe [string]");<br />

return EXIT_FAILURE;<br />

}<br />

free(c_str);<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 270<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM34-C. Only free memory allocated dynamically<br />

9.4.3 Noncompliant Code Example (realloc())<br />

In this noncompliant example, the pointer parameter to realloc(), buf, does not refer to dynamically<br />

allocated memory:<br />

#include <br />

enum { BUFSIZE = 256 };<br />

void f(void) {<br />

char buf[BUFSIZE];<br />

char *p = (char *)realloc(buf, 2 * BUFSIZE);<br />

if (p == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

9.4.4 Compliant Solution (realloc())<br />

In this compliant solution, buf refers to dynamically allocated memory:<br />

#include <br />

enum { BUFSIZE = 256 };<br />

void f(void) {<br />

char *buf = (char *)malloc(BUFSIZE * sizeof(char));<br />

char *p = (char *)realloc(buf, 2 * BUFSIZE);<br />

if (p == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

Note that realloc() will behave properly even if malloc() failed, because when given a null<br />

pointer, realloc() behaves like a call to malloc().<br />

9.4.5 Risk Assessment<br />

The consequences of this error depend on the implementation, but they range from nothing to arbitrary<br />

code execution if that memory is reused by malloc().<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MEM34-C High Likely Medium P18 L1<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 271<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM34-C. Only free memory allocated dynamically<br />

9.4.5.1 Related Vulnerabilities<br />

CVE-2015-0240 describes a vulnerability in which an uninitialized pointer is passed to<br />

TALLOC_FREE(), which is a Samba-specific memory deallocation macro that wraps the talloc_free()<br />

function. The implementation of talloc_free() would access the uninitialized<br />

pointer, resulting in a remote exploit.<br />

9.4.6 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961<br />

MITRE CWE<br />

MEM31-C. Free dynamically allocated<br />

memory when no longer needed<br />

MEM51-CPP. Properly deallocate dynamically<br />

allocated resources<br />

Reallocating or freeing memory that was not<br />

dynamically allocated [xfree]<br />

CWE-590, Free of Memory Not on the Heap<br />

9.4.7 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Seacord 2013b]<br />

Subclause J.2, “Undefined Behavior”<br />

Chapter 4, “Dynamic Memory Management”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 272<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM35-C. Allocate sufficient memory for an object<br />

9.5 MEM35-C. Allocate sufficient memory for an object<br />

The types of integer expressions used as size arguments to malloc(), calloc(), realloc(),<br />

or aligned_alloc() must have sufficient range to represent the size of the objects to be stored.<br />

If size arguments are incorrect or can be manipulated by an attacker, then a buffer overflow may<br />

occur. Incorrect size arguments, inadequate range checking, integer overflow, or truncation can<br />

result in the allocation of an inadequately sized buffer.<br />

Typically, the amount of memory to allocate will be the size of the type of object to allocate.<br />

When allocating space for an array, the size of the object will be multiplied by the bounds of the<br />

array. When allocating space for a structure containing a flexible array member, the size of the array<br />

member must be added to the size of the structure. (See MEM33-C. Allocate and copy structures<br />

containing a flexible array member dynamically.) Use the correct type of the object when<br />

computing the size of memory to allocate.<br />

STR31-C. Guarantee that storage for strings has sufficient space for character data and the null<br />

terminator is a specific instance of this rule.<br />

9.5.1 Noncompliant Code Example (Integer)<br />

In this noncompliant code example, an array of long is allocated and assigned to p. The code<br />

checks for unsigned integer overflow in compliance with INT32-C. Ensure that operations on<br />

signed integers do not result in overflow and also ensures that len is not equal to zero. (See<br />

MEM04-C. Beware of zero-length allocations.) However, because sizeof(int) is used to compute<br />

the size, and not sizeof(long), an insufficient amount of memory can be allocated on implementations<br />

where sizeof(long) is larger than sizeof(int).<br />

#include <br />

#include <br />

void function(size_t len) {<br />

long *p;<br />

if (len == 0 || len > SIZE_MAX / sizeof(long)) {<br />

/* Handle overflow */<br />

}<br />

p = (long *)malloc(len * sizeof(int));<br />

if (p == NULL) {<br />

/* Handle error */<br />

}<br />

free(p);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 273<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM35-C. Allocate sufficient memory for an object<br />

9.5.2 Compliant Solution (Integer)<br />

This compliant solution uses sizeof(long) to correctly size the memory allocation:<br />

#include <br />

#include <br />

void function(size_t len) {<br />

long *p;<br />

if (len == 0 || len > SIZE_MAX / sizeof(long)) {<br />

/* Handle overflow */<br />

}<br />

p = (long *)malloc(len * sizeof(long));<br />

if (p == NULL) {<br />

/* Handle error */<br />

}<br />

free(p);<br />

}<br />

9.5.3 Compliant Solution (Integer)<br />

Alternatively, sizeof(*p) can be used to properly size the allocation:<br />

#include <br />

#include <br />

void function(size_t len) {<br />

long *p;<br />

if (len == 0 || len > SIZE_MAX / sizeof(*p)) {<br />

/* Handle overflow */<br />

}<br />

p = (long *)malloc(len * sizeof(*p));<br />

if (p == NULL) {<br />

/* Handle error */<br />

}<br />

free(p);<br />

}<br />

9.5.4 Noncompliant Code Example (Pointer)<br />

In this noncompliant code example, inadequate space is allocated for a struct tm object because<br />

the size of the pointer is being used to determine the size of the pointed-to object:<br />

#include <br />

#include <br />

struct tm *make_tm(int year, int mon, int day, int hour,<br />

int min, int sec) {<br />

struct tm *tmb;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 274<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM35-C. Allocate sufficient memory for an object<br />

}<br />

tmb = (struct tm *)malloc(sizeof(tmb));<br />

if (tmb == NULL) {<br />

return NULL;<br />

}<br />

*tmb = (struct tm) {<br />

.tm_sec = sec, .tm_min = min, .tm_hour = hour,<br />

.tm_mday = day, .tm_mon = mon, .tm_year = year<br />

};<br />

return tmb;<br />

9.5.5 Compliant Solution (Pointer)<br />

In this compliant solution, the correct amount of memory is allocated for the struct tm object.<br />

When allocating space for a single object, passing the (dereferenced) pointer type to the sizeof<br />

operator is a simple way to allocate sufficient memory. Because the sizeof operator does not<br />

evaluate its operand, dereferencing an uninitialized or null pointer in this context is well-defined<br />

behavior.<br />

#include <br />

#include <br />

struct tm *make_tm(int year, int mon, int day, int hour,<br />

int min, int sec) {<br />

struct tm *tmb;<br />

tmb = (struct tm *)malloc(sizeof(*tmb));<br />

if (tmb == NULL) {<br />

return NULL;<br />

}<br />

*tmb = (struct tm) {<br />

.tm_sec = sec, .tm_min = min, .tm_hour = hour,<br />

.tm_mday = day, .tm_mon = mon, .tm_year = year<br />

};<br />

return tmb;<br />

}<br />

9.5.6 Risk Assessment<br />

Providing invalid size arguments to memory allocation functions can lead to buffer overflows and<br />

the execution of arbitrary code with the permissions of the vulnerable process.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MEM35-C High Probable High P6 L2<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 275<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM35-C. Allocate sufficient memory for an object<br />

9.5.7 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

ARR01-C. Do not apply the sizeof operator to<br />

a pointer when taking the size of an array<br />

INT31-C. Ensure that integer conversions do<br />

not result in lost or misinterpreted data<br />

INT32-C. Ensure that operations on signed integers<br />

do not result in overflow<br />

INT18-C. Evaluate integer expressions in a<br />

larger size before comparing or assigning to<br />

that size<br />

MEM04-C. Beware of zero-length allocations<br />

Buffer Boundary Violation (Buffer Overflow)<br />

[HCB]<br />

Taking the size of a pointer to determine the<br />

size of the pointed-to type [sizeofptr]<br />

CWE-131, Incorrect Calculation of Buffer Size<br />

CWE-190, Integer Overflow or Wraparound<br />

CWE-467, Use of sizeof() on a Pointer<br />

Type<br />

9.5.8 Bibliography<br />

[Coverity 2007]<br />

[Drepper 2006]<br />

[Seacord 2013]<br />

[Viega 2005]<br />

[xorl 2009]<br />

Section 2.1.1, “Respecting Memory Bounds”<br />

Chapter 4, “Dynamic Memory Management”<br />

Chapter 5, “Integer Security”<br />

Section 5.6.8, “Use of sizeof() on a Pointer<br />

Type”<br />

CVE-2009-0587: Evolution Data Server<br />

Base64 Integer Overflows<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 276<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Memory Management (MEM) - MEM36-C. Do not modify the alignment of objects by calling realloc()<br />

9.6 MEM36-C. Do not modify the alignment of objects by calling<br />

realloc()<br />

Do not invoke realloc() to modify the size of allocated objects that have stricter alignment requirements<br />

than those guaranteed by malloc(). Storage allocated by a call to the standard<br />

aligned_alloc() function, for example, can have stricter than normal alignment requirements.<br />

The C standard requires only that a pointer returned by realloc() be suitably aligned so that it<br />

may be assigned to a pointer to any type of object with a fundamental alignment requirement.<br />

9.6.1 Noncompliant Code Example<br />

This noncompliant code example returns a pointer to allocated memory that has been aligned to a<br />

4096-byte boundary. If the resize argument to the realloc() function is larger than the object<br />

referenced by ptr, then realloc() will allocate new memory that is suitably aligned so that it<br />

may be assigned to a pointer to any type of object with a fundamental alignment requirement but<br />

may not preserve the stricter alignment of the original object.<br />

#include <br />

void func(void) {<br />

size_t resize = 1024;<br />

size_t alignment = 1


Memory Management (MEM) - MEM36-C. Do not modify the alignment of objects by calling realloc()<br />

size_t align = 1


Memory Management (MEM) - MEM36-C. Do not modify the alignment of objects by calling realloc()<br />

if (NULL == (ptr = (int *)aligned_alloc(alignment,<br />

sizeof(int)))) {<br />

/* Handle error */<br />

}<br />

if (NULL == (ptr1 = (int *)aligned_alloc(alignment,<br />

resize))) {<br />

/* Handle error */<br />

}<br />

if (NULL == (memcpy(ptr1, ptr, sizeof(int))) {<br />

/* Handle error */<br />

}<br />

}<br />

free(ptr);<br />

9.6.3 Compliant Solution (Windows)<br />

Windows defines the _aligned_malloc() function to allocate memory on a specified alignment<br />

boundary. The _aligned_realloc() [MSDN] can be used to change the size of this<br />

memory. This compliant solution demonstrates one such usage:<br />

#include <br />

void func(void) {<br />

size_t alignment = 1


Memory Management (MEM) - MEM36-C. Do not modify the alignment of objects by calling realloc()<br />

9.6.4 Risk Assessment<br />

Improper alignment can lead to arbitrary memory locations being accessed and written to.<br />

Recommendation Severity Likelihood Remediation Cost Priority Level<br />

MEM36-C Low Probable High P2 L3<br />

9.6.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[MSDN]<br />

7.22.3.1, “The aligned_alloc Function”<br />

aligned_malloc()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 280<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO30-C. Exclude user input from format strings<br />

10 Input/Output (FIO)<br />

10.1 FIO30-C. Exclude user input from format strings<br />

Never call a formatted I/O function with a format string containing a tainted value . An attacker<br />

who can fully or partially control the contents of a format string can crash a vulnerable process,<br />

view the contents of the stack, view memory content, or write to an arbitrary memory location.<br />

Consequently, the attacker can execute arbitrary code with the permissions of the vulnerable process<br />

[Seacord 2013b]. Formatted output functions are particularly dangerous because many programmers<br />

are unaware of their capabilities. For example, formatted output functions can be used<br />

to write an integer value to a specified address using the %n conversion specifier.<br />

10.1.1 Noncompliant Code Example<br />

The incorrect_password() function in this noncompliant code example is called during identification<br />

and authentication to display an error message if the specified user is not found or the<br />

password is incorrect. The function accepts the name of the user as a string referenced by user.<br />

This is an exemplar of untrusted data that originates from an unauthenticated user. The function<br />

constructs an error message that is then output to stderr using the C <strong>Standard</strong> fprintf() function.<br />

#include <br />

#include <br />

#include <br />

void incorrect_password(const char *user) {<br />

int ret;<br />

/* User names are restricted to 256 or fewer characters */<br />

static const char msg_format[] = "%s cannot be authenticated.\n";<br />

size_t len = strlen(user) + sizeof(msg_format);<br />

char *msg = (char *)malloc(len);<br />

if (msg == NULL) {<br />

/* Handle error */<br />

}<br />

ret = snprintf(msg, len, msg_format, user);<br />

if (ret < 0) {<br />

/* Handle error */<br />

} else if (ret >= len) {<br />

/* Handle truncated output */<br />

}<br />

fprintf(stderr, msg);<br />

free(msg);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 281<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO30-C. Exclude user input from format strings<br />

The incorrect_password() function calculates the size of the message, allocates dynamic<br />

storage, and then constructs the message in the allocated memory using the snprintf() function.<br />

The addition operations are not checked for integer overflow because the string referenced<br />

by user is known to have a length of 256 or less. Because the %s characters are replaced by the<br />

string referenced by user in the call to snprintf(), the resulting string needs 1 byte less than is<br />

allocated. The snprintf() function is commonly used for messages that are displayed in multiple<br />

locations or messages that are difficult to build. However, the resulting code contains a format-string<br />

vulnerability because the msg includes untrusted user input and is passed as the formatstring<br />

argument in the call to fprintf().<br />

10.1.2 Compliant Solution (fputs())<br />

This compliant solution fixes the problem by replacing the fprintf() call with a call to<br />

fputs(), which outputs msg directly to stderr without evaluating its contents:<br />

#include <br />

#include <br />

#include <br />

void incorrect_password(const char *user) {<br />

int ret;<br />

/* User names are restricted to 256 or fewer characters */<br />

static const char msg_format[] = "%s cannot be authenticated.\n";<br />

size_t len = strlen(user) + sizeof(msg_format);<br />

char *msg = (char *)malloc(len);<br />

if (msg == NULL) {<br />

/* Handle error */<br />

}<br />

ret = snprintf(msg, len, msg_format, user);<br />

if (ret < 0) {<br />

/* Handle error */<br />

} else if (ret >= len) {<br />

/* Handle truncated output */<br />

}<br />

fputs(msg, stderr);<br />

free(msg);<br />

}<br />

10.1.3 Compliant Solution (fprintf())<br />

This compliant solution passes the untrusted user input as one of the variadic arguments to<br />

fprintf() and not as part of the format string, eliminating the possibility of a format-string vulnerability:<br />

#include <br />

void incorrect_password(const char *user) {<br />

static const char msg_format[] = "%s cannot be authenticated.\n";<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 282<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO30-C. Exclude user input from format strings<br />

}<br />

fprintf(stderr, msg_format, user);<br />

10.1.4 Noncompliant Code Example (POSIX)<br />

This noncompliant code example is similar to the first noncompliant code example but uses the<br />

POSIX function syslog() [IEEE Std 1003.1:2013] instead of the fprintf() function. The<br />

syslog() function is also susceptible to format-string vulnerabilities.<br />

#include <br />

#include <br />

#include <br />

#include <br />

void incorrect_password(const char *user) {<br />

int ret;<br />

/* User names are restricted to 256 or fewer characters */<br />

static const char msg_format[] = "%s cannot be authenticated.\n";<br />

size_t len = strlen(user) + sizeof(msg_format);<br />

char *msg = (char *)malloc(len);<br />

if (msg != NULL) {<br />

/* Handle error */<br />

}<br />

ret = snprintf(msg, len, msg_format, user);<br />

if (ret < 0) {<br />

/* Handle error */<br />

} else if (ret >= len) {<br />

/* Handle truncated output */<br />

}<br />

syslog(LOG_INFO, msg);<br />

free(msg);<br />

}<br />

The syslog() function first appeared in BSD 4.2 and is supported by Linux and other modern<br />

UNIX implementations. It is not available on Windows systems.<br />

10.1.5 Compliant Solution (POSIX)<br />

This compliant solution passes the untrusted user input as one of the variadic arguments to syslog()<br />

instead of including it in the format string:<br />

#include <br />

void incorrect_password(const char *user) {<br />

static const char msg_format[] = "%s cannot be authenticated.\n";<br />

syslog(LOG_INFO, msg_format, user);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 283<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO30-C. Exclude user input from format strings<br />

10.1.6 Risk Assessment<br />

Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable<br />

process, view the contents of the stack, view memory content, or write to an arbitrary memory location<br />

and consequently execute arbitrary code with the permissions of the vulnerable process.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO30-C High Likely Medium P18 L1<br />

10.1.6.1 Related Vulnerabilities<br />

Two examples of format-string vulnerabilities resulting from a violation of this rule include Ettercap<br />

and Samba.<br />

In Ettercap v.NG-0.7.2, the ncurses user interface suffers from a format-string defect. The<br />

curses_msg() function in ec_curses.c calls wdg_scroll_print(), which takes a format<br />

string and its parameters and passes it to vw_printw(). The curses_msg() function uses one<br />

of its parameters as the format string. This input can include user data, allowing for a formatstring<br />

vulnerability.<br />

The Samba AFS ACL mapping VFS plug-in fails to properly sanitize user-controlled file names<br />

that are used in a format specifier supplied to snprintf(). This security flaw becomes exploitable<br />

when a user can write to a share that uses Samba’s afsacl.so library for setting Windows<br />

NT access control lists on files residing on an AFS file system.<br />

10.1.7 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java IDS06-J. Exclude unsanitized user input from<br />

format strings<br />

<strong>CERT</strong> Perl Secure <strong>Coding</strong> <strong>Standard</strong><br />

IDS30-PL. Exclude user input from format<br />

strings<br />

ISO/IEC TR 24772:2013<br />

Injection [RST]<br />

ISO/IEC TS 17961:2013<br />

Including tainted or out-of-domain input in a<br />

format string [usrfmt]<br />

MITRE CWE<br />

CWE-134, Uncontrolled Format String<br />

10.1.8 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[Seacord 2013b]<br />

[Viega 2005]<br />

XSH, System Interfaces, syslog<br />

Chapter 6, “Formatted Output”<br />

Section 5.2.23, “Format String Problem”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 284<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

10.2 FIO32-C. Do not perform operations on devices that are only<br />

appropriate for files<br />

File names on many operating systems, including Windows and UNIX, may be used to access<br />

special files, which are actually devices. Reserved Microsoft Windows device names include AUX,<br />

CON, PRN, COM1, and LPT1 or paths using the \\.\ device namespace. Device files on UNIX systems<br />

are used to apply access rights and to direct operations on the files to the appropriate device<br />

drivers.<br />

Performing operations on device files that are intended for ordinary character or binary files can<br />

result in crashes and denial-of-service attacks. For example, when Windows attempts to interpret<br />

the device name as a file resource, it performs an invalid resource access that usually results in a<br />

crash [Howard 2002].<br />

Device files in UNIX can be a security risk when an attacker can access them in an unauthorized<br />

way. For example, if attackers can read or write to the /dev/kmem device, they may be able to<br />

alter the priority, UID, or other attributes of their process or simply crash the system. Similarly,<br />

access to disk devices, tape devices, network devices, and terminals being used by other processes<br />

can lead to problems [Garfinkel 1996].<br />

On Linux, it is possible to lock certain applications by attempting to open devices rather than<br />

files. Consider the following example:<br />

/dev/mouse<br />

/dev/console<br />

/dev/tty0<br />

/dev/zero<br />

A Web browser that failed to check for these devices would allow an attacker to create a website<br />

with image tags such as that would lock the user's mouse.<br />

10.2.1 Noncompliant Code Example<br />

In this noncompliant code example, the user can specify a locked device or a FIFO (first-in, firstout)<br />

file name, which can cause the program to hang on the call to fopen():<br />

#include <br />

void func(const char *file_name) {<br />

FILE *file;<br />

if ((file = fopen(file_name, "wb")) == NULL) {<br />

/* Handle error */<br />

}<br />

/* Operate on the file */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 285<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

}<br />

if (fclose(file) == EOF) {<br />

/* Handle error */<br />

}<br />

10.2.2 Compliant Solution (POSIX)<br />

POSIX defines the O_NONBLOCK flag to open(), which ensures that delayed operations on a file<br />

do not hang the program [IEEE Std 1003.1:2013].<br />

When opening a FIFO with O_RDONLY or O_WRONLY set:<br />

When opening a block special or character special file that supports nonblocking opens:<br />

Otherwise, the behavior of O_NONBLOCK is unspecified.<br />

Once the file is open, programmers can use the POSIX lstat() and fstat() functions to obtain<br />

information about a file and the S_ISREG() macro to determine if the file is a regular file.<br />

Because the behavior of O_NONBLOCK on subsequent calls to read() or write() is unspecified,<br />

it is advisable to disable the flag after it has been determined that the file in question is not a special<br />

device.<br />

When available (Linux 2.1.126+, FreeBSD, Solaris 10, POSIX.1-2008), the O_NOFOLLOW flag<br />

should also be used. (See POS01-C. Check for the existence of links when dealing with files.)<br />

When O_NOFOLLOW is not available, symbolic link checks should use the method from POS35-C.<br />

Avoid race conditions while checking for the existence of a symbolic link.<br />

#include <br />

#include <br />

#include <br />

#include <br />

#ifdef O_NOFOLLOW<br />

#define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK<br />

#else<br />

#define OPEN_FLAGS O_NONBLOCK<br />

#endif<br />

void func(const char *file_name) {<br />

struct stat orig_st;<br />

struct stat open_st;<br />

int fd;<br />

int flags;<br />

if ((lstat(file_name, &orig_st) != 0) ||<br />

(!S_ISREG(orig_st.st_mode))) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 286<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

}<br />

/* Race window */<br />

fd = open(file_name, OPEN_FLAGS | O_WRONLY);<br />

if (fd == -1) {<br />

/* Handle error */<br />

}<br />

if (fstat(fd, &open_st) != 0) {<br />

/* Handle error */<br />

}<br />

if ((orig_st.st_mode != open_st.st_mode) ||<br />

(orig_st.st_ino != open_st.st_ino) ||<br />

(orig_st.st_dev != open_st.st_dev)) {<br />

/* The file was tampered with */<br />

}<br />

/*<br />

* Optional: drop the O_NONBLOCK now that we are sure<br />

* this is a good file.<br />

*/<br />

if ((flags = fcntl(fd, F_GETFL)) == -1) {<br />

/* Handle error */<br />

}<br />

if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) {<br />

/* Handle error */<br />

}<br />

/* Operate on the file */<br />

}<br />

if (close(fd) == -1) {<br />

/* Handle error */<br />

}<br />

This code contains an intractable TOCTOU (time-of-check, time-of-use) race condition under<br />

which an attacker can alter the file referenced by file_name following the call to lstat() but<br />

before the call to open(). The switch will be discovered after the file is opened, but opening the<br />

file cannot be prevented in the case where this action itself causes undesired behavior. (See<br />

FIO45-C. Avoid TOCTOU race conditions while accessing files for more information about<br />

TOCTOU race conditions.)<br />

Essentially, an attacker can switch out a file for one of the file types shown in the following table<br />

with the specified effect.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 287<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

File Types and Effects<br />

Type<br />

Another regular file<br />

FIFO<br />

Symbolic link<br />

Special device<br />

Note on Effect<br />

The fstat() verification fails.<br />

Either open() returns -1 and sets errno to<br />

ENXIO, or open() succeeds and the fstat()<br />

verification fails.<br />

open() returns -1 if O_NOFOLLOW is available;<br />

otherwise, the fstat() verification fails.<br />

Usually the fstat() verification fails on st_mode.<br />

This can still be a problem if the device is one for<br />

which just opening (or closing) it causes a side effect.<br />

If st_mode compares equal, then the device is one<br />

that, after opening, appears to be a regular file. It<br />

would then fail the fstat() verification on<br />

st_dev and st_ino (unless it happens to be the<br />

same file, as can happen with /dev/fd/* on Solaris,<br />

but this would not be a problem).<br />

To be compliant with this rule and to prevent this TOCTOU race condition, file_name must refer<br />

to a file in a secure directory. (See FIO15-C. Ensure that file operations are performed in a secure<br />

directory.)<br />

10.2.3 Noncompliant Code Example (Windows)<br />

This noncompliant code example uses the GetFileType() function to attempt to prevent opening<br />

a special file:<br />

#include <br />

void func(const TCHAR *file_name) {<br />

HANDLE hFile = CreateFile(<br />

file_name,<br />

GENERIC_READ | GENERIC_WRITE, 0,<br />

NULL, OPEN_EXISTING,<br />

FILE_ATTRIBUTE_NORMAL, NULL<br />

);<br />

if (hFile == INVALID_HANDLE_VALUE) {<br />

/* Handle error */<br />

} else if (GetFileType(hFile) != FILE_TYPE_DISK) {<br />

/* Handle error */<br />

CloseHandle(hFile);<br />

} else {<br />

/* Operate on the file */<br />

CloseHandle(hFile);<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 288<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

Although tempting, the Win32 GetFileType() function is dangerous in this case. If the file<br />

name given identifies a named pipe that is currently blocking on a read request, the call to Get-<br />

FileType() will block until the read request completes. This provides an effective attack vector<br />

for a denial-of-service attack on the application. Furthermore, the act of opening a file handle may<br />

cause side effects, such as line states being set to their default voltage when opening a serial device.<br />

10.2.4 Compliant Solution (Windows)<br />

Microsoft documents a list of reserved identifiers that represent devices and have a device<br />

namespace to be used specifically by devices [MSDN]. In this compliant solution, the<br />

isReservedName() function can be used to determine if a specified path refers to a device. Care<br />

must be taken to avoid a TOCTOU race condition when first testing a path name using the<br />

isReservedName() function and then later operating on that path name.<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

static bool isReservedName(const char *path) {<br />

/* This list of reserved names comes from MSDN */<br />

static const char *reserved[] = {<br />

"nul", "con", "prn", "aux", "com1", "com2", "com3",<br />

"com4", "com5", "com6", "com7", "com8", "com9",<br />

"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6",<br />

"lpt7", "lpt8", "lpt9"<br />

};<br />

bool ret = false;<br />

/*<br />

* First, check to see if this is a device namespace, which<br />

* always starts with \\.\, because device namespaces are not<br />

* valid file paths.<br />

*/<br />

if (!path || 0 == strncmp(path, "\\\\.\\", 4)) {<br />

return true;<br />

}<br />

/* Compare against the list of ancient reserved names */<br />

for (size_t i = 0; !ret &&<br />

i < sizeof(reserved) / sizeof(*reserved); ++i) {<br />

/*<br />

* Because Windows uses a case-insensitive file system, operate<br />

on<br />

* a lowercase version of the given filename. Note: This ignores<br />

* globalization issues and assumes ASCII characters.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 289<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO32-C. Do not perform operations on devices that are only appropriate for files<br />

}<br />

*/<br />

if (0 == _stricmp(path, reserved[i])) {<br />

ret = true;<br />

}<br />

}<br />

return ret;<br />

10.2.5 Risk Assessment<br />

Allowing operations that are appropriate only for regular files to be performed on devices can result<br />

in denial-of-service attacks or more serious exploits depending on the platform.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO32-C Medium Unlikely Medium P4 L3<br />

10.2.6 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

FIO05-C. Identify files using multiple file attributes<br />

FIO15-C. Ensure that file operations are performed<br />

in a secure directory<br />

POS01-C. Check for the existence of links<br />

when dealing with files<br />

POS35-C. Avoid race conditions while checking<br />

for the existence of a symbolic link<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java FIO00-J. Do not operate on files in shared directories<br />

MITRE CWE<br />

CWE-67, Improper Handling of Windows Device<br />

Names<br />

10.2.7 Bibliography<br />

[Garfinkel 1996]<br />

[Howard 2002]<br />

[IEEE Std 1003.1:2013]<br />

[MSDN]<br />

Section 5.6, “Device Files”<br />

Chapter 11, “Canonical Representation Issues”<br />

XSH, System Interfaces, open<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 290<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO34-C. Distinguish between characters read from a file and EOF or WEOF<br />

10.3 FIO34-C. Distinguish between characters read from a file and EOF<br />

or WEOF<br />

The EOF macro represents a negative value that is used to indicate that the file is exhausted and no<br />

data remains when reading data from a file. EOF is an example of an in-band error indicator. Inband<br />

error indicators are problematic to work with, and the creation of new in-band-error indicators<br />

is discouraged by ERR02-C. Avoid in-band error indicators.<br />

The byte I/O functions fgetc(), getc(), and getchar() all read a character from a stream and<br />

return it as an int. (See STR00-C. Represent characters using an appropriate type.) If the stream<br />

is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF.<br />

If a read error occurs, the error indicator for the stream is set and the function returns EOF. If these<br />

functions succeed, they cast the character returned into an unsigned char.<br />

Because EOF is negative, it should not match any unsigned character value. However, this is only<br />

true for implementations where the int type is wider than char. On an implementation where<br />

int and char have the same width, a character-reading function can read and return a valid character<br />

that has the same bit-pattern as EOF. This could occur, for example, if an attacker inserted a<br />

value that looked like EOF into the file or data stream to alter the behavior of the program.<br />

The C <strong>Standard</strong> requires only that the int type be able to represent a maximum value of +32767<br />

and that a char type be no larger than an int. Although uncommon, this situation can result in<br />

the integer constant expression EOF being indistinguishable from a valid character; that is,<br />

(int)(unsigned char)65535 == -1. Consequently, failing to use feof() and ferror() to<br />

detect end-of-file and file errors can result in incorrectly identifying the EOF character on rare implementations<br />

where sizeof(int) == sizeof(char).<br />

This problem is much more common when reading wide characters. The fgetwc(), getwc(),<br />

and getwchar() functions return a value of type wint_t. This value can represent the next wide<br />

character read, or it can represent WEOF, which indicates end-of-file for wide character streams.<br />

On most implementations, the wchar_t type has the same width as wint_t, and these functions<br />

can return a character indistinguishable from WEOF.<br />

In the UTF-16 character set, 0xFFFF is guaranteed not to be a character, which allows WEOF to be<br />

represented as the value -1. Similarly, all UTF-32 characters are positive when viewed as a<br />

signed 32-bit integer. All widely used character sets are designed with at least one value that does<br />

not represent a character. Consequently, it would require a custom character set designed without<br />

consideration of the C programming language for this problem to occur with wide characters or<br />

with ordinary characters that are as wide as int.<br />

The C <strong>Standard</strong> feof() and ferror() functions are not subject to the problems associated with<br />

character and integer sizes and should be used to verify end-of-file and file errors for susceptible<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 291<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO34-C. Distinguish between characters read from a file and EOF or WEOF<br />

implementations [Kettlewell 2002]. Calling both functions on each iteration of a loop adds significant<br />

overhead, so a good strategy is to temporarily trust EOF and WEOF within the loop but verify<br />

them with feof() and ferror() following the loop.<br />

10.3.1 Noncompliant Code Example<br />

This noncompliant code example loops while the character c is not EOF:<br />

#include <br />

void func(void) {<br />

int c;<br />

}<br />

do {<br />

c = getchar();<br />

} while (c != EOF);<br />

Although EOF is guaranteed to be negative and distinct from the value of any unsigned character,<br />

it is not guaranteed to be different from any such value when converted to an int. Consequently,<br />

when int has the same width as char, this loop may terminate prematurely.<br />

10.3.2 Compliant Solution (Portable)<br />

This compliant solution uses feof() to test for end-of-file and ferror() to test for errors:<br />

#include <br />

void func(void) {<br />

int c;<br />

}<br />

do {<br />

c = getchar();<br />

} while (c != EOF);<br />

if (feof(stdin)) {<br />

/* Handle end of file */<br />

} else if (ferror(stdin)) {<br />

/* Handle file error */<br />

} else {<br />

/* Received a character that resembles EOF; handle error */<br />

}<br />

10.3.3 Noncompliant Code Example (Nonportable)<br />

This noncompliant code example uses an assertion to ensure that the code is executed only on architectures<br />

where int is wider than char and EOF is guaranteed not to be a valid character value.<br />

However, this code example is noncompliant because the variable c is declared as a char rather<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 292<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO34-C. Distinguish between characters read from a file and EOF or WEOF<br />

than an int, making it possible for a valid character value to compare equal to the value of the<br />

EOF macro when char is signed because of sign extension:<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char c;<br />

static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation");<br />

}<br />

do {<br />

c = getchar();<br />

} while (c != EOF);<br />

Assuming that a char is a signed 8-bit type and an int is a 32-bit type, if getchar() returns the<br />

character value '\xff (decimal 255), it will be interpreted as EOF because this value is sign-extended<br />

to 0xFFFFFFFF (the value of EOF) to perform the comparison. (See STR34-C. Cast characters<br />

to unsigned char before converting to larger integer sizes.)<br />

10.3.4 Compliant Solution (Nonportable)<br />

This compliant solution declares c to be an int. Consequently, the loop will terminate only when<br />

the file is exhausted.<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

int c;<br />

static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation");<br />

}<br />

do {<br />

c = getchar();<br />

} while (c != EOF);<br />

10.3.5 Noncompliant Code Example (Wide Characters)<br />

In this noncompliant example, the result of the call to the C standard library function getwc() is<br />

stored into a variable of type wchar_t and is subsequently compared with WEOF:<br />

#include <br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 293<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO34-C. Distinguish between characters read from a file and EOF or WEOF<br />

enum { BUFFER_SIZE = 32 };<br />

void g(void) {<br />

wchar_t buf[BUFFER_SIZE];<br />

wchar_t wc;<br />

size_t i = 0;<br />

}<br />

while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) {<br />

if (i < (BUFFER_SIZE - 1)) {<br />

buf[i++] = wc;<br />

}<br />

}<br />

buf[i] = L'\0';<br />

This code suffers from two problems. First, the value returned by getwc() is immediately converted<br />

to wchar_t before being compared with WEOF. Second, there is no check to ensure that<br />

wint_t is wider than wchar_t. Both of these problems make it possible for an attacker to terminate<br />

the loop prematurely by supplying the wide-character value matching WEOF in the file.<br />

10.3.6 Compliant Solution (Portable)<br />

This compliant solution declares c to be a wint_t to match the integer type returned by<br />

getwc(). Furthermore, it does not rely on WEOF to determine end-of-file definitively.<br />

#include <br />

#include <br />

#include <br />

enum {BUFFER_SIZE = 32 }<br />

void g(void) {<br />

wchar_t buf[BUFFER_SIZE];<br />

wint_t wc;<br />

size_t i = 0;<br />

while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) {<br />

if (i < BUFFER_SIZE - 1) {<br />

buf[i++] = wc;<br />

}<br />

}<br />

if (feof(stdin) || ferror(stdin)) {<br />

buf[i] = L'\0';<br />

} else {<br />

/* Received a wide character that resembles WEOF; handle error<br />

*/<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 294<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO34-C. Distinguish between characters read from a file and EOF or WEOF<br />

10.3.7 Exceptions<br />

FIO34-C-EX1: A number of C functions do not return characters but can return EOF as a status<br />

code. These functions include fclose(), fflush(), fputs(), fscanf(), puts(), scanf(),<br />

sscanf(), vfscanf(), and vscanf(). These return values can be compared to EOF without<br />

validating the result.<br />

10.3.8 Risk Assessment<br />

Incorrectly assuming characters from a file cannot match EOF or WEOF has resulted in significant<br />

vulnerabilities, including command injection attacks. (See the *CA-1996-22 advisory.)<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO34-C High Probable Medium P12 L1<br />

10.3.9 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

STR00-C. Represent characters using an appropriate<br />

type<br />

INT31-C. Ensure that integer conversions do<br />

not result in lost or misinterpreted data<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java FIO08-J. Use an int to capture the return value<br />

of methods that read a character or byte<br />

ISO/IEC TS 17961:2013<br />

Using character values that are indistinguishable<br />

from EOF [chreof]<br />

10.3.10 Bibliography<br />

[Kettlewell 2002]<br />

[NIST 2006]<br />

[Summit 2005] Question 12.2<br />

Section 1.2, “ and Character<br />

Types”<br />

SAMATE Reference Dataset Test Case ID<br />

000-000-088<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 295<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when successful<br />

10.4 FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty<br />

string when successful<br />

Errors can occur when incorrect assumptions are made about the type of data being read. These<br />

assumptions may be violated, for example, when binary data has been read from a file instead of<br />

text from a user’s terminal or the output of a process is piped to stdin. (See FIO14-C. Understand<br />

the difference between text mode and binary mode with file streams.) On some systems, it<br />

may also be possible to input a null byte (as well as other binary codes) from the keyboard.<br />

Subclause 7.21.7.2 of the C <strong>Standard</strong> [ISO/IEC 9899:2011] says,<br />

The fgets function returns s if successful. If end-of-file is encountered and no characters<br />

have been read into the array, the contents of the array remain unchanged and a<br />

null pointer is returned.<br />

The wide-character function fgetws() has the same behavior. Therefore, if fgets() or<br />

fgetws() returns a non-null pointer, it is safe to assume that the array contains data. However, it<br />

is erroneous to assume that the array contains a nonempty string because the data may contain<br />

null characters.<br />

10.4.1 Noncompliant Code Example<br />

This noncompliant code example attempts to remove the trailing newline (\n) from an input line.<br />

The fgets() function is typically used to read a newline-terminated line of input from a stream.<br />

It takes a size parameter for the destination buffer and copies, at most, size - 1 characters from<br />

a stream to a character array.<br />

#include <br />

#include <br />

enum { BUFFER_SIZE = 1024 };<br />

void func(void) {<br />

char buf[BUFFER_SIZE];<br />

}<br />

if (fgets(buf, sizeof(buf), stdin) == NULL) {<br />

/* Handle error */<br />

}<br />

buf[strlen(buf) - 1] = '\0';<br />

The strlen() function computes the length of a string by determining the number of characters<br />

that precede the terminating null character. A problem occurs if the first character read from the<br />

input by fgets() happens to be a null character. This may occur, for example, if a binary data<br />

file is read by the fgets() call [Lai 2006]. If the first character in buf is a null character,<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 296<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when successful<br />

strlen(buf) returns 0, the expression strlen(buf) - 1 wraps around to a large positive<br />

value, and a write-outside-array-bounds error occurs.<br />

10.4.2 Compliant Solution<br />

This compliant solution uses strchr() to replace the newline character in the string if it exists:<br />

#include <br />

#include <br />

enum { BUFFER_SIZE = 1024 };<br />

void func(void) {<br />

char buf[BUFFER_SIZE];<br />

char *p;<br />

}<br />

if (fgets(buf, sizeof(buf), stdin)) {<br />

p = strchr(buf, '\n');<br />

if (p) {<br />

*p = '\0';<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

10.4.3 Risk Assessment<br />

Incorrectly assuming that character data has been read can result in an out-of-bounds memory<br />

write or other flawed logic.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO37-C High Probable Medium P12 L1<br />

10.4.4 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

MITRE CWE<br />

FIO14-C. Understand the difference between<br />

text mode and binary mode with file streams<br />

FIO20-C. Avoid unintentional truncation when<br />

using fgets() or fgetws()<br />

CWE-119, Improper Restriction of Operations<br />

within the Bounds of a Memory Buffer<br />

CWE-123, Write-what-where Condition<br />

CWE-125, Out-of-bounds Read<br />

CWE-241, Improper Handling of Unexpected<br />

Data Type<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 297<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when successful<br />

10.4.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Lai 2006]<br />

[Seacord 2013]<br />

Subclause 7.21.7.2, “The fgets Function”<br />

Subclause 7.29.3.2, “The fgetws Function”<br />

Chapter 2, “Strings”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 298<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO38-C. Do not copy a FILE object<br />

10.5 FIO38-C. Do not copy a FILE object<br />

According to the C <strong>Standard</strong>, 7.21.3, paragraph 6 [ISO/IEC 9899:2011],<br />

The address of the FILE object used to control a stream may be significant; a copy of a<br />

FILE object need not serve in place of the original.<br />

Consequently, do not copy a FILE object.<br />

10.5.1 Noncompliant Code Example<br />

This noncompliant code example can fail because a by-value copy of stdout is being used in the<br />

call to fputs():<br />

#include <br />

int main(void) {<br />

FILE my_stdout = *stdout;<br />

if (fputs("Hello, World!\n", &my_stdout) == EOF) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

When compiled under Microsoft Visual Studio 2013 and run on Windows, this noncompliant example<br />

results in an “access violation” at runtime.<br />

10.5.2 Compliant Solution<br />

In this compliant solution, a copy of the stdout pointer to the FILE object is used in the call to<br />

fputs():<br />

#include <br />

int main(void) {<br />

FILE *my_stdout = stdout;<br />

if (fputs("Hello, World!\n", my_stdout) == EOF) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 299<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO38-C. Do not copy a FILE object<br />

10.5.3 Risk Assessment<br />

Using a copy of a FILE object in place of the original may result in a crash, which can be used in<br />

a denial-of-service attack.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO38-C Low Probable Medium P4 L3<br />

10.5.4 Related Guidelines<br />

ISO/IEC TS 17961:2013<br />

Copying a FILE object [filecpy]<br />

10.5.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.21.3, “Files”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 300<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning<br />

call<br />

10.6 FIO39-C. Do not alternately input and output from a stream without<br />

an intervening flush or positioning call<br />

The C <strong>Standard</strong>, 7.21.5.3, paragraph 7 [ISO/IEC 9899:2011], places the following restrictions on<br />

update streams:<br />

When a file is opened with update mode . . ., both input and output may be performed on<br />

the associated stream. However, output shall not be directly followed by input without an<br />

intervening call to the fflush function or to a file positioning function (fseek, fsetpos,<br />

or rewind), and input shall not be directly followed by output without an intervening call<br />

to a file positioning function, unless the input operation encounters end-of-file. Opening<br />

(or creating) a text file with update mode may instead open (or create) a binary stream in<br />

some implementations.<br />

The following scenarios can result in undefined behavior. (See undefined behavior 151.)<br />

• Receiving input from a stream directly following an output to that stream without an intervening<br />

call to fflush(), fseek(), fsetpos(), or rewind() if the file is not at end-of-file<br />

• Outputting to a stream after receiving input from that stream without a call to fseek(),<br />

fsetpos(), or rewind() if the file is not at end-of-file<br />

Consequently, a call to fseek(), fflush(), or fsetpos() is necessary between input and output<br />

to the same stream. See ERR07-C. Prefer functions that support error checking over equivalent<br />

functions that don’t for more information on why fseek() is preferred over rewind().<br />

10.6.1 Noncompliant Code Example<br />

This noncompliant code example appends data to a file and then reads from the same file:<br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

extern void initialize_data(char *data, size_t size);<br />

void func(const char *file_name) {<br />

char data[BUFFERSIZE];<br />

char append_data[BUFFERSIZE];<br />

FILE *file;<br />

file = fopen(file_name, "a+");<br />

if (file == NULL) {<br />

/* Handle error */<br />

}<br />

initialize_data(append_data, BUFFERSIZE);<br />

if (fwrite(append_data, 1, BUFFERSIZE, file) != BUFFERSIZE) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 301<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning<br />

call<br />

/* Handle error */<br />

}<br />

if (fread(data, 1, BUFFERSIZE, file) < BUFFERSIZE) {<br />

/* Handle there not being data */<br />

}<br />

}<br />

if (fclose(file) == EOF) {<br />

/* Handle error */<br />

}<br />

Because there is no intervening flush or positioning call between the calls to fread() and<br />

fwrite(), the behavior is undefined.<br />

10.6.2 Compliant Solution<br />

In this compliant solution, fseek() is called between the output and input, eliminating the undefined<br />

behavior:<br />

#include <br />

enum { BUFFERSIZE = 32 };<br />

extern void initialize_data(char *data, size_t size);<br />

void func(const char *file_name) {<br />

char data[BUFFERSIZE];<br />

char append_data[BUFFERSIZE];<br />

FILE *file;<br />

file = fopen(file_name, "a+");<br />

if (file == NULL) {<br />

/* Handle error */<br />

}<br />

initialize_data(append_data, BUFFERSIZE);<br />

if (fwrite(append_data, BUFFERSIZE, 1, file) != BUFFERSIZE) {<br />

/* Handle error */<br />

}<br />

if (fseek(file, 0L, SEEK_SET) != 0) {<br />

/* Handle error */<br />

}<br />

if (fread(data, BUFFERSIZE, 1, file) != 0) {<br />

/* Handle there not being data */<br />

}<br />

if (fclose(file) == EOF) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 302<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning<br />

call<br />

}<br />

}<br />

10.6.3 Risk Assessment<br />

Alternately inputting and outputting from a stream without an intervening flush or positioning call<br />

is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO39-C Low Likely Medium P6 L2<br />

10.6.4 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

FIO50-CPP. Do not alternately input and output<br />

from a file stream without an intervening<br />

positioning call<br />

Interleaving stream inputs and outputs without<br />

a flush or positioning call [ioileave]<br />

10.6.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.21.5.3, “The fopen Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 303<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO40-C. Reset strings on fgets() or fgetws() failure<br />

10.7 FIO40-C. Reset strings on fgets() or fgetws() failure<br />

If either of the C <strong>Standard</strong> fgets() or fgetws() functions fail, the contents of the array being<br />

written is indeterminate. (See undefined behavior 170.) It is necessary to reset the string to a<br />

known value to avoid errors on subsequent string manipulation functions.<br />

10.7.1 Noncompliant Code Example<br />

In this noncompliant code example, an error flag is set if fgets() fails. However, buf is not reset<br />

and has indeterminate contents:<br />

#include <br />

enum { BUFFER_SIZE = 1024 };<br />

void func(FILE *file) {<br />

char buf[BUFFER_SIZE];<br />

}<br />

if (fgets(buf, sizeof(buf), file) == NULL) {<br />

/* Set error flag and continue */<br />

}<br />

10.7.2 Compliant Solution<br />

In this compliant solution, buf is set to an empty string if fgets() fails. The equivalent solution<br />

for fgetws() would set buf to an empty wide string.<br />

#include <br />

enum { BUFFER_SIZE = 1024 };<br />

void func(FILE *file) {<br />

char buf[BUFFER_SIZE];<br />

}<br />

if (fgets(buf, sizeof(buf), file) == NULL) {<br />

/* Set error flag and continue */<br />

*buf = '\0';<br />

}<br />

10.7.3 Exceptions<br />

FIO40-C-EX1: If the string goes out of scope immediately following the call to fgets() or<br />

fgetws() or is not referenced in the case of a failure, it need not be reset.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 304<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO40-C. Reset strings on fgets() or fgetws() failure<br />

10.7.4 Risk Assessment<br />

Making invalid assumptions about the contents of an array modified by fgets() or fgetws()<br />

can result in undefined behavior and abnormal program termination.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO40-C Low Probable Medium P4 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 305<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects<br />

10.8 FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream<br />

argument that has side effects<br />

Do not invoke getc() or putc() or their wide-character analogues getwc() and putwc() with<br />

a stream argument that has side effects. The stream argument passed to these macros may be evaluated<br />

more than once if these functions are implemented as unsafe macros. (See PRE31-C. Avoid<br />

side effects in arguments to unsafe macros for more information.)<br />

This rule does not apply to the character argument in putc() or the wide-character argument in<br />

putwc(), which is guaranteed to be evaluated exactly once.<br />

10.8.1 Noncompliant Code Example (getc())<br />

This noncompliant code example calls the getc() function with an expression as the stream argument.<br />

If getc() is implemented as a macro, the file may be opened multiple times. (See<br />

FIO24-C. Do not open a file that is already open.)<br />

#include <br />

void func(const char *file_name) {<br />

FILE *fptr;<br />

int c = getc(fptr = fopen(file_name, "r"));<br />

if (feof(stdin) || ferror(stdin)) {<br />

/* Handle error */<br />

}<br />

}<br />

if (fclose(fptr) == EOF) {<br />

/* Handle error */<br />

}<br />

This noncompliant code example also violates ERR33-C. Detect and handle standard library errors<br />

because the value returned by fopen() is not checked for errors.<br />

10.8.2 Compliant Solution (getc())<br />

In this compliant solution, fopen() is called before getc() and its return value is checked for<br />

errors:<br />

#include <br />

void func(const char *file_name) {<br />

int c;<br />

FILE *fptr;<br />

fptr = fopen(file_name, "r");<br />

if (fptr == NULL) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 306<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects<br />

}<br />

/* Handle error */<br />

c = getc(fptr);<br />

if (c == EOF) {<br />

/* Handle error */<br />

}<br />

}<br />

if (fclose(fptr) == EOF) {<br />

/* Handle error */<br />

}<br />

10.8.3 Noncompliant Code Example (putc())<br />

In this noncompliant example, putc() is called with an expression as the stream argument. If<br />

putc() is implemented as a macro, this expression might be evaluated multiple times.<br />

#include <br />

void func(const char *file_name) {<br />

FILE *fptr = NULL;<br />

int c = 'a';<br />

while (c


Input/Output (FIO) - FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects<br />

10.8.4 Compliant Solution (putc())<br />

In this compliant solution, the stream argument to putc() no longer has side effects:<br />

#include <br />

void func(const char *file_name) {<br />

int c = 'a';<br />

FILE *fptr = fopen(file_name, "w");<br />

if (fptr == NULL) {<br />

/* Handle error */<br />

}<br />

while (c


Input/Output (FIO) - FIO42-C. Close files when they are no longer needed<br />

10.9 FIO42-C. Close files when they are no longer needed<br />

A call to the fopen() or freopen() function must be matched with a call to fclose() before<br />

the lifetime of the last pointer that stores the return value of the call has ended or before normal<br />

program termination, whichever occurs first.<br />

In general, this rule should also be applied to other functions with open and close resources, such<br />

as the POSIX open() and close() functions, or the Microsoft Windows CreateFile() and<br />

CloseHandle() functions.<br />

10.9.1 Noncompliant Code Example<br />

This code example is noncompliant because the file opened by the call to fopen() is not closed<br />

before function func() returns:<br />

#include <br />

int func(const char *filename) {<br />

FILE *f = fopen(filename, "r");<br />

if (NULL == f) {<br />

return -1;<br />

}<br />

/* ... */<br />

return 0;<br />

}<br />

10.9.2 Compliant Solution<br />

In this compliant solution, the file pointed to by f is closed before returning to the caller:<br />

#include <br />

int func(const char *filename) {<br />

FILE *f = fopen(filename, "r");<br />

if (NULL == f) {<br />

return -1;<br />

}<br />

/* ... */<br />

if (fclose(f) == EOF) {<br />

return -1;<br />

}<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 309<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO42-C. Close files when they are no longer needed<br />

10.9.3 Noncompliant Code Example (exit())<br />

This code example is noncompliant because the resource allocated by the call to fopen() is not<br />

closed before the program terminates. Although exit() closes the file, the program has no way<br />

of determining if an error occurs while flushing or closing the file.<br />

#include <br />

#include <br />

int main(void) {<br />

FILE *f = fopen(filename, "w");<br />

if (NULL == f) {<br />

exit(EXIT_FAILURE);<br />

}<br />

/* ... */<br />

exit(EXIT_SUCCESS);<br />

}<br />

10.9.4 Compliant Solution (exit())<br />

In this compliant solution, the program closes f explicitly before calling exit(), allowing any<br />

error that occurs when flushing or closing the file to be handled appropriately:<br />

#include <br />

#include <br />

int main(void) {<br />

FILE *f = fopen(filename, "w");<br />

if (NULL == f) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

if (fclose(f) == EOF) {<br />

/* Handle error */<br />

}<br />

exit(EXIT_SUCCESS);<br />

}<br />

10.9.5 Noncompliant Code Example (POSIX)<br />

This code example is noncompliant because the resource allocated by the call to open() is not<br />

closed before function func() returns:<br />

#include <br />

#include <br />

int func(const char *filename) {<br />

int fd = open(filename, O_RDONLY, S_IRUSR);<br />

if (-1 == fd) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 310<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO42-C. Close files when they are no longer needed<br />

}<br />

return -1<br />

}<br />

/* ... */<br />

return 0;<br />

10.9.6 Compliant Solution (POSIX)<br />

In this compliant solution, fd is closed before returning to the caller:<br />

#include <br />

#include <br />

#include <br />

int func(const char *filename) {<br />

int fd = open(filename, O_RDONLY, S_IRUSR);<br />

if (-1 == fd) {<br />

return -1<br />

}<br />

/* ... */<br />

if (-1 == close(fd)) {<br />

return -1;<br />

}<br />

return 0;<br />

}<br />

10.9.7 Noncompliant Code Example (Windows)<br />

In this noncompliant code example, the file opened by the Microsoft Windows CreateFile() function<br />

is not closed before func() returns:<br />

#include <br />

int func(LPCTSTR filename) {<br />

HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL,<br />

OPEN_EXISTING,<br />

FILE_ATTRIBUTE_NORMAL, NULL);<br />

if (INVALID_HANDLE_VALUE == hFile) {<br />

return -1;<br />

}<br />

/* ... */<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 311<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO42-C. Close files when they are no longer needed<br />

10.9.8 Compliant Solution (Windows)<br />

In this compliant solution, hFile is closed by invoking the CloseHandle() function before returning<br />

to the caller:<br />

#include <br />

int func(LPCTSTR filename) {<br />

HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL,<br />

OPEN_EXISTING,<br />

FILE_ATTRIBUTE_NORMAL, NULL);<br />

if (INVALID_HANDLE_VALUE == hFile) {<br />

return -1;<br />

}<br />

/* ... */<br />

if (!CloseHandle(hFile)) {<br />

return -1;<br />

}<br />

}<br />

return 0;<br />

10.9.9 Risk Assessment<br />

Failing to properly close files may allow an attacker to exhaust system resources and can increase<br />

the risk that data written into in-memory file buffers will not be flushed in the event of abnormal<br />

program termination.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO42-C Medium Unlikely Medium P4 L3<br />

10.9.10 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

FIO51-CPP. Close files when they are no<br />

longer needed<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java FIO04-J. Release resources when they are no<br />

longer needed<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

Failing to close files or free dynamic memory<br />

when they are no longer needed [fileclose]<br />

CWE-404, Improper Resource Shutdown or<br />

Release<br />

10.9.11 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

XSH, System Interfaces, open<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 312<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO44-C. Only use values for fsetpos() that are returned from fgetpos()<br />

10.10 FIO44-C. Only use values for fsetpos() that are returned from<br />

fgetpos()<br />

The C <strong>Standard</strong>, 7.21.9.3 [ISO/IEC 9899:2011], defines the following behavior for fsetpos():<br />

The fsetpos function sets the mbstate_t object (if any) and file position indicator for<br />

the stream pointed to by stream according to the value of the object pointed to by pos,<br />

which shall be a value obtained from an earlier successful call to the fgetpos function<br />

on a stream associated with the same file.<br />

Invoking the fsetpos() function with any other values for pos is undefined behavior.<br />

10.10.1 Noncompliant Code Example<br />

This noncompliant code example attempts to read three values from a file and then set the file position<br />

pointer back to the beginning of the file:<br />

#include <br />

#include <br />

int opener(FILE *file) {<br />

int rc;<br />

fpos_t offset;<br />

memset(&offset, 0, sizeof(offset));<br />

if (file == NULL) {<br />

return -1;<br />

}<br />

/* Read in data from file */<br />

rc = fsetpos(file, &offset);<br />

if (rc != 0 ) {<br />

return rc;<br />

}<br />

}<br />

return 0;<br />

Only the return value of an fgetpos() call is a valid argument to fsetpos(); passing a value of<br />

type fpos_t that was created in any other way is undefined behavior.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 313<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO44-C. Only use values for fsetpos() that are returned from fgetpos()<br />

10.10.2 Compliant Solution<br />

In this compliant solution, the initial file position indicator is stored by first calling fgetpos(),<br />

which is used to restore the state to the beginning of the file in the later call to fsetpos():<br />

#include <br />

#include <br />

int opener(FILE *file) {<br />

int rc;<br />

fpos_t offset;<br />

if (file == NULL) {<br />

return -1;<br />

}<br />

rc = fgetpos(file, &offset);<br />

if (rc != 0 ) {<br />

return rc;<br />

}<br />

/* Read in data from file */<br />

rc = fsetpos(file, &offset);<br />

if (rc != 0 ) {<br />

return rc;<br />

}<br />

}<br />

return 0;<br />

10.10.3 Risk Assessment<br />

Misuse of the fsetpos() function can position a file position indicator to an unintended location<br />

in the file.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO44-C Medium Unlikely Medium P4 L3<br />

10.10.4 Related Guidelines<br />

ISO/IEC TS 17961:2013<br />

Using a value for fsetpos other than a value returned<br />

from fgetpos [xfilepos]<br />

10.10.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.21.9.3, “The fsetpos Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 314<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO45-C. Avoid TOCTOU race conditions while accessing files<br />

10.11 FIO45-C. Avoid TOCTOU race conditions while accessing files<br />

A TOCTOU (time-of-check, time-of-use) race condition is possible when two or more concurrent<br />

processes are operating on a shared file system [Seacord 2013b]. Typically, the first access is a<br />

check to verify some attribute of the file, followed by a call to use the file. An attacker can alter<br />

the file between the two accesses, or replace the file with a symbolic or hard link to a different<br />

file. These TOCTOU conditions can be exploited when a program performs two or more file operations<br />

on the same file name or path name.<br />

A program that performs two or more file operations on a single file name or path name creates a<br />

race window between the two file operations. This race window comes from the assumption that<br />

the file name or path name refers to the same resource both times. If an attacker can modify the<br />

file, remove it, or replace it with a different file, then this assumption will not hold.<br />

10.11.1 Noncompliant Code Example<br />

If an existing file is opened for writing with the w mode argument, the file’s previous contents (if<br />

any) are destroyed. This noncompliant code example tries to prevent an existing file from being<br />

overwritten by first opening it for reading before opening it for writing. An attacker can exploit<br />

the race window between the two calls to fopen() to overwrite an existing file.<br />

#include <br />

void open_some_file(const char *file) {<br />

FILE *f = fopen(file, "r");<br />

if (NULL != f) {<br />

/* File exists, handle error */<br />

} else {<br />

if (fclose(f) == EOF) {<br />

/* Handle error */<br />

}<br />

f = fopen(file, "w");<br />

if (NULL == f) {<br />

/* Handle error */<br />

}<br />

}<br />

}<br />

/* Write to file */<br />

if (fclose(f) == EOF) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 315<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO45-C. Avoid TOCTOU race conditions while accessing files<br />

10.11.2 Compliant Solution<br />

This compliant solution invokes fopen() at a single location and uses the x mode of fopen(),<br />

which was added in C11. This mode causes fopen() to fail if the file exists. This check and subsequent<br />

open is performed without creating a race window. The x mode provides exclusive access<br />

to the file only if the host environment provides this support.<br />

#include <br />

void open_some_file(const char *file) {<br />

FILE *f = fopen(file, "wx")<br />

if (NULL == f) {<br />

/* Handle error */<br />

}<br />

/* Write to file */<br />

if (fclose(f) == EOF) {<br />

/* Handle error */<br />

}<br />

}<br />

10.11.3 Compliant Solution (POSIX)<br />

This compliant solution uses the O_CREAT and O_EXCL flags of POSIX’s open() function. These<br />

flags cause open() to fail if the file exists.<br />

#include <br />

#include <br />

#include <br />

void open_some_file(const char *file) {<br />

int fd = open(file, O_CREAT | O_EXCL | O_WRONLY);<br />

if (-1 != fd) {<br />

FILE *f = fdopen(fd, "w");<br />

if (NULL != f) {<br />

/* Write to file */<br />

}<br />

}<br />

if (fclose(f) == EOF) {<br />

/* Handle error */<br />

}<br />

} else {<br />

if (close(fd) == -1) {<br />

/* Handle error */<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 316<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO45-C. Avoid TOCTOU race conditions while accessing files<br />

10.11.4 Exceptions<br />

FIO45-C-EX1: TOCTOU race conditions require that the vulnerable process is more privileged<br />

than the attacker; otherwise there is nothing to be gained from a successful attack. An unprivileged<br />

process is not subject to this rule.<br />

FIO45-C-EX2: Accessing a file name or path name multiple times is permitted if the file referenced<br />

resides in a secure directory (for more information, see FIO15-C. Ensure that file operations<br />

are performed in a secure directory).<br />

FIO45-C-EX3: Accessing a file name or path name multiple times is permitted if the program<br />

can verify that every operation operates on the same file.<br />

This POSIX code example verifies that each subsequent file access operates on the same file. In<br />

POSIX, every file can be uniquely identified by using its device and i-node attributes. This code<br />

example checks that a file name refers to a regular file (and not a directory, symbolic link, or<br />

other special file) by invoking lstat(). This call also retrieves its device and i-node. The file is<br />

subsequently opened. Finally, the program verifies that the file that was opened is the same one<br />

(matching device and i-nodes) as the file that was confirmed as a regular file.<br />

#include <br />

#include <br />

int open_regular_file(char *filename, int flags) {<br />

struct stat lstat_info;<br />

struct stat fstat_info;<br />

int f;<br />

if (lstat(filename, &lstat_info) == -1) {<br />

/* File does not exist, handle error */<br />

}<br />

if (!S_ISREG(lstat_info.st_mode)) {<br />

/* File is not a regular file, handle error */<br />

}<br />

if ((f = open(filename, flags)) == -1) {<br />

/* File has disappeared, handle error */<br />

}<br />

if (fstat(f, &fstat_info) == -1) {<br />

/* Handle error */<br />

}<br />

if (lstat_info.st_ino != fstat_info.st_ino ||<br />

lstat_info.st_dev != fstat_info.st_dev) {<br />

/* Open file is not the expected regular file, handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 317<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO45-C. Avoid TOCTOU race conditions while accessing files<br />

}<br />

/* f is the expected regular open file */<br />

return f;<br />

10.11.5 Risk Assessment<br />

TOCTOU race conditions can result in unexpected behavior, including privilege escalation.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO45-C High Probable High P6 L2<br />

10.11.6 Bibliography<br />

[Seacord 2013b]<br />

Chapter 7, “Files”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 318<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO46-C. Do not access a closed file<br />

10.12 FIO46-C. Do not access a closed file<br />

Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior.<br />

(See undefined behavior 148.) Programs that close the standard streams (especially stdout<br />

but also stderr and stdin) must be careful not to use these streams in subsequent function<br />

calls, particularly those that implicitly operate on them (such as printf(), perror(), and<br />

getc()).<br />

This rule can be generalized to other file representations.<br />

10.12.1 Noncompliant Code Example<br />

In this noncompliant code example, the stdout stream is used after it is closed:<br />

#include <br />

int close_stdout(void) {<br />

if (fclose(stdout) == EOF) {<br />

return -1;<br />

}<br />

}<br />

printf("stdout successfully closed.\n");<br />

return 0;<br />

10.12.2 Compliant Solution<br />

In this compliant solution, stdout is not used again after it is closed. This must remain true for<br />

the remainder of the program, or stdout must be assigned the address of an open file object.<br />

#include <br />

int close_stdout(void) {<br />

if (fclose(stdout) == EOF) {<br />

return -1;<br />

}<br />

}<br />

fputs("stdout successfully closed.", stderr);<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 319<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO46-C. Do not access a closed file<br />

10.12.3 Risk Assessment<br />

Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO46-C Medium Unlikely Medium P4 L3<br />

10.12.4 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

XSH, System Interfaces, open<br />

Subclause 7.21.3, “Files”<br />

Subclause 7.21.5.1, “The fclose Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 320<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO47-C. Use valid format strings<br />

10.13 FIO47-C. Use valid format strings<br />

The formatted output functions (fprintf() and related functions) convert, format, and print<br />

their arguments under control of a format string. The C <strong>Standard</strong>, 7.21.6.1, paragraph 3 [ISO/IEC<br />

9899:2011], specifies<br />

The format shall be a multibyte character sequence, beginning and ending in its initial<br />

shift state. The format is composed of zero or more directives: ordinary multibyte characters<br />

(not %), which are copied unchanged to the output stream; and conversion specifications,<br />

each of which results in fetching zero or more subsequent arguments, converting<br />

them, if applicable, according to the corresponding conversion specifier, and then<br />

writing the result to the output stream.<br />

Each conversion specification is introduced by the % character followed (in order) by<br />

• Zero or more flags (in any order), which modify the meaning of the conversion specification<br />

• An optional minimum field width<br />

• An optional precision that gives the minimum number of digits to appear for certain conversion<br />

specifiers<br />

• An optional length modifier that specifies the size of the argument<br />

• A conversion specifier character that indicates the type of conversion to be applied<br />

Common mistakes in creating format strings include<br />

• Providing an incorrect number of arguments for the format string<br />

• Using invalid conversion specifiers<br />

• Using a flag character that is incompatible with the conversion specifier<br />

• Using a length modifier that is incompatible with the conversion specifier<br />

• Mismatching the argument type and conversion specifier<br />

• Using an argument of type other than int for width or precision<br />

The following table summarizes the compliance of various conversion specifications. The first<br />

column contains one or more conversion specifier characters. The next four columns consider the<br />

combination of the specifier characters with the various flags (the apostrophe ['], -, +, the space<br />

character, #, and 0). The next eight columns consider the combination of the specifier characters<br />

with the various length modifiers (h, hh, l, ll, j, z, t, and L).<br />

Valid combinations are marked with a type name; arguments matched with the conversion specification<br />

are interpreted as that type. For example, an argument matched with the specifier %hd is<br />

interpreted as a short, so short appears in the cell where d and h intersect. The last column denotes<br />

the expected types of arguments matched with the original specifier characters.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 321<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO47-C. Use valid format strings<br />

Valid and meaningful combinations are marked by the symbol (save for the length modifier columns,<br />

as described previously). Valid combinations that have no effect are labeled N/E. Using a<br />

combination marked by the symbol, using a specification not represented in the table, or using an<br />

argument of an unexpected type is undefined behavior. (See undefined behaviors 153, 155, 157,<br />

158, 161, and 162.)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 322<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO47-C. Use valid format strings<br />

Conversion<br />

Specifier<br />

Character<br />

'XSI -, +,<br />

SPACE<br />

# 0 h hh l ll j z t L Argument<br />

Type<br />

d, i short signed char long long long intmax_t size_t ptrdiff_t Signed integer<br />

o unsigned<br />

short<br />

u unsigned<br />

short<br />

x, X unsigned<br />

short<br />

unsigned<br />

char<br />

unsigned<br />

char<br />

unsigned<br />

char<br />

unsigned<br />

long<br />

unsigned<br />

long<br />

unsigned<br />

long<br />

unsigned<br />

long long<br />

unsigned<br />

long long<br />

unsigned<br />

long long<br />

uintmax_t size_t ptrdiff_t Unsigned<br />

integer<br />

uintmax_t size_t ptrdiff_t Unsigned<br />

integer<br />

uintmax_t size_t ptrdiff_t Unsigned<br />

integer<br />

f, F N/E N/E long<br />

double<br />

e, E N/E N/E long<br />

double<br />

g, G N/E N/E long<br />

double<br />

a, A N/E N/E long<br />

double<br />

double or long<br />

double<br />

double or long<br />

double<br />

double or long<br />

double<br />

double or long<br />

double<br />

c wint_t int or wint_t<br />

s NTWS NTBS or<br />

NTWS<br />

p void*<br />

n short* char* long* long long* intmax_t* size_t* ptrdiff_t* Pointer to<br />

integer<br />

CXSI wint_t<br />

SXSI NTWS<br />

% None<br />

SPACE: The space (“ “) character<br />

N/E: No effect<br />

NTBS: char* argument pointing to a null-terminated character string<br />

NTWS: wchar_t* argument pointing to a null-terminated wide character string<br />

XSI: ISO/IEC 9945-2003 XSI extension<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 323<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO47-C. Use valid format strings<br />

The formatted input functions (fscanf() and related functions) use similarly specified format<br />

strings and impose similar restrictions on their format strings and arguments.<br />

Do not supply an unknown or invalid conversion specification or an invalid combination of flag<br />

character, precision, length modifier, or conversion specifier to a formatted IO function. Likewise,<br />

do not provide a number or type of argument that does not match the argument type of the conversion<br />

specifier used in the format string.<br />

Format strings are usually string literals specified at the call site, but they need not be. However,<br />

they should not contain tainted values. (See FIO30-C. Exclude user input from format strings for<br />

more information.)<br />

10.13.1 Noncompliant Code Example<br />

Mismatches between arguments and conversion specifications may result in undefined behavior.<br />

Compilers may diagnose type mismatches in formatted output function invocations. In this noncompliant<br />

code example, the error_type argument to printf() is incorrectly matched with<br />

the s specifier rather than with the d specifier. Likewise, the error_msg argument is incorrectly<br />

matched with the d specifier instead of the s specifier. These usages result in undefined behavior.<br />

One possible result of this invocation is that printf() will interpret the error_type argument<br />

as a pointer and try to read a string from the address that error_type contains, possibly resulting<br />

in an access violation.<br />

#include <br />

void func(void) {<br />

const char *error_msg = "Resource not available to user.";<br />

int error_type = 3;<br />

/* ... */<br />

printf("Error (type %s): %d\n", error_type, error_msg);<br />

/* ... */<br />

}<br />

10.13.2 Compliant Solution<br />

This compliant solution ensures that the arguments to the printf() function match their respective<br />

conversion specifications:<br />

#include <br />

void func(void) {<br />

const char *error_msg = "Resource not available to user.";<br />

int error_type = 3;<br />

/* ... */<br />

printf("Error (type %d): %s\n", error_type, error_msg);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 324<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Input/Output (FIO) - FIO47-C. Use valid format strings<br />

}<br />

/* ... */<br />

10.13.3 Risk Assessment<br />

Incorrectly specified format strings can result in memory corruption or abnormal program termination.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

FIO47-C High Unlikely Medium P6 L2<br />

10.13.4 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

FIO00-CPP. Take care when creating format<br />

strings<br />

Using invalid format strings [invfmtstr]<br />

CWE-686, Function Call with Incorrect Argument<br />

Type<br />

10.13.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.21.6.1, “The fprintf Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 325<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV30-C. Do not modify the object referenced by the return value of certain functions<br />

11 Environment (ENV)<br />

11.1 ENV30-C. Do not modify the object referenced by the return value<br />

of certain functions<br />

Some functions return a pointer to an object that cannot be modified without causing undefined<br />

behavior. These functions include getenv(), setlocale(), localeconv(), asctime(), and<br />

strerror(). In such cases, the function call results must be treated as being const-qualified.<br />

The C <strong>Standard</strong>, 7.22.4.6, paragraph 4 [ISO/IEC 9899:2011], defines getenv() as follows:<br />

The getenv function returns a pointer to a string associated with the matched list member.<br />

The string pointed to shall not be modified by the program, but may be overwritten<br />

by a subsequent call to the getenv function. If the specified name cannot be found, a<br />

null pointer is returned.<br />

If the string returned by getenv() must be altered, a local copy should be created. Altering the<br />

string returned by getenv() is undefined behavior. (See undefined behavior 184.)<br />

Similarly, subclause 7.11.1.1, paragraph 8 [ISO/IEC 9899:2011], defines setlocale() as follows:<br />

The pointer to string returned by the setlocale function is such that a subsequent call<br />

with that string value and its associated category will restore that part of the program’s<br />

locale. The string pointed to shall not be modified by the program, but may be overwritten<br />

by a subsequent call to the setlocale function.<br />

And subclause 7.11.2.1, paragraph 8 [ISO/IEC 9899:2011], defines localeconv() as follows:<br />

The localeconv function returns a pointer to the filled-in object. The structure pointed<br />

to by the return value shall not be modified by the program, but may be overwritten by a<br />

subsequent call to the localeconv function. In addition, calls to the setlocale function<br />

with categories LC_ALL, LC_MONETARY, or LC_NUMERIC may overwrite the contents of<br />

the structure.<br />

Altering the string returned by setlocale() or the structure returned by localeconv() are undefined<br />

behaviors. (See undefined behaviors 120 and 121.) Furthermore, the C <strong>Standard</strong> imposes<br />

no requirements on the contents of the string by setlocale(). Consequently, no assumptions<br />

can be made as to the string's internal contents or structure.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 326<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV30-C. Do not modify the object referenced by the return value of certain functions<br />

Finally, subclause 7.24.6.2, paragraph 4 [ISO/IEC 9899:2011], states<br />

The strerror function returns a pointer to the string, the contents of which are localespecific.<br />

The array pointed to shall not be modified by the program, but may be overwritten<br />

by a subsequent call to the strerror function.<br />

Altering the string returned by strerror() is undefined behavior. (See undefined behavior 184.)<br />

11.1.1 Noncompliant Code Example (getenv())<br />

This noncompliant code example modifies the string returned by getenv() by replacing all double<br />

quotation marks (“) with underscores (_):<br />

#include <br />

void trstr(char *c_str, char orig, char rep) {<br />

while (*c_str != '\0') {<br />

if (*c_str == orig) {<br />

*c_str = rep;<br />

}<br />

++c_str;<br />

}<br />

}<br />

void func(void) {<br />

char *env = getenv("TEST_ENV");<br />

if (env == NULL) {<br />

/* Handle error */<br />

}<br />

trstr(env,'"', '_');<br />

}<br />

11.1.2 Compliant Solution (getenv()) (Environment Not Modified)<br />

If the programmer does not intend to modify the environment, this compliant solution demonstrates<br />

how to modify a copy of the return value:<br />

#include <br />

#include <br />

void trstr(char *c_str, char orig, char rep) {<br />

while (*c_str != '\0') {<br />

if (*c_str == orig) {<br />

*c_str = rep;<br />

}<br />

++c_str;<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 327<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV30-C. Do not modify the object referenced by the return value of certain functions<br />

void func(void) {<br />

const char *env;<br />

char *copy_of_env;<br />

env = getenv("TEST_ENV");<br />

if (env == NULL) {<br />

/* Handle error */<br />

}<br />

copy_of_env = (char *)malloc(strlen(env) + 1);<br />

if (copy_of_env == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

strcpy(copy_of_env, env);<br />

trstr(copy_of_env,'"', '_');<br />

/* ... */<br />

free(copy_of_env);<br />

11.1.3 Compliant Solution (getenv()) (Modifying the Environment in POSIX)<br />

If the programmer’s intent is to modify the environment, this compliant solution, which saves the<br />

altered string back into the environment by using the POSIX setenv() and strdup() functions,<br />

can be used:<br />

#include <br />

#include <br />

void trstr(char *c_str, char orig, char rep) {<br />

while (*c_str != '\0') {<br />

if (*c_str == orig) {<br />

*c_str = rep;<br />

}<br />

++c_str;<br />

}<br />

}<br />

void func(void) {<br />

const char *env;<br />

char *copy_of_env;<br />

env = getenv("TEST_ENV");<br />

if (env == NULL) {<br />

/* Handle error */<br />

}<br />

copy_of_env = strdup(env);<br />

if (copy_of_env == NULL) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 328<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV30-C. Do not modify the object referenced by the return value of certain functions<br />

}<br />

trstr(copy_of_env,'"', '_');<br />

}<br />

if (setenv("TEST_ENV", copy_of_env, 1) != 0) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

free(copy_of_env);<br />

11.1.4 Noncompliant Code Example (localeconv())<br />

In this noncompliant example, the object returned by localeconv() is directly modified:<br />

#include <br />

void f2(void) {<br />

struct lconv *conv = localeconv();<br />

}<br />

if ('\0' == conv->decimal_point[0]) {<br />

conv->decimal_point = ".";<br />

}<br />

11.1.5 Compliant Solution (localeconv()) (Copy)<br />

This compliant solution modifies a copy of the object returned by localeconv():<br />

#include <br />

#include <br />

#include <br />

void f2(void) {<br />

const struct lconv *conv = localeconv();<br />

if (conv == NULL) {<br />

/* Handle error */<br />

}<br />

struct lconv *copy_of_conv = (struct lconv *)malloc(<br />

sizeof(struct lconv));<br />

if (copy_of_conv == NULL) {<br />

/* Handle error */<br />

}<br />

memcpy(copy_of_conv, conv, sizeof(struct lconv));<br />

if ('\0' == copy_of_conv->decimal_point[0]) {<br />

copy_of_conv->decimal_point = ".";<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 329<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV30-C. Do not modify the object referenced by the return value of certain functions<br />

}<br />

}<br />

/* ... */<br />

free(copy_of_conv);<br />

11.1.6 Risk Assessment<br />

Modifying the object pointed to by the return value of getenv(), setlocale(), localeconv(),<br />

asctime(), or strerror() is undefined behavior. Even if the modification succeeds,<br />

the modified object can be overwritten by a subsequent call to the same function.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ENV30-C Low Probable Medium P4 L3<br />

11.1.7 Related Guidelines<br />

ISO/IEC TS 17961:2013<br />

Modifying the string returned by getenv, localeconv,<br />

setlocale, and strerror<br />

[libmod]<br />

11.1.8 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

XSH, System Interfaces, getenv<br />

XSH, System Interfaces, setlocale<br />

XSH, System Interfaces, localeconv<br />

7.11.1.1, “The setlocale Function”<br />

7.11.2.1, “The localeconv Function”<br />

7.22.4.6, “The getenv Function”<br />

7.24.6.2, “The strerror Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 330<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it<br />

11.2 ENV31-C. Do not rely on an environment pointer following an<br />

operation that may invalidate it<br />

Some implementations provide a nonportable environment pointer that is valid when main() is<br />

called but may be invalidated by operations that modify the environment.<br />

The C <strong>Standard</strong>, J.5.1 [ISO/IEC 9899:2011], states<br />

In a hosted environment, the main function receives a third argument, char *envp[],<br />

that points to a null-terminated array of pointers to char, each of which points to a string<br />

that provides information about the environment for this execution of the program.<br />

Consequently, under a hosted environment supporting this common extension, it is possible to access<br />

the environment through a modified form of main():<br />

main(int argc, char *argv[], char *envp[]){ /* ... */ }<br />

However, modifying the environment by any means may cause the environment memory to be reallocated,<br />

with the result that envp now references an incorrect location. For example, when compiled<br />

with GCC 4.8.1 and run on a 32-bit Intel GNU/Linux machine, the following code,<br />

#include <br />

#include <br />

extern char **environ;<br />

int main(int argc, const char *argv[], const char *envp[]) {<br />

printf("environ: %p\n", environ);<br />

printf("envp: %p\n", envp);<br />

setenv("MY_NEW_VAR", "new_value", 1);<br />

puts("--Added MY_NEW_VAR--");<br />

printf("environ: %p\n", environ);<br />

printf("envp: %p\n", envp);<br />

return 0;<br />

}<br />

yields<br />

% ./envp-environ<br />

environ: 0xbf8656ec<br />

envp: 0xbf8656ec<br />

--Added MY_NEW_VAR--<br />

environ: 0x804a008<br />

envp: 0xbf8656ec<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 331<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it<br />

It is evident from these results that the environment has been relocated as a result of the call to<br />

setenv(). The external variable environ is updated to refer to the current environment; the<br />

envp parameter is not.<br />

An environment pointer may also become invalidated by subsequent calls to getenv(). (See<br />

ENV34-C. Do not store pointers returned by certain functions for more information.)<br />

11.2.1 Noncompliant Code Example (POSIX)<br />

After a call to the POSIX setenv() function or to another function that modifies the environment,<br />

the envp pointer may no longer reference the current environment. The Portable Operating<br />

System Interface (POSIX®), Base Specifications, Issue 7 [IEEE Std 1003.1:2013], states<br />

Unanticipated results may occur if setenv() changes the external variable environ. In<br />

particular, if the optional envp argument to main() is present, it is not changed, and<br />

thus may point to an obsolete copy of the environment (as may any other copy of environ).<br />

This noncompliant code example accesses the envp pointer after calling setenv():<br />

#include <br />

#include <br />

int main(int argc, const char *argv[], const char *envp[]) {<br />

if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {<br />

/* Handle error */<br />

}<br />

if (envp != NULL) {<br />

for (size_t i = 0; envp[i] != NULL; ++i) {<br />

puts(envp[i]);<br />

}<br />

}<br />

return 0;<br />

}<br />

Because envp may no longer point to the current environment, this program has undefined behavior.<br />

11.2.2 Compliant Solution (POSIX)<br />

Use environ in place of envp when defined:<br />

#include <br />

#include <br />

extern char **environ;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 332<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it<br />

int main(void) {<br />

if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {<br />

/* Handle error */<br />

}<br />

if (environ != NULL) {<br />

for (size_t i = 0; environ[i] != NULL; ++i) {<br />

puts(environ[i]);<br />

}<br />

}<br />

return 0;<br />

}<br />

11.2.3 Noncompliant Code Example (Windows)<br />

After a call to the Windows _putenv_s() function or to another function that modifies the environment,<br />

the envp pointer may no longer reference the environment.<br />

According to the Visual C++ reference [MSDN]<br />

The environment block passed to main and wmain is a “frozen” copy of the current environment.<br />

If you subsequently change the environment via a call to _putenv or<br />

_wputenv, the current environment (as returned by getenv / _wgetenv and the _environ<br />

/ _wenviron variable) will change, but the block pointed to by envp will not change.<br />

This noncompliant code example accesses the envp pointer after calling _putenv_s():<br />

#include <br />

#include <br />

int main(int argc, const char *argv[], const char *envp[]) {<br />

if (_putenv_s("MY_NEW_VAR", "new_value") != 0) {<br />

/* Handle error */<br />

}<br />

if (envp != NULL) {<br />

for (size_t i = 0; envp[i] != NULL; ++i) {<br />

puts(envp[i]);<br />

}<br />

}<br />

return 0;<br />

}<br />

Because envp no longer points to the current environment, this program has undefined behavior.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 333<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it<br />

11.2.4 Compliant Solution (Windows)<br />

This compliant solution uses the _environ variable in place of envp:<br />

#include <br />

#include <br />

_CRTIMP extern char **_environ;<br />

int main(int argc, const char *argv[]) {<br />

if (_putenv_s("MY_NEW_VAR", "new_value") != 0) {<br />

/* Handle error */<br />

}<br />

if (_environ != NULL) {<br />

for (size_t i = 0; _environ[i] != NULL; ++i) {<br />

puts(_environ[i]);<br />

}<br />

}<br />

return 0;<br />

}<br />

11.2.5 Compliant Solution<br />

This compliant solution can reduce remediation time when a large amount of noncompliant envp<br />

code exists. It replaces<br />

int main(int argc, char *argv[], char *envp[]) {<br />

/* ... */<br />

}<br />

with<br />

#if defined (_POSIX_) || defined (__USE_POSIX)<br />

extern char **environ;<br />

#define envp environ<br />

#elif defined(_WIN32)<br />

_CRTIMP extern char **_environ;<br />

#define envp _environ<br />

#endif<br />

int main(int argc, char *argv[]) {<br />

/* ... */<br />

}<br />

This compliant solution may need to be extended to support other implementations that support<br />

forms of the external variable environ.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 334<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it<br />

11.2.6 Risk Assessment<br />

Using the envp environment pointer after the environment has been modified can result in undefined<br />

behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ENV31-C Low Probable Medium P4 L3<br />

11.2.7 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

VOID ENV31-CPP. Do not rely on an environment<br />

pointer following an operation that may<br />

invalidate it<br />

11.2.8 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

[MSDN]<br />

XSH, System Interfaces, setenv<br />

J.5.1, “Environment Arguments”<br />

_environ, _wenviron,<br />

getenv, _wgetenv,<br />

_putenv_s, _wputenv_s<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 335<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV32-C. All exit handlers must return normally<br />

11.3 ENV32-C. All exit handlers must return normally<br />

The C <strong>Standard</strong> provides three functions that cause an application to terminate normally:<br />

_Exit(), exit(), and quick_exit(). These are collectively called exit functions. When the<br />

exit() function is called, or control transfers out of the main() entry point function, functions<br />

registered with atexit() are called (but not at_quick_exit()). When the quick_exit()<br />

function is called, functions registered with at_quick_exit() (but not atexit()) are called.<br />

These functions are collectively called exit handlers. When the _Exit() function is called, no<br />

exit handlers or signal handlers are called.<br />

Exit handlers must terminate by returning. It is important and potentially safety-critical for all exit<br />

handlers to be allowed to perform their cleanup actions. This is particularly true because the application<br />

programmer does not always know about handlers that may have been installed by support<br />

libraries. Two specific issues include nested calls to an exit function and terminating a call to an<br />

exit handler by invoking longjmp.<br />

A nested call to an exit function is undefined behavior. (See undefined behavior 182.) This behavior<br />

can occur only when an exit function is invoked from an exit handler or when an exit function<br />

is called from within a signal handler. (See SIG30-C. Call only asynchronous-safe functions<br />

within signal handlers.)<br />

If a call to the longjmp() function is made that would terminate the call to a function registered<br />

with atexit(), the behavior is undefined.<br />

11.3.1 Noncompliant Code Example<br />

In this noncompliant code example, the exit1() and exit2() functions are registered by<br />

atexit() to perform required cleanup upon program termination. However, if some_condition<br />

evaluates to true, exit() is called a second time, resulting in undefined behavior.<br />

#include <br />

void exit1(void) {<br />

/* ... Cleanup code ... */<br />

return;<br />

}<br />

void exit2(void) {<br />

extern int some_condition;<br />

if (some_condition) {<br />

/* ... More cleanup code ... */<br />

exit(0);<br />

}<br />

return;<br />

}<br />

int main(void) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 336<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV32-C. All exit handlers must return normally<br />

}<br />

if (atexit(exit1) != 0) {<br />

/* Handle error */<br />

}<br />

if (atexit(exit2) != 0) {<br />

/* Handle error */<br />

}<br />

/* ... Program code ... */<br />

return 0;<br />

Functions registered by the atexit() function are called in the reverse order from which they<br />

were registered. Consequently, if exit2() exits in any way other than by returning, exit1()<br />

will not be executed. The same may also be true for atexit() handlers installed by support libraries.<br />

11.3.2 Compliant Solution<br />

A function that is registered as an exit handler by atexit() must exit by returning, as in this<br />

compliant solution:<br />

#include <br />

void exit1(void) {<br />

/* ... Cleanup code ... */<br />

return;<br />

}<br />

void exit2(void) {<br />

extern int some_condition;<br />

if (some_condition) {<br />

/* ... More cleanup code ... */<br />

}<br />

return;<br />

}<br />

int main(void) {<br />

if (atexit(exit1) != 0) {<br />

/* Handle error */<br />

}<br />

if (atexit(exit2) != 0) {<br />

/* Handle error */<br />

}<br />

/* ... Program code ... */<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 337<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV32-C. All exit handlers must return normally<br />

11.3.3 Noncompliant Code Example<br />

In this noncompliant code example, exit1() is registered by atexit() so that upon program<br />

termination, exit1() is called. The exit1() function jumps back to main() to return, with undefined<br />

results.<br />

#include <br />

#include <br />

jmp_buf env;<br />

int val;<br />

void exit1(void) {<br />

longjmp(env, 1);<br />

}<br />

int main(void) {<br />

if (atexit(exit1) != 0) {<br />

/* Handle error */<br />

}<br />

if (setjmp(env) == 0) {<br />

exit(0);<br />

} else {<br />

return 0;<br />

}<br />

}<br />

11.3.4 Compliant Solution<br />

This compliant solution does not call longjmp()but instead returns from the exit handler normally:<br />

#include <br />

void exit1(void) {<br />

return;<br />

}<br />

int main(void) {<br />

if (atexit(exit1) != 0) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 338<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV32-C. All exit handlers must return normally<br />

11.3.5 Risk Assessment<br />

Terminating a call to an exit handler in any way other than by returning is undefined behavior and<br />

may result in abnormal program termination or other unpredictable behavior. It may also prevent<br />

other registered handlers from being invoked.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ENV32-C Medium Likely Medium P12 L1<br />

11.3.6 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24772:2013<br />

MITRE CWE<br />

SIG30-C. Call only asynchronous-safe functions<br />

within signal handlers<br />

Structured Programming [EWD]<br />

Termination Strategy [REU]<br />

CWE-705, Incorrect Control Flow Scoping<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 339<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

11.4 ENV33-C. Do not call system()<br />

The C <strong>Standard</strong> system() function executes a specified command by invoking an implementation-defined<br />

command processor, such as a UNIX shell or CMD.EXE in Microsoft Windows. The<br />

POSIX popen() and Windows _popen() functions also invoke a command processor but create a<br />

pipe between the calling program and the executed command, returning a pointer to a stream that<br />

can be used to either read from or write to the pipe [IEEE Std 1003.1:2013].<br />

Use of the system() function can result in exploitable vulnerabilities, in the worst case allowing<br />

execution of arbitrary system commands. Situations in which calls to system() have high risk<br />

include the following:<br />

• When passing an unsanitized or improperly sanitized command string originating from a<br />

tainted source<br />

• If a command is specified without a path name and the command processor path name resolution<br />

mechanism is accessible to an attacker<br />

• If a relative path to an executable is specified and control over the current working directory<br />

is accessible to an attacker<br />

• If the specified executable program can be spoofed by an attacker<br />

Do not invoke a command processor via system() or equivalent functions to execute a command.<br />

11.4.1 Noncompliant Code Example<br />

In this noncompliant code example, the system() function is used to execute any_cmd in the<br />

host environment. Invocation of a command processor is not required.<br />

#include <br />

#include <br />

#include <br />

enum { BUFFERSIZE = 512 };<br />

void func(const char *input) {<br />

char cmdbuf[BUFFERSIZE];<br />

int len_wanted = snprintf(cmdbuf, BUFFERSIZE,<br />

"any_cmd '%s'", input);<br />

if (len_wanted >= BUFFERSIZE) {<br />

/* Handle error */<br />

} else if (len_wanted < 0) {<br />

/* Handle error */<br />

} else if (system(cmdbuf) == -1) {<br />

/* Handle error */<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 340<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

If this code is compiled and run with elevated privileges on a Linux system, for example, an attacker<br />

can create an account by entering the following string:<br />

happy'; useradd 'attacker<br />

The shell would interpret this string as two separate commands:<br />

any_cmd 'happy';<br />

useradd 'attacker'<br />

and create a new user account that the attacker can use to access the compromised system.<br />

This noncompliant code example also violates STR02-C. Sanitize data passed to complex subsystems.<br />

11.4.2 Compliant Solution (POSIX)<br />

In this compliant solution, the call to system() is replaced with a call to execve(). The exec<br />

family of functions does not use a full shell interpreter, so it is not vulnerable to command-injection<br />

attacks, such as the one illustrated in the noncompliant code example.<br />

The execlp(), execvp(), and (nonstandard) execvP() functions duplicate the actions of the<br />

shell in searching for an executable file if the specified file name does not contain a forward slash<br />

character (/). As a result, they should be used without a forward slash character (/) only if the<br />

PATH environment variable is set to a safe value, as described in ENV03-C. Sanitize the environment<br />

when invoking external programs.<br />

The execl(), execle(), execv(), and execve() functions do not perform path name substitution.<br />

Additionally, precautions should be taken to ensure the external executable cannot be modified by<br />

an untrusted user, for example, by ensuring the executable is not writable by the user.<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

void func(char *input) {<br />

pid_t pid;<br />

int status;<br />

pid_t ret;<br />

char *const args[3] = {"any_exe", input, NULL};<br />

char **env;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 341<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

extern char **environ;<br />

/* ... Sanitize arguments ... */<br />

}<br />

pid = fork();<br />

if (pid == -1) {<br />

/* Handle error */<br />

} else if (pid != 0) {<br />

while ((ret = waitpid(pid, &status, 0)) == -1) {<br />

if (errno != EINTR) {<br />

/* Handle error */<br />

break;<br />

}<br />

}<br />

if ((ret != -1) &&<br />

(!WIFEXITED(status) || !WEXITSTATUS(status)) ) {<br />

/* Report unexpected child status */<br />

}<br />

} else {<br />

/* ... Initialize env as a sanitized copy of environ ... */<br />

if (execve("/usr/bin/any_cmd", args, env) == -1) {<br />

/* Handle error */<br />

_Exit(127);<br />

}<br />

}<br />

This compliant solution is significantly different from the preceding noncompliant code example.<br />

First, input is incorporated into the args array and passed as an argument to execve(), eliminating<br />

concerns about buffer overflow or string truncation while forming the command string.<br />

Second, this compliant solution forks a new process before executing “/usr/bin/any_cmd” in<br />

the child process. Although this method is more complicated than calling system(), the added<br />

security is worth the additional effort.<br />

The exit status of 127 is the value set by the shell when a command is not found, and POSIX recommends<br />

that applications should do the same. XCU, Section 2.8.2, of <strong>Standard</strong> for Information<br />

Technology—Portable Operating System Interface (POSIX®), Base Specifications, Issue 7 [IEEE<br />

Std 1003.1:2013], says<br />

If a command is not found, the exit status shall be 127. If the command name is found,<br />

but it is not an executable utility, the exit status shall be 126. Applications that invoke<br />

utilities without using the shell should use these exit status values to report similar errors.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 342<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

11.4.3 Compliant Solution (Windows)<br />

This compliant solution uses the Microsoft Windows CreateProcess() API:<br />

#include <br />

void func(TCHAR *input) {<br />

STARTUPINFO si = { 0 };<br />

PROCESS_INFORMATION pi;<br />

si.cb = sizeof(si);<br />

if (!CreateProcess(TEXT("any_cmd.exe"), input, NULL, NULL, FALSE,<br />

0, 0, 0, &si, &pi)) {<br />

/* Handle error */<br />

}<br />

CloseHandle(pi.hThread);<br />

CloseHandle(pi.hProcess);<br />

}<br />

This compliant solution relies on the input parameter being non-const. If it were const, the<br />

solution would need to create a copy of the parameter because the CreateProcess() function<br />

can modify the command-line arguments to be passed into the newly created process.<br />

This solution creates the process such that the child process does not inherit any handles from the<br />

parent process, in compliance with WIN03-C. Understand HANDLE inheritance.<br />

11.4.4 Noncompliant Code Example (POSIX)<br />

This noncompliant code invokes the C system() function to remove the .config file in the<br />

user’s home directory.<br />

#include <br />

void func(void) {<br />

system("rm ~/.config");<br />

}<br />

If the vulnerable program has elevated privileges, an attacker can manipulate the value of the<br />

HOME environment variable such that this program can remove any file named .config anywhere<br />

on the system.<br />

11.4.5 Compliant Solution (POSIX)<br />

An alternative to invoking the system() call to execute an external program to perform a required<br />

operation is to implement the functionality directly in the program using existing library<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 343<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

calls. This compliant solution calls the POSIX unlink() function to remove a file without invoking<br />

the system() function [IEEE Std 1003.1:2013]:<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

const char *file_format = "%s/.config";<br />

size_t len;<br />

char *pathname;<br />

struct passwd *pwd;<br />

/* Get /etc/passwd entry for current user */<br />

pwd = getpwuid(getuid());<br />

if (pwd == NULL) {<br />

/* Handle error */<br />

}<br />

/* Build full path name home dir from pw entry */<br />

len = strlen(pwd->pw_dir) + strlen(file_format) + 1;<br />

pathname = (char *)malloc(len);<br />

if (NULL == pathname) {<br />

/* Handle error */<br />

}<br />

int r = snprintf(pathname, len, file_format, pwd->pw_dir);<br />

if (r < 0 || r >= len) {<br />

/* Handle error */<br />

}<br />

if (unlink(pathname) != 0) {<br />

/* Handle error */<br />

}<br />

}<br />

free(pathname);<br />

The unlink() function is not susceptible to a symlink attack where the final component of<br />

pathname (the file name) is a symbolic link because unlink() will remove the symbolic link<br />

and not affect any file or directory named by the contents of the symbolic link. (See FIO01-C. Be<br />

careful using functions that use file names for identification.) While this reduces the susceptibility<br />

of the unlink() function to symlink attacks, it does not eliminate it. The unlink() function is<br />

still susceptible if one of the directory names included in the pathname is a symbolic link. This<br />

could cause the unlink() function to delete a similarly named file in a different directory.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 344<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

11.4.6 Compliant Solution (Windows)<br />

This compliant solution uses the Microsoft Windows SHGetKnownFolderPath() API to get the<br />

current user’s My Documents folder, which is then combined with the file name to create the path<br />

to the file to be deleted. The file is then removed using the DeleteFile() API.<br />

#include <br />

#include <br />

#include <br />

#if defined(_MSC_VER)<br />

#pragma comment(lib, "Shlwapi")<br />

#endif<br />

void func(void) {<br />

HRESULT hr;<br />

LPWSTR path = 0;<br />

WCHAR full_path[MAX_PATH];<br />

}<br />

hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);<br />

if (FAILED(hr)) {<br />

/* Handle error */<br />

}<br />

if (!PathCombineW(full_path, path, L".config")) {<br />

/* Handle error */<br />

}<br />

CoTaskMemFree(path);<br />

if (!DeleteFileW(full_path)) {<br />

/* Handle error */<br />

}<br />

11.4.7 Exceptions<br />

ENV33-C-EX1: It is permissible to call system() with a null pointer argument to determine the<br />

presence of a command processor for the system.<br />

11.4.8 Risk Assessments<br />

If the command string passed to system(), popen(), or other function that invokes a command<br />

processor is not fully sanitized, the risk of exploitation is high. In the worst case scenario, an attacker<br />

can execute arbitrary system commands on the compromised machine with the privileges<br />

of the vulnerable process.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ENV33-C High Probable Medium P12 L1<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 345<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV33-C. Do not call system()<br />

11.4.9 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ENV03-C. Sanitize the environment when invoking<br />

external programs.<br />

ENV02-CPP. Do not call system() if you do<br />

not need a command processor<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java IDS07-J. Sanitize untrusted data passed to the<br />

Runtime.exec() method<br />

ISO/IEC TR 24772:2013<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

Unquoted Search Path or Element [XZQ]<br />

Calling system [syscall]<br />

CWE-78, Improper Neutralization of Special<br />

Elements Used in an OS Command (aka “OS<br />

Command Injection”)<br />

CWE-88, Argument Injection or Modification<br />

11.4.10 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[Wheeler 2004]<br />

XSH, System Interfaces, exec<br />

XSH, System Interfaces, popen<br />

XSH, System Interfaces, unlink<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 346<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

11.5 ENV34-C. Do not store pointers returned by certain functions<br />

The C <strong>Standard</strong>, 7.22.4.6, paragraph 4 [ISO/IEC 9899:2011], states<br />

The getenv function returns a pointer to a string associated with the matched list member.<br />

The string pointed to shall not be modified by the program but may be overwritten<br />

by a subsequent call to the getenv function.<br />

This paragraph gives an implementation the latitude, for example, to return a pointer to a statically<br />

allocated buffer. Consequently, do not store this pointer because the string data it points to may be<br />

overwritten by a subsequent call to the getenv() function or invalidated by modifications to the<br />

environment. This string should be referenced immediately and discarded. If later use is anticipated,<br />

the string should be copied so the copy can be safely referenced as needed.<br />

The getenv() function is not thread-safe. Make sure to address any possible race conditions resulting<br />

from the use of this function.<br />

The asctime(), localeconv(), setlocale(), and strerror() functions have similar restrictions.<br />

Do not access the objects returned by any of these functions after a subsequent call.<br />

11.5.1 Noncompliant Code Example<br />

This noncompliant code example attempts to compare the value of the TMP and TEMP environment<br />

variables to determine if they are the same:<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char *tmpvar;<br />

char *tempvar;<br />

}<br />

tmpvar = getenv("TMP");<br />

if (!tmpvar) {<br />

/* Handle error */<br />

}<br />

tempvar = getenv("TEMP");<br />

if (!tempvar) {<br />

/* Handle error */<br />

}<br />

if (strcmp(tmpvar, tempvar) == 0) {<br />

printf("TMP and TEMP are the same.\n");<br />

} else {<br />

printf("TMP and TEMP are NOT the same.\n");<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 347<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

This code example is noncompliant because the string referenced by tmpvar may be overwritten<br />

as a result of the second call to the getenv() function. As a result, it is possible that both<br />

tmpvar and tempvar will compare equal even if the two environment variables have different<br />

values.<br />

11.5.2 Compliant Solution<br />

This compliant solution uses the malloc() and strcpy() functions to copy the string returned<br />

by getenv() into a dynamically allocated buffer:<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char *tmpvar;<br />

char *tempvar;<br />

const char *temp = getenv("TMP");<br />

if (temp != NULL) {<br />

tmpvar = (char *)malloc(strlen(temp)+1);<br />

if (tmpvar != NULL) {<br />

strcpy(tmpvar, temp);<br />

} else {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

temp = getenv("TEMP");<br />

if (temp != NULL) {<br />

tempvar = (char *)malloc(strlen(temp)+1);<br />

if (tempvar != NULL) {<br />

strcpy(tempvar, temp);<br />

} else {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

if (strcmp(tmpvar, tempvar) == 0) {<br />

printf("TMP and TEMP are the same.\n");<br />

} else {<br />

printf("TMP and TEMP are NOT the same.\n");<br />

}<br />

free(tmpvar);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 348<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

}<br />

free(tempvar);<br />

11.5.3 Compliant Solution (Annex K)<br />

The C <strong>Standard</strong>, Annex K, provides the getenv_s() function for getting a value from the current<br />

environment. However, getenv_s() can still have data races with other threads of execution that<br />

modify the environment list.<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char *tmpvar;<br />

char *tempvar;<br />

size_t requiredSize;<br />

errno_t err;<br />

err = getenv_s(&requiredSize, NULL, 0, "TMP");<br />

if (err) {<br />

/* Handle error */<br />

}<br />

tmpvar = (char *)malloc(requiredSize);<br />

if (!tmpvar) {<br />

/* Handle error */<br />

}<br />

err = getenv_s(&requiredSize, tmpvar, requiredSize, "TMP" );<br />

if (err) {<br />

/* Handle error */<br />

}<br />

err = getenv_s(&requiredSize, NULL, 0, "TEMP");<br />

if (err) {<br />

/* Handle error */<br />

}<br />

tempvar = (char *)malloc(requiredSize);<br />

if (!tempvar) {<br />

/* Handle error */<br />

}<br />

err = getenv_s(&requiredSize, tempvar, requiredSize, "TEMP" );<br />

if (err) {<br />

/* Handle error */<br />

}<br />

if (strcmp(tmpvar, tempvar) == 0) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 349<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

}<br />

printf("TMP and TEMP are the same.\n");<br />

} else {<br />

printf("TMP and TEMP are NOT the same.\n");<br />

}<br />

free(tmpvar);<br />

tmpvar = NULL;<br />

free(tempvar);<br />

tempvar = NULL;<br />

11.5.4 Compliant Solution (Windows)<br />

Microsoft Windows provides the _dupenv_s() and wdupenv_s() functions for getting a value<br />

from the current environment [MSDN]. The _dupenv_s() function searches the list of environment<br />

variables for a specified name. If the name is found, a buffer is allocated; the variable’s<br />

value is copied into the buffer, and the buffer’s address and number of elements are returned. The<br />

_dupenv_s() and _wdupenv_s() functions provide more convenient alternatives to<br />

getenv_s() and _wgetenv_s() because each function handles buffer allocation directly.<br />

The caller is responsible for freeing any allocated buffers returned by these functions by calling<br />

free().<br />

#include <br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char *tmpvar;<br />

char *tempvar;<br />

size_t len;<br />

errno_t err = _dupenv_s(&tmpvar, &len, "TMP");<br />

if (err) {<br />

/* Handle error */<br />

}<br />

err = _dupenv_s(&tempvar, &len, "TEMP");<br />

if (err) {<br />

/* Handle error */<br />

}<br />

if (strcmp(tmpvar, tempvar) == 0) {<br />

printf("TMP and TEMP are the same.\n");<br />

} else {<br />

printf("TMP and TEMP are NOT the same.\n");<br />

}<br />

free(tmpvar);<br />

tmpvar = NULL;<br />

free(tempvar);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 350<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

}<br />

tempvar = NULL;<br />

11.5.5 Compliant Solution (POSIX)<br />

POSIX provides the strdup() function, which can make a copy of the environment variable<br />

string [IEEE Std 1003.1:2013]. The strdup() function is also included in Extensions to the C<br />

Library—Part II [ISO/IEC TR 24731-2:2010].<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

char *tmpvar;<br />

char *tempvar;<br />

}<br />

const char *temp = getenv("TMP");<br />

if (temp != NULL) {<br />

tmpvar = strdup(temp);<br />

if (tmpvar == NULL) {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

temp = getenv("TEMP");<br />

if (temp != NULL) {<br />

tempvar = strdup(temp);<br />

if (tempvar == NULL) {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

if (strcmp(tmpvar, tempvar) == 0) {<br />

printf("TMP and TEMP are the same.\n");<br />

} else {<br />

printf("TMP and TEMP are NOT the same.\n");<br />

}<br />

free(tmpvar);<br />

tmpvar = NULL;<br />

free(tempvar);<br />

tempvar = NULL;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 351<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Environment (ENV) - ENV34-C. Do not store pointers returned by certain functions<br />

11.5.6 Risk Assessment<br />

Storing the pointer to the string returned by getenv(), localeconv(), setlocale(), or<br />

strerror() can result in overwritten data.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ENV34-C Low Probable Medium P4 L3<br />

11.5.7 Related Guidelines<br />

C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TR 24731-2<br />

ISO/IEC TS 17961:2013<br />

ENV00-C. Do not store objects that can be<br />

overwritten by multiple calls to getenv() and<br />

similar functions<br />

5.3.1.1, “The strdup Function”<br />

Using an object overwritten by getenv, localeconv,<br />

setlocale, and strerror [libuse]<br />

11.5.8 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

[MSDN]<br />

[Viega 2003]<br />

Chapter 8, “Environment Variables”<br />

XSH, System Interfaces, strdup<br />

Subclause 7.22.4, “Communication with the<br />

Environment”<br />

Subclause 7.22.4.6, “The getenv Function”<br />

Subclause K.3.6.2.1, “The getenv_s Function”<br />

_dupenv_s(), _wdupenv_s()<br />

Section 3.6, “Using Environment Variables Securely”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 352<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

12 Signals (SIG)<br />

12.1 SIG30-C. Call only asynchronous-safe functions within signal<br />

handlers<br />

Call only asynchronous-safe functions within signal handlers. For strictly conforming programs,<br />

only the C standard library functions abort(), _Exit(), quick_exit(), and signal() can be<br />

safely called from within a signal handler.<br />

The C <strong>Standard</strong>, 7.14.1.1, paragraph 5 [ISO/IEC 9899:2011], states that if the signal occurs other<br />

than as the result of calling the abort() or raise() function, the behavior is undefined if<br />

...the signal handler calls any function in the standard library other than the abort function,<br />

the _Exit function, the quick_exit function, or the signal function with the first<br />

argument equal to the signal number corresponding to the signal that caused the invocation<br />

of the handler.<br />

Implementations may define a list of additional asynchronous-safe functions. These functions can<br />

also be called within a signal handler. This restriction applies to library functions as well as application-defined<br />

functions.<br />

According to the C Rationale, 7.14.1.1 [C99 Rationale 2003],<br />

When a signal occurs, the normal flow of control of a program is interrupted. If a signal<br />

occurs that is being trapped by a signal handler, that handler is invoked. When it is finished,<br />

execution continues at the point at which the signal occurred. This arrangement<br />

can cause problems if the signal handler invokes a library function that was being executed<br />

at the time of the signal.<br />

In general, it is not safe to invoke I/O functions from within signal handlers. Programmers should<br />

ensure a function is included in the list of an implementation’s asynchronous-safe functions for all<br />

implementations the code will run on before using them in signal handlers.<br />

12.1.1 Noncompliant Code Example<br />

In this noncompliant example, the C standard library functions fprintf() and free() are<br />

called from the signal handler via the function log_message(). Neither function is asynchronous-safe.<br />

#include <br />

#include <br />

#include <br />

enum { MAXLINE = 1024 };<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 353<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

char *info = NULL;<br />

void log_message(void) {<br />

fputs(info, stderr);<br />

}<br />

void handler(int signum) {<br />

log_message();<br />

free(info);<br />

info = NULL;<br />

}<br />

int main(void) {<br />

if (signal(SIGINT, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

info = (char *)malloc(MAXLINE);<br />

if (info == NULL) {<br />

/* Handle Error */<br />

}<br />

while (1) {<br />

/* Main loop program code */<br />

log_message();<br />

}<br />

/* More program code */<br />

}<br />

return 0;<br />

12.1.2 Compliant Solution<br />

Signal handlers should be as concise as possible—ideally by unconditionally setting a flag and returning.<br />

This compliant solution sets a flag of type volatile sig_atomic_t and returns; the<br />

log_message() and free() functions are called directly from main():<br />

#include <br />

#include <br />

#include <br />

enum { MAXLINE = 1024 };<br />

volatile sig_atomic_t eflag = 0;<br />

char *info = NULL;<br />

void log_message(void) {<br />

fputs(info, stderr);<br />

}<br />

void handler(int signum) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 354<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

}<br />

eflag = 1;<br />

int main(void) {<br />

if (signal(SIGINT, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

info = (char *)malloc(MAXLINE);<br />

if (info == NULL) {<br />

/* Handle error */<br />

}<br />

while (!eflag) {<br />

/* Main loop program code */<br />

log_message();<br />

}<br />

/* More program code */<br />

log_message();<br />

free(info);<br />

info = NULL;<br />

}<br />

return 0;<br />

12.1.3 Noncompliant Code Example (longjmp())<br />

Invoking the longjmp() function from within a signal handler can lead to undefined behavior if<br />

it results in the invocation of any non-asynchronous-safe functions. Consequently, neither<br />

longjmp() nor the POSIX siglongjmp() functions should ever be called from within a signal<br />

handler.<br />

This noncompliant code example is similar to a vulnerability in an old version of Sendmail [VU<br />

#834865]. The intent is to execute code in a main() loop, which also logs some data. Upon receiving<br />

a SIGINT, the program transfers out of the loop, logs the error, and terminates.<br />

However, an attacker can exploit this noncompliant code example by generating a SIGINT just<br />

before the second if statement in log_message(). The result is that longjmp() transfers control<br />

back to main(), where log_message() is called again. However, the first if statement<br />

would not be executed this time (because buf is not set to NULL as a result of the interrupt), and<br />

the program would write to the invalid memory location referenced by buf0.<br />

#include <br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 355<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

enum { MAXLINE = 1024 };<br />

static jmp_buf env;<br />

void handler(int signum) {<br />

longjmp(env, 1);<br />

}<br />

void log_message(char *info1, char *info2) {<br />

static char *buf = NULL;<br />

static size_t bufsize;<br />

char buf0[MAXLINE];<br />

if (buf == NULL) {<br />

buf = buf0;<br />

bufsize = sizeof(buf0);<br />

}<br />

/*<br />

* Try to fit a message into buf, else reallocate<br />

* it on the heap and then log the message.<br />

*/<br />

/* Program is vulnerable if SIGINT is raised here */<br />

}<br />

if (buf == buf0) {<br />

buf = NULL;<br />

}<br />

int main(void) {<br />

if (signal(SIGINT, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

char *info1;<br />

char *info2;<br />

/* info1 and info2 are set by user input here */<br />

if (setjmp(env) == 0) {<br />

while (1) {<br />

/* Main loop program code */<br />

log_message(info1, info2);<br />

/* More program code */<br />

}<br />

} else {<br />

log_message(info1, info2);<br />

}<br />

}<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 356<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

12.1.4 Compliant Solution<br />

In this compliant solution, the call to longjmp() is removed; the signal handler sets an error flag<br />

instead:<br />

#include <br />

#include <br />

enum { MAXLINE = 1024 };<br />

volatile sig_atomic_t eflag = 0;<br />

void handler(int signum) {<br />

eflag = 1;<br />

}<br />

void log_message(char *info1, char *info2) {<br />

static char *buf = NULL;<br />

static size_t bufsize;<br />

char buf0[MAXLINE];<br />

if (buf == NULL) {<br />

buf = buf0;<br />

bufsize = sizeof(buf0);<br />

}<br />

}<br />

/*<br />

* Try to fit a message into buf, else reallocate<br />

* it on the heap and then log the message.<br />

*/<br />

if (buf == buf0) {<br />

buf = NULL;<br />

}<br />

int main(void) {<br />

if (signal(SIGINT, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

char *info1;<br />

char *info2;<br />

/* info1 and info2 are set by user input here */<br />

while (!eflag) {<br />

/* Main loop program code */<br />

log_message(info1, info2);<br />

/* More program code */<br />

}<br />

log_message(info1, info2);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 357<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

}<br />

return 0;<br />

12.1.5 Noncompliant Code Example (raise())<br />

In this noncompliant code example, the int_handler() function is used to carry out tasks specific<br />

to SIGINT and then raises SIGTERM. However, there is a nested call to the raise() function,<br />

which is undefined behavior.<br />

#include <br />

#include <br />

void term_handler(int signum) {<br />

/* SIGTERM handler */<br />

}<br />

void int_handler(int signum) {<br />

/* SIGINT handler */<br />

if (raise(SIGTERM) != 0) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

if (signal(SIGTERM, term_handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

if (signal(SIGINT, int_handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

/* Program code */<br />

if (raise(SIGINT) != 0) {<br />

/* Handle error */<br />

}<br />

/* More code */<br />

}<br />

return EXIT_SUCCESS;<br />

12.1.6 Compliant Solution<br />

In this compliant solution, int_handler() invokes term_handler() instead of raising<br />

SIGTERM:<br />

#include <br />

#include <br />

void term_handler(int signum) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 358<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

}<br />

/* SIGTERM handler */<br />

void int_handler(int signum) {<br />

/* SIGINT handler */<br />

/* Pass control to the SIGTERM handler */<br />

term_handler(SIGTERM);<br />

}<br />

int main(void) {<br />

if (signal(SIGTERM, term_handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

if (signal(SIGINT, int_handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

/* Program code */<br />

if (raise(SIGINT) != 0) {<br />

/* Handle error */<br />

}<br />

/* More code */<br />

}<br />

return EXIT_SUCCESS;<br />

12.1.7 Implementation Details<br />

12.1.7.1 POSIX<br />

The following table from the POSIX standard [IEEE Std 1003.1:2013] defines a set of functions<br />

that are asynchronous-signal-safe. Applications may invoke these functions, without restriction,<br />

from a signal handler.<br />

_Exit() fexecve() posix_trace_event sigprocmask()<br />

()<br />

_exit() fork() pselect() sigqueue()<br />

abort() fstat() pthread_kill() sigset()<br />

accept() fstatat() pthread_self() sigsuspend()<br />

access() fsync() pthread_sigmask() sleep()<br />

aio_error() ftruncate() raise() sockatmark()<br />

aio_return() futimens() read() socket()<br />

aio_suspend() getegid() readlink() socketpair()<br />

alarm() geteuid() readlinkat() stat()<br />

bind() getgid() recv() symlink()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 359<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

cfgetispeed() getgroups() recvfrom() symlinkat()<br />

cfgetospeed() getpeername() recvmsg() tcdrain()<br />

cfsetispeed() getpgrp() rename() tcflow()<br />

cfsetospeed() getpid() renameat() tcflush()<br />

chdir() getppid() rmdir() tcgetattr()<br />

chmod() getsockname() select() tcgetpgrp()<br />

chown() getsockopt() sem_post() tcsendbreak()<br />

clock_gettime() getuid() send() tcsetattr()<br />

close() kill() sendmsg() tcsetpgrp()<br />

connect() link() sendto() time()<br />

creat() linkat() setgid() timer_getoverrun()<br />

dup() listen() setpgid() timer_gettime()<br />

dup2() lseek() setsid() timer_settime()<br />

execl() lstat() setsockopt() times()<br />

execle() mkdir() setuid() umask()<br />

execv() mkdirat() shutdown() uname()<br />

execve() mkfifo() sigaction() unlink()<br />

faccessat() mkfifoat() sigaddset() unlinkat()<br />

fchdir() mknod() sigdelset() utime()<br />

fchmod() mknodat() sigemptyset() utimensat()<br />

fchmodat() open() sigfillset() utimes()<br />

fchown() openat() sigismember() wait()<br />

fchownat() pause() signal() waitpid()<br />

fcntl() pipe() sigpause() write()<br />

fdatasync() poll() sigpending()<br />

All functions not listed in this table are considered to be unsafe with respect to signals. In the<br />

presence of signals, all POSIX functions behave as defined when called from or interrupted by a<br />

signal handler, with a single exception: when a signal interrupts an unsafe function and the signal<br />

handler calls an unsafe function, the behavior is undefined.<br />

The C <strong>Standard</strong>, 7.14.1.1, paragraph 4 [ISO/IEC 9899:2011], states<br />

If the signal occurs as the result of calling the abort or raise function, the signal handler<br />

shall not call the raise function.<br />

However, in the description of signal(), POSIX [IEEE Std 1003.1:2013] states<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 360<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

This restriction does not apply to POSIX applications, as POSIX.1-2008 requires<br />

raise() to be async-signal-safe.<br />

See also undefined behavior 131.<br />

12.1.7.2 OpenBSD<br />

The OpenBSD signal() manual page lists a few additional functions that are asynchronous-safe<br />

in OpenBSD but “probably not on other systems” [OpenBSD], including snprintf(), vsnprintf(),<br />

and syslog_r() but only when the syslog_data struct is initialized as a local<br />

variable.<br />

12.1.8 Risk Assessment<br />

Invoking functions that are not asynchronous-safe from within a signal handler is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

SIG30-C High Likely Medium P18 L1<br />

12.1.8.1 Related Vulnerabilities<br />

For an overview of software vulnerabilities resulting from improper signal handling, see Michal<br />

Zalewski’s paper “Delivering Signals for Fun and Profit” [Zalewski 2001].<br />

<strong>CERT</strong> Vulnerability Note VU #834865, “Sendmail signal I/O race condition,” describes a vulnerability<br />

resulting from a violation of this rule. Another notable case where using the longjmp()<br />

function in a signal handler caused a serious vulnerability is wu-ftpd 2.4 [Greenman 1997]. The<br />

effective user ID is set to 0 in one signal handler. If a second signal interrupts the first, a call is<br />

made to longjmp(), returning the program to the main thread but without lowering the user’s<br />

privileges. These escalated privileges can be used for further exploitation.<br />

12.1.9 Related Guidelines<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

Calling functions in the C <strong>Standard</strong> Library<br />

other than abort, _Exit, and signal from<br />

within a signal handler [asyncsig]<br />

CWE-479, Signal Handler Use of a Non-reentrant<br />

Function<br />

12.1.10 Bibliography<br />

[C99 Rationale 2003] Subclause 5.2.3, “Signals and Interrupts”<br />

Subclause 7.14.1.1, “The signal Function”<br />

[Dowd 2006]<br />

Chapter 13, “Synchronization and State”<br />

[Greenman 1997]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 361<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG30-C. Call only asynchronous-safe functions within signal handlers<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

[OpenBSD]<br />

[VU #834865]<br />

[Zalewski 2001]<br />

XSH, System Interfaces, longjmp<br />

XSH, System Interfaces, raise<br />

7.14.1.1, “The signal Function”<br />

signal() Man Page<br />

“Delivering Signals for Fun and Profit”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 362<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG31-C. Do not access shared objects in signal handlers<br />

12.2 SIG31-C. Do not access shared objects in signal handlers<br />

Accessing or modifying shared objects in signal handlers can result in race conditions that can<br />

leave data in an inconsistent state. The two exceptions (C <strong>Standard</strong>, 5.1.2.3, paragraph 5) to this<br />

rule are the ability to read from and write to lock-free atomic objects and variables of type volatile<br />

sig_atomic_t. Accessing any other type of object from a signal handler is undefined behavior.<br />

(See undefined behavior 131.)<br />

The need for the volatile keyword is described in DCL22-C. Use volatile for data that cannot<br />

be cached.<br />

The type sig_atomic_t is the integer type of an object that can be accessed as an atomic entity<br />

even in the presence of asynchronous interrupts. The type of sig_atomic_t is implementationdefined,<br />

though it provides some guarantees. Integer values ranging from SIG_ATOMIC_MIN<br />

through SIG_ATOMIC_MAX, inclusive, may be safely stored to a variable of the type. In addition,<br />

when sig_atomic_t is a signed integer type, SIG_ATOMIC_MIN must be no greater than −127<br />

and SIG_ATOMIC_MAX no less than 127. Otherwise, SIG_ATOMIC_MIN must be 0 and<br />

SIG_ATOMIC_MAX must be no less than 255. The macros SIG_ATOMIC_MIN and<br />

SIG_ATOMIC_MAX are defined in the header .<br />

According to the C99 Rationale [C99 Rationale 2003], other than calling a limited, prescribed set<br />

of library functions,<br />

the C89 Committee concluded that about the only thing a strictly conforming program<br />

can do in a signal handler is to assign a value to a volatile static variable which<br />

can be written uninterruptedly and promptly return.<br />

However, this issue was discussed at the April 2008 meeting of ISO/IEC WG14, and it was<br />

agreed that there are no known implementations in which it would be an error to read a value<br />

from a volatile sig_atomic_t variable, and the original intent of the committee was that<br />

both reading and writing variables of volatile sig_atomic_t would be strictly conforming.<br />

The signal handler may also call a handful of functions, including abort(). (See SIG30-C. Call<br />

only asynchronous-safe functions within signal handlers for more information.)<br />

12.2.1 Noncompliant Code Example<br />

In this noncompliant code example, err_msg is updated to indicate that the SIGINT signal was<br />

delivered. The err_msg variable is a character pointer and not a variable of type volatile<br />

sig_atomic_t.<br />

#include <br />

#include <br />

#include <br />

enum { MAX_MSG_SIZE = 24 };<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 363<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG31-C. Do not access shared objects in signal handlers<br />

char *err_msg;<br />

void handler(int signum) {<br />

strcpy(err_msg, "SIGINT encountered.");<br />

}<br />

int main(void) {<br />

signal(SIGINT, handler);<br />

}<br />

err_msg = (char *)malloc(MAX_MSG_SIZE);<br />

if (err_msg == NULL) {<br />

/* Handle error */<br />

}<br />

strcpy(err_msg, "No errors yet.");<br />

/* Main code loop */<br />

return 0;<br />

12.2.2 Compliant Solution (Writing volatile sig_atomic_t)<br />

For maximum portability, signal handlers should only unconditionally set a variable of type volatile<br />

sig_atomic_t and return, as in this compliant solution:<br />

#include <br />

#include <br />

#include <br />

enum { MAX_MSG_SIZE = 24 };<br />

volatile sig_atomic_t e_flag = 0;<br />

void handler(int signum) {<br />

e_flag = 1;<br />

}<br />

int main(void) {<br />

char *err_msg = (char *)malloc(MAX_MSG_SIZE);<br />

if (err_msg == NULL) {<br />

/* Handle error */<br />

}<br />

}<br />

signal(SIGINT, handler);<br />

strcpy(err_msg, "No errors yet.");<br />

/* Main code loop */<br />

if (e_flag) {<br />

strcpy(err_msg, "SIGINT received.");<br />

}<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 364<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG31-C. Do not access shared objects in signal handlers<br />

12.2.3 Compliant Solution (Lock-Free Atomic Access)<br />

Signal handlers can refer to objects with static or thread storage a duration that are lock-free<br />

atomic objects, as in this compliant solution:<br />

#include <br />

#include <br />

#include <br />

#include <br />

#ifdef __STDC_NO_ATOMICS__<br />

#error "Atomics are not supported"<br />

#elif ATOMIC_INT_LOCK_FREE == 0<br />

#error "int is never lock-free"<br />

#endif<br />

atomic_int e_flag = ATOMIC_VAR_INIT(0);<br />

void handler(int signum) {<br />

e_flag = 1;<br />

}<br />

int main(void) {<br />

enum { MAX_MSG_SIZE = 24 };<br />

char err_msg[MAX_MSG_SIZE];<br />

#if ATOMIC_INT_LOCK_FREE == 1<br />

if (!atomic_is_lock_free(&e_flag)) {<br />

return EXIT_FAILURE;<br />

}<br />

#endif<br />

if (signal(SIGINT, handler) == SIG_ERR) {<br />

return EXIT_FAILURE;<br />

}<br />

strcpy(err_msg, "No errors yet.");<br />

/* Main code loop */<br />

if (e_flag) {<br />

strcpy(err_msg, "SIGINT received.");<br />

}<br />

return EXIT_SUCCESS;<br />

}<br />

12.2.4 Exceptions<br />

SIG31-C-EX1: The C <strong>Standard</strong>, 7.14.1.1 paragraph 5 [ISO/IEC 9899:2011], makes a special exception<br />

for errno when a valid call to the signal() function results in a SIG_ERR return, allowing<br />

errno to take an indeterminate value. (See ERR32-C. Do not rely on indeterminate values of<br />

errno.)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 365<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG31-C. Do not access shared objects in signal handlers<br />

12.2.5 Risk Assessment<br />

Accessing or modifying shared objects in signal handlers can result in accessing data in an inconsistent<br />

state. Michal Zalewski’s paper “Delivering Signals for Fun and Profit” [Zalewski 2001]<br />

provides some examples of vulnerabilities that can result from violating this and other signal-handling<br />

rules.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

SIG31-C High Likely High P9 L2<br />

12.2.6 Related Guidelines<br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

Accessing shared objects in signal handlers [accsig]<br />

CWE-662, Improper Synchronization<br />

12.2.7 Bibliography<br />

[C99 Rationale 2003] 5.2.3, “Signals and Interrupts”<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.14.1.1, “The signal Function”<br />

[Zalewski 2001]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 366<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG34-C. Do not call signal() from within interruptible signal handlers<br />

12.3 SIG34-C. Do not call signal() from within interruptible signal<br />

handlers<br />

A signal handler should not reassert its desire to handle its own signal. This is often done on nonpersistent<br />

platforms—that is, platforms that, upon receiving a signal, reset the handler for the signal<br />

to SIG_DFL before calling the bound signal handler. Calling signal() under these conditions<br />

presents a race condition. (See SIG01-C. Understand implementation-specific details<br />

regarding signal handler persistence.)<br />

A signal handler may call signal() only if it does not need to be asynchronous-safe (that is, if<br />

all relevant signals are masked so that the handler cannot be interrupted).<br />

12.3.1 Noncompliant Code Example (POSIX)<br />

On nonpersistent platforms, this noncompliant code example contains a race window, starting<br />

when the host environment resets the signal and ending when the handler calls signal(). During<br />

that time, a second signal sent to the program will trigger the default signal behavior, consequently<br />

defeating the persistent behavior implied by the call to signal() from within the handler<br />

to reassert the binding.<br />

If the environment is persistent (that is, it does not reset the handler when the signal is received),<br />

the signal() call from within the handler() function is redundant.<br />

#include <br />

void handler(int signum) {<br />

if (signal(signum, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

/* Handle signal */<br />

}<br />

void func(void) {<br />

if (signal(SIGUSR1, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

}<br />

12.3.2 Compliant Solution (POSIX)<br />

Calling the signal() function from within the signal handler to reassert the binding is unnecessary<br />

for persistent platforms, as in this compliant solution:<br />

#include <br />

void handler(int signum) {<br />

/* Handle signal */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 367<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG34-C. Do not call signal() from within interruptible signal handlers<br />

}<br />

void func(void) {<br />

if (signal(SIGUSR1, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

}<br />

12.3.3 Compliant Solution (POSIX)<br />

POSIX defines the sigaction() function, which assigns handlers to signals in a similar manner<br />

to signal() but allows the caller to explicitly set persistence. Consequently, the sigaction()<br />

function can be used to eliminate the race window on nonpersistent platforms, as in this compliant<br />

solution:<br />

#include <br />

#include <br />

void handler(int signum) {<br />

/* Handle signal */<br />

}<br />

void func(void) {<br />

struct sigaction act;<br />

act.sa_handler = handler;<br />

act.sa_flags = 0;<br />

if (sigemptyset(&act.sa_mask) != 0) {<br />

/* Handle error */<br />

}<br />

if (sigaction(SIGUSR1, &act, NULL) != 0) {<br />

/* Handle error */<br />

}<br />

}<br />

Although the handler in this example does not call signal(), it could do so safely because the<br />

signal is masked and the handler cannot be interrupted. If the same handler is installed for more<br />

than one signal, the signals must be masked explicitly in act.sa_mask to ensure that the handler<br />

cannot be interrupted because the system masks only the signal being delivered.<br />

POSIX recommends that new applications should use sigaction() rather than signal(). The<br />

sigaction() function is not defined by the C <strong>Standard</strong> and is not supported on some platforms,<br />

including Windows.<br />

12.3.4 Compliant Solution (Windows)<br />

There is no safe way to implement persistent signal-handler behavior on Windows platforms, and<br />

it should not be attempted. If a design depends on this behavior, and the design cannot be altered,<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 368<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG34-C. Do not call signal() from within interruptible signal handlers<br />

it may be necessary to claim a deviation from this rule after completing an appropriate risk analysis.<br />

The reason for this is that Windows is a nonpersistent platform as discussed above. Just before<br />

calling the current handler function, Windows resets the handler for the next occurrence of the<br />

same signal to SIG_DFL. If the handler calls signal() to reinstall itself, there is still a race window.<br />

A signal might occur between the start of the handler and the call to signal(), which<br />

would invoke the default behavior instead of the desired handler.<br />

12.3.5 Exceptions<br />

SIG34-C-EX1: For implementations with persistent signal handlers, it is safe for a handler to<br />

modify the behavior of its own signal. Behavior modifications include ignoring the signal, resetting<br />

to the default behavior, and having the signal handled by a different handler. A handler reasserting<br />

its binding is also safe but unnecessary.<br />

The following code example resets a signal handler to the system’s default behavior:<br />

#include <br />

void handler(int signum) {<br />

#if !defined(_WIN32)<br />

if (signal(signum, SIG_DFL) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

#endif<br />

/* Handle signal */<br />

}<br />

void func(void) {<br />

if (signal(SIGUSR1, handler) == SIG_ERR) {<br />

/* Handle error */<br />

}<br />

}<br />

12.3.6 Risk Assessment<br />

Two signals in quick succession can trigger a race condition on nonpersistent platforms, causing<br />

the signal’s default behavior despite a handler’s attempt to override it.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

SIG34-C Low Unlikely Low P3 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 369<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG34-C. Do not call signal() from within interruptible signal handlers<br />

12.3.7 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

SIG01-C. Understand implementation-specific<br />

details regarding signal handler persistence<br />

Calling signal from interruptible signal handlers<br />

[sigcall]<br />

CWE-479, Signal Handler Use of a Non-reentrant<br />

Function<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 370<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG35-C. Do not return from a computational exception signal handler<br />

12.4 SIG35-C. Do not return from a computational exception signal<br />

handler<br />

According to the C <strong>Standard</strong>, 7.14.1.1 [ISO/IEC 9899:2011], if a signal handler returns when it<br />

has been entered as a result of a computational exception (that is, with the value of its argument of<br />

SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding to such an<br />

exception) returns, then the behavior is undefined. (See undefined behavior 130.)<br />

The Portable Operating System Interface (POSIX®), Base Specifications, Issue 7 [IEEE Std<br />

1003.1:2013], adds SIGBUS to the list of computational exception signal handlers:<br />

The behavior of a process is undefined after it returns normally from a signal-catching<br />

function for a SIGBUS, SIGFPE, SIGILL, or SIGSEGV signal that was not generated by<br />

kill(), sigqueue(), or raise().<br />

Do not return from SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding<br />

to a computational exception, such as SIGBUS on POSIX systems, regardless of how the<br />

signal was generated.<br />

12.4.1 Noncompliant Code Example<br />

In this noncompliant code example, the division operation has undefined behavior if denom<br />

equals 0 and may result in a SIGFPE signal to the program. (See INT33-C. Ensure that division<br />

and remainder operations do not result in divide-by-zero errors.)<br />

#include <br />

#include <br />

#include <br />

#include <br />

volatile sig_atomic_t denom;<br />

void sighandle(int s) {<br />

/* Fix the offending volatile */<br />

if (denom == 0) {<br />

denom = 1;<br />

}<br />

}<br />

int main(int argc, char *argv[]) {<br />

if (argc < 2) {<br />

return 0;<br />

}<br />

char *end = NULL;<br />

long temp = strtol(argv[1], &end, 10);<br />

if (end == argv[1] || 0 != *end ||<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 371<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG35-C. Do not return from a computational exception signal handler<br />

{<br />

}<br />

((LONG_MIN == temp || LONG_MAX == temp) && errno == ERANGE))<br />

/* Handle error */<br />

denom = (sig_atomic_t)temp;<br />

signal(SIGFPE, sighandle);<br />

}<br />

long result = 100 / (long)denom;<br />

return 0;<br />

When compiled with some implementations, this noncompliant code example will loop infinitely<br />

if given the input 0. It illustrates that even when a SIGFPE handler attempts to fix the error condition<br />

while obeying all other rules of signal handling, the program still does not behave as expected.<br />

12.4.2 Compliant Solution<br />

The only portably safe way to leave a SIGFPE, SIGILL, or SIGSEGV handler is to invoke<br />

abort(), quick_exit(), or _Exit(). In the case of SIGFPE, the default action is abnormal<br />

termination, so no user-defined handler is required:<br />

#include <br />

#include <br />

#include <br />

#include <br />

int main(int argc, char *argv[]) {<br />

if (argc < 2) {<br />

return 0;<br />

}<br />

char *end = NULL;<br />

long denom = strtol(argv[1], &end, 10);<br />

if (end == argv[1] || 0 != *end ||<br />

((LONG_MIN == denom || LONG_MAX == denom) && errno ==<br />

ERANGE)) {<br />

/* Handle error */<br />

}<br />

}<br />

long result = 100 / denom;<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 372<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Signals (SIG) - SIG35-C. Do not return from a computational exception signal handler<br />

12.4.2.1 Implementation Details<br />

Some implementations define useful behavior for programs that return from one or more of these<br />

signal handlers. For example, Solaris provides the sigfpe() function specifically to set a<br />

SIGFPE handler that a program may safely return from. Oracle also provides platform-specific<br />

computational exceptions for the SIGTRAP, SIGBUS, and SIGEMT signals. Finally, GNU libsigsegv<br />

takes advantage of the ability to return from a SIGSEGV handler to implement page-level<br />

memory management in user mode.<br />

12.4.3 Risk Assessment<br />

Returning from a computational exception signal handler is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

SIG35-C Low Unlikely High P1 L3<br />

12.4.4 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

2.4.1, Signal Generation and Delivery<br />

Subclause 7.14.1.1, “The signal Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 373<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

13 Error Handling (ERR)<br />

13.1 ERR30-C. Set errno to zero before calling a library function known<br />

to set errno, and check errno only after the function returns a value<br />

indicating failure<br />

The value of errno is initialized to zero at program startup, but it is never subsequently set to<br />

zero by any C standard library function. The value of errno may be set to nonzero by a C standard<br />

library function call whether or not there is an error, provided the use of errno is not documented<br />

in the description of the function. It is meaningful for a program to inspect the contents of<br />

errno only after an error might have occurred. More precisely, errno is meaningful only after a<br />

library function that sets errno on error has returned an error code.<br />

According to Question 20.4 of C-FAQ [Summit 2005]<br />

In general, you should detect errors by checking return values, and use errno only to<br />

distinguish among the various causes of an error, such as “File not found” or “Permission<br />

denied.” (Typically, you use perror or strerror to print these discriminating error<br />

messages.) It’s only necessary to detect errors with errno when a function does not<br />

have a unique, unambiguous, out-of-band error return (that is, because all of its possible<br />

return values are valid; one example is atoi [sic]). In these cases (and in these<br />

cases only; check the documentation to be sure whether a function allows this), you can<br />

detect errors by setting errno to 0, calling the function, and then testing errno. (Setting<br />

errno to 0 first is important, as no library function ever does that for you.)<br />

Note that atoi() is not required to set the value of errno.<br />

Library functions fall into the following categories:<br />

• Those that set errno and return and out-of-band error indicator<br />

• Those that set errno and return and in-band error indicator<br />

• Those that do not promise to set errno<br />

• Those with differing standards documentation<br />

13.1.1 Library Functions that Set errno and Return an Out-of-Band Error<br />

Indicator<br />

The C <strong>Standard</strong> specifies that the functions listed in the following table set errno and return an<br />

out-of-band error indicator. That is, their return value on error can never be returned by a successful<br />

call.<br />

A program may set and check errno for these library functions but is not required to do so. The<br />

program should not check the value of errno without first verifying that the function returned an<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 374<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

error indicator. For example, errno should not be checked after calling signal() without first<br />

ensuring that signal() actually returned SIG_ERR.<br />

Functions That Set errno and Return an Out-of-Band Error Indicator<br />

Function Name Return Value errno Value<br />

ftell() -1L Positive<br />

fgetpos(), fsetpos() Nonzero Positive<br />

mbrtowc(), mbsrtowcs() (size_t)(-1) EILSEQ<br />

signal() SIG_ERR Positive<br />

wcrtomb(), wcsrtombs() (size_t)(-1) EILSEQ<br />

mbrtoc16(), mbrtoc32() (size_t)(-1) EILSEQ<br />

c16rtomb(), cr32rtomb() (size_t)(-1) EILSEQ<br />

13.1.2 Library Functions that Set errno and Return an In-Band Error Indicator<br />

The C <strong>Standard</strong> specifies that the functions listed in the following table set errno and return an<br />

in-band error indicator. That is, the return value when an error occurs is also a valid return value<br />

for successful calls. For example, the strtoul() function returns ULONG_MAX and sets errno to<br />

ERANGE if an error occurs. Because ULONG_MAX is a valid return value, errno must be used to<br />

check whether an error actually occurred. A program that uses errno for error checking must set<br />

it to 0 before calling one of these library functions and then inspect errno before a subsequent<br />

library function call.<br />

The fgetwc() and fputwc() functions return WEOF in multiple cases, only one of which results<br />

in setting errno. The string conversion functions will return the maximum or minimum representable<br />

value and set errno to ERANGE if the converted value cannot be represented by the data<br />

type. However, if the conversion cannot happen because the input is invalid, the function will return<br />

0, and the output pointer parameter will be assigned the value of the input pointer parameter,<br />

provided the output parameter is non-null.<br />

Functions that Set errno and Return an In-Band Error Indicator<br />

Function Name Return Value errno Value<br />

fgetwc(), fputwc() WEOF EILSEQ<br />

strtol(), wcstol() LONG_MIN or LONG_MAX ERANGE<br />

strtoll(), wcstoll() LLONG_MIN or LLONG_MAX ERANGE<br />

strtoul(), wcstoul() ULONG_MAX ERANGE<br />

strtoull(), wcstoull() ULLONG_MAX ERANGE<br />

strtoumax(),wcstoumax() UINTMAX_MAX<br />

ERANGE<br />

strtod(), wcstod() 0 or ±HUGE_VAL ERANGE<br />

strtof(), wcstof() 0 or ±HUGE_VALF ERANGE<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 375<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

Function Name Return Value errno Value<br />

strtold(), wcstold() 0 or ±HUGE_VALL ERANGE<br />

strtoimax(),wcstoimax() INTMAX_MIN, INTMAX_MAX ERANGE<br />

13.1.3 Library Functions that Do Not Promise to Set errno<br />

The C <strong>Standard</strong> fails to document the behavior of errno for some functions. For example, the<br />

setlocale() function normally returns a null pointer in the event of an error, but no guarantees<br />

are made about setting errno.<br />

After calling one of these functions, a program should not rely solely on the value of errno to determine<br />

if an error occurred. The function might have altered errno, but this does not ensure that<br />

errno will properly indicate an error condition.<br />

13.1.4 Library Functions with Differing <strong>Standard</strong>s Documentation<br />

Some functions behave differently regarding errno in various standards. The fopen() function<br />

is one such example. When fopen() encounters an error, it returns a null pointer. The C <strong>Standard</strong><br />

makes no mention of errno when describing fopen(). However, POSIX.1 declares that when<br />

fopen() encounters an error, it returns a null pointer and sets errno to a value indicating the error<br />

[IEEE Std 1003.1-2013]. The implication is that a program conforming to C but not to POSIX<br />

(such as a Windows program) should not check errno after calling fopen(), but a POSIX program<br />

may check errno if fopen() returns a null pointer.<br />

13.1.5 Library Functions and errno<br />

The following uses of errno are documented in the C <strong>Standard</strong>:<br />

• Functions defined in may set errno but are not required to.<br />

• For numeric conversion functions in the strtod, strtol, wcstod, and wcstol families, if<br />

the correct result is outside the range of representable values, an appropriate minimum or<br />

maximum value is returned and the value ERANGE is stored in errno. For floating-point conversion<br />

functions in the strtod and wcstod families, if an underflow occurs, whether<br />

errno acquires the value ERANGE is implementation-defined. If the conversion fails, 0 is returned<br />

and errno is not set.<br />

• The numeric conversion function atof() and those in the atoi family “need not affect the<br />

value of” errno.<br />

• For mathematical functions in , if the integer expression math_errhandling &<br />

MATH_ERRNO is nonzero, on a domain error, errno acquires the value EDOM; on an overflow<br />

with default rounding or if the mathematical result is an exact infinity from finite arguments,<br />

errno acquires the value ERANGE; and on an underflow, whether errno acquires the value<br />

ERANGE is implementation-defined.<br />

• If a request made by calling signal() cannot be honored, a value of SIG_ERR is returned<br />

and a positive value is stored in errno.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 376<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

• The byte I/O functions, wide-character I/O functions, and multibyte conversion functions<br />

store the value of the macro EILSEQ in errno if and only if an encoding error occurs.<br />

• On failure, fgetpos() and fsetpos() return nonzero and store an implementation-defined<br />

positive value in errno.<br />

• On failure, ftell() returns -1L and stores an implementation-defined positive value in<br />

errno.<br />

• The perror() function maps the error number in errno to a message and writes it to<br />

stderr.<br />

The POSIX.1 standard defines the use of errno by many more functions (including the C standard<br />

library function). POSIX also has a small set of functions that are exceptions to the rule. These<br />

functions have no return value reserved to indicate an error, but they still set errno on error. To<br />

detect an error, an application must set errno to 0 before calling the function and check whether<br />

it is nonzero after the call. Affected functions include strcoll(), strxfrm(), strerror(),<br />

wcscoll(), wcsxfrm(), and fwide().The C <strong>Standard</strong> allows these functions to set errno to a<br />

nonzero value on success. Consequently, this type of error checking should be performed only on<br />

POSIX systems.<br />

13.1.6 Noncompliant Code Example (strtoul())<br />

This noncompliant code example fails to set errno to 0 before invoking strtoul(). If an error<br />

occurs, strtoul() returns a valid value (ULONG_MAX), so errno is the only means of determining<br />

if strtoul() ran successfully.<br />

#include <br />

#include <br />

#include <br />

void func(const char *c_str) {<br />

unsigned long number;<br />

char *endptr;<br />

}<br />

number = strtoul(c_str, &endptr, 0);<br />

if (endptr == c_str || (number == ULONG_MAX<br />

&& errno == ERANGE)) {<br />

/* Handle error */<br />

} else {<br />

/* Computation succeeded */<br />

}<br />

Any error detected in this manner may have occurred earlier in the program or may not represent<br />

an actual error.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 377<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

13.1.7 Compliant Solution (strtoul())<br />

This compliant solution sets errno to 0 before the call to strtoul() and inspects errno after<br />

the call:<br />

#include <br />

#include <br />

#include <br />

void func(const char *c_str) {<br />

unsigned long number;<br />

char *endptr;<br />

}<br />

errno = 0;<br />

number = strtoul(c_str, &endptr, 0);<br />

if (endptr == c_str || (number == ULONG_MAX<br />

&& errno == ERANGE)) {<br />

/* Handle error */<br />

} else {<br />

/* Computation succeeded */<br />

}<br />

13.1.8 Noncompliant Code Example (fopen())<br />

This noncompliant code example may fail to diagnose errors because fopen() might not set<br />

errno even if an error occurs:<br />

#include <br />

#include <br />

void func(const char *filename) {<br />

FILE *fileptr;<br />

}<br />

errno = 0;<br />

fileptr = fopen(filename, "rb");<br />

if (errno != 0) {<br />

/* Handle error */<br />

}<br />

13.1.9 Compliant Solution (fopen(), C)<br />

The C <strong>Standard</strong> makes no mention of errno when describing fopen(). In this compliant solution,<br />

the results of the call to fopen() are used to determine failure and errno is not checked:<br />

#include <br />

void func(const char *filename) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 378<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

}<br />

FILE *fileptr = fopen(filename, "rb");<br />

if (fileptr == NULL) {<br />

/* An error occurred in fopen() */<br />

}<br />

13.1.10 Compliant Solution (fopen(), POSIX)<br />

In this compliant solution, errno is checked only after an error has already been detected by another<br />

means:<br />

#include <br />

#include <br />

void func(const char *filename) {<br />

FILE *fileptr;<br />

}<br />

errno = 0;<br />

fileptr = fopen(filename, "rb");<br />

if (fileptr == NULL) {<br />

/*<br />

* An error occurred in fopen(); now it's valid<br />

* to examine errno.<br />

*/<br />

perror(filename);<br />

}<br />

13.1.11 Risk Assessment<br />

The improper use of errno may result in failing to detect an error condition or in incorrectly<br />

identifying an error condition when none exists.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ERR30-C Medium Probable Medium P8 L2<br />

13.1.12 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

MITRE CWE<br />

EXP12-C. Do not ignore values returned by<br />

functions<br />

Incorrectly setting and using errno [inverrno]<br />

CWE-456, Missing Initialization of a Variable<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 379<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only<br />

after the function returns a value indicating failure<br />

13.1.13 Bibliography<br />

[Brainbell.com]<br />

Macros and Miscellaneous Pitfalls<br />

[Horton 1990] Section 11, p. 168<br />

Section 14, p. 254<br />

[IEEE Std 1003.1-2013]<br />

XSH, System Interfaces, fopen<br />

[Koenig 1989] Section 5.4, p. 73<br />

[Summit 2005]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 380<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR32-C. Do not rely on indeterminate values of errno<br />

13.2 ERR32-C. Do not rely on indeterminate values of errno<br />

According to the C <strong>Standard</strong> [ISO/IEC 9899:2011], the behavior of a program is undefined when<br />

the value of errno is referred to after a signal occurred other than as the result of calling<br />

the abort or raise function and the corresponding signal handler obtained a SIG_ERR<br />

return from a call to the signal function.<br />

See undefined behavior 133.<br />

A signal handler is allowed to call signal(); if that fails, signal() returns SIG_ERR and sets<br />

errno to a positive value. However, if the event that caused a signal was external (not the result<br />

of the program calling abort() or raise()), the only functions the signal handler may call are<br />

_Exit() or abort(), or it may call signal() on the signal currently being handled; if signal()<br />

fails, the value of errno is indeterminate.<br />

This rule is also a special case of SIG31-C. Do not access shared objects in signal handlers. The<br />

object designated by errno is of static storage duration and is not a volatile sig_atomic_t.<br />

As a result, performing any action that would require errno to be set would normally cause undefined<br />

behavior. The C <strong>Standard</strong>, 7.14.1.1, paragraph 5, makes a special exception for errno in<br />

this case, allowing errno to take on an indeterminate value but specifying that there is no other<br />

undefined behavior. This special exception makes it possible to call signal() from within a signal<br />

handler without risking undefined behavior, but the handler, and any code executed after the<br />

handler returns, must not depend on the value of errno being meaningful.<br />

13.2.1 Noncompliant Code Example<br />

The handler() function in this noncompliant code example attempts to restore default handling<br />

for the signal indicated by signum. If the request to set the signal to default can be honored, the<br />

signal() function returns the value of the signal handler for the most recent successful call to<br />

the signal() function for the specified signal. Otherwise, a value of SIG_ERR is returned and a<br />

positive value is stored in errno. Unfortunately, the value of errno is indeterminate because the<br />

handler() function is called when an external signal is raised, so any attempt to read errno (for<br />

example, by the perror() function) is undefined behavior:<br />

#include <br />

#include <br />

#include <br />

typedef void (*pfv)(int);<br />

void handler(int signum) {<br />

pfv old_handler = signal(signum, SIG_DFL);<br />

if (old_handler == SIG_ERR) {<br />

perror("SIGINT handler"); /* Undefined behavior */<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 381<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR32-C. Do not rely on indeterminate values of errno<br />

}<br />

int main(void) {<br />

pfv old_handler = signal(SIGINT, handler);<br />

if (old_handler == SIG_ERR) {<br />

perror("SIGINT handler");<br />

/* Handle error */<br />

}<br />

/* Main code loop */<br />

}<br />

return EXIT_SUCCESS;<br />

The call to perror() from handler() also violates SIG30-C. Call only asynchronous-safe<br />

functions within signal handlers.<br />

13.2.2 Compliant Solution<br />

This compliant solution does not reference errno and does not return from the signal handler if<br />

the signal() call fails:<br />

#include <br />

#include <br />

#include <br />

typedef void (*pfv)(int);<br />

void handler(int signum) {<br />

pfv old_handler = signal(signum, SIG_DFL);<br />

if (old_handler == SIG_ERR) {<br />

abort();<br />

}<br />

}<br />

int main(void) {<br />

pfv old_handler = signal(SIGINT, handler);<br />

if (old_handler == SIG_ERR) {<br />

perror("SIGINT handler");<br />

/* Handle error */<br />

}<br />

/* Main code loop */<br />

}<br />

return EXIT_SUCCESS;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 382<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR32-C. Do not rely on indeterminate values of errno<br />

13.2.3 Noncompliant Code Example (POSIX)<br />

POSIX is less restrictive than C about what applications can do in signal handlers. It has a long<br />

list of asynchronous-safe functions that can be called. (See SIG30-C. Call only asynchronous-safe<br />

functions within signal handlers.) Many of these functions set errno on error, which can lead to a<br />

signal handler being executed between a call to a failed function and the subsequent inspection of<br />

errno. Consequently, the value inspected is not the one set by that function but the one set by a<br />

function call in the signal handler. POSIX applications can avoid this problem by ensuring that<br />

signal handlers containing code that might alter errno always save the value of errno on entry<br />

and restore it before returning.<br />

The signal handler in this noncompliant code example alters the value of errno. As a result, it<br />

can cause incorrect error handling if executed between a failed function call and the subsequent<br />

inspection of errno:<br />

#include <br />

#include <br />

#include <br />

#include <br />

void reaper(int signum) {<br />

errno = 0;<br />

for (;;) {<br />

int rc = waitpid(-1, NULL, WNOHANG);<br />

if ((0 == rc) || (-1 == rc && EINTR != errno)) {<br />

break;<br />

}<br />

}<br />

if (ECHILD != errno) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

struct sigaction act;<br />

act.sa_handler = reaper;<br />

act.sa_flags = 0;<br />

if (sigemptyset(&act.sa_mask) != 0) {<br />

/* Handle error */<br />

}<br />

if (sigaction(SIGCHLD, &act, NULL) != 0) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

}<br />

return EXIT_SUCCESS;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 383<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR32-C. Do not rely on indeterminate values of errno<br />

13.2.4 Compliant Solution (POSIX)<br />

This compliant solution saves and restores the value of errno in the signal handler:<br />

#include <br />

#include <br />

#include <br />

#include <br />

void reaper(int signum) {<br />

errno_t save_errno = errno;<br />

errno = 0;<br />

for (;;) {<br />

int rc = waitpid(-1, NULL, WNOHANG);<br />

if ((0 == rc) || (-1 == rc && EINTR != errno)) {<br />

break;<br />

}<br />

}<br />

if (ECHILD != errno) {<br />

/* Handle error */<br />

}<br />

errno = save_errno;<br />

}<br />

int main(void) {<br />

struct sigaction act;<br />

act.sa_handler = reaper;<br />

act.sa_flags = 0;<br />

if (sigemptyset(&act.sa_mask) != 0) {<br />

/* Handle error */<br />

}<br />

if (sigaction(SIGCHLD, &act, NULL) != 0) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

}<br />

return EXIT_SUCCESS;<br />

13.2.5 Risk Assessment<br />

Referencing indeterminate values of errno is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ERR32-C Low Unlikely Low P3 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 384<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR32-C. Do not rely on indeterminate values of errno<br />

13.2.6 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

SIG30-C. Call only asynchronous-safe functions<br />

within signal handlers<br />

SIG31-C. Do not access shared objects in signal<br />

handlers<br />

13.2.7 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.14.1.1, “The signal Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 385<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

13.3 ERR33-C. Detect and handle standard library errors<br />

The majority of the standard library functions, including I/O functions and memory allocation<br />

functions, return either a valid value or a value of the correct return type that indicates an error<br />

(for example, −1 or a null pointer). Assuming that all calls to such functions will succeed and failing<br />

to check the return value for an indication of an error is a dangerous practice that may lead to<br />

unexpected or undefined behavior when an error occurs. It is essential that programs detect and<br />

appropriately handle all errors in accordance with an error-handling policy, as discussed in<br />

ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy.<br />

The successful completion or failure of each of the standard library functions listed in the following<br />

table shall be determined either by comparing the function’s return value with the value listed<br />

in the column labeled “Error Return” or by calling one of the library functions mentioned in the<br />

footnotes.<br />

<strong>Standard</strong> Library Functions<br />

Function Successful Return Error Return<br />

aligned_alloc() Pointer to space NULL<br />

asctime_s() 0 Nonzero<br />

at_quick_exit() 0 Nonzero<br />

atexit() 0 Nonzero<br />

bsearch() Pointer to matching element NULL<br />

bsearch_s() Pointer to matching element NULL<br />

btowc() Converted wide character WEOF<br />

c16rtomb() Number of bytes (size_t)(-1)<br />

c32rtomb() Number of bytes (size_t)(-1)<br />

calloc() Pointer to space NULL<br />

clock() Processor time (clock_t)(-1)<br />

cnd_broadcast() thrd_success thrd_error<br />

cnd_init() thrd_success thrd_nomem or thrd_error<br />

cnd_signal() thrd_success thrd_error<br />

cnd_timedwait() thrd_success thrd_timedout or<br />

thrd_error<br />

cnd_wait() thrd_success thrd_error<br />

ctime_s() 0 Nonzero<br />

fclose() 0 EOF (negative)<br />

fflush() 0 EOF (negative)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 386<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

fgetc() Character read EOF 6<br />

fgetpos() 0 Nonzero, errno > 0<br />

fgets() Pointer to string NULL<br />

fgetwc() Wide character read WEOF 6<br />

fopen() Pointer to stream NULL<br />

fopen_s() 0 Nonzero<br />

fprintf()<br />

fprintf_s()<br />

Number of characters<br />

(nonnegative)<br />

Number of characters<br />

(nonnegative)<br />

Negative<br />

Negative<br />

fputc() Character written EOF 7<br />

fputs() Nonnegative EOF (negative)<br />

fputwc() Wide character written WEOF<br />

fputws() Nonnegative EOF (negative)<br />

fread() Elements read Elements read<br />

freopen() Pointer to stream NULL<br />

freopen_s() 0 Nonzero<br />

fscanf()<br />

fscanf_s()<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

EOF (negative)<br />

EOF (negative)<br />

fseek() 0 Nonzero<br />

fsetpos() 0 Nonzero, errno > 0<br />

ftell() File position −1L, errno > 0<br />

fwprintf()<br />

Number of wide characters<br />

(nonnegative)<br />

Negative<br />

fwprintf_s()<br />

Number of wide characters Negative<br />

(nonnegative)<br />

fwrite() Elements written Elements written<br />

fwscanf()<br />

Number of conversions EOF (negative)<br />

(nonnegative)<br />

fwscanf_s()<br />

Number of conversions EOF (negative)<br />

(nonnegative)<br />

getc() Character read EOF 6<br />

______________________<br />

6<br />

By calling ferror() and feof()<br />

7<br />

By calling ferror()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 387<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

getchar() Character read EOF 6<br />

getenv() Pointer to string NULL<br />

getenv_s() Pointer to string NULL<br />

gets_s() Pointer to string NULL<br />

getwc() Wide character read WEOF<br />

getwchar() Wide character read WEOF<br />

gmtime() Pointer to broken-down time NULL<br />

gmtime_s() Pointer to broken-down time NULL<br />

localtime() Pointer to broken-down time NULL<br />

localtime_s() Pointer to broken-down time NULL<br />

malloc() Pointer to space NULL<br />

mblen(), s != NULL Number of bytes −1<br />

mbrlen(), s != NULL Number of bytes or status (size_t)(-1)<br />

mbrtoc16() Number of bytes or status (size_t)(-1), errno ==<br />

EILSEQ<br />

mbrtoc32() Number of bytes or status (size_t)(-1), errno ==<br />

EILSEQ<br />

mbrtowc(), s != NULL Number of bytes or status (size_t)(-1), errno ==<br />

EILSEQ<br />

mbsrtowcs() Number of non-null elements (size_t)(-1), errno ==<br />

EILSEQ<br />

mbsrtowcs_s() 0 Nonzero<br />

mbstowcs() Number of non-null elements (size_t)(-1)<br />

mbstowcs_s() 0 Nonzero<br />

mbtowc(), s != NULL Number of bytes −1<br />

memchr() Pointer to located character NULL<br />

mktime() Calendar time (time_t)(-1)<br />

mtx_init() thrd_success thrd_error<br />

mtx_lock() thrd_success thrd_error<br />

mtx_timedlock() thrd_success thrd_timedout or<br />

thrd_error<br />

mtx_trylock() thrd_success thrd_busy or thrd_error<br />

mtx_unlock() thrd_success thrd_error<br />

printf_s()<br />

Number of characters<br />

(nonnegative)<br />

Negative<br />

putc() Character written EOF 7<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 388<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

putwc() Wide character written WEOF<br />

raise() 0 Nonzero<br />

realloc() Pointer to space NULL<br />

remove() 0 Nonzero<br />

rename() 0 Nonzero<br />

setlocale() Pointer to string NULL<br />

setvbuf() 0 Nonzero<br />

scanf()<br />

scanf_s()<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

EOF (negative)<br />

EOF (negative)<br />

signal() Pointer to previous function SIG_ERR, errno > 0<br />

snprintf()<br />

snprintf_s()<br />

sprintf()<br />

sprintf_s()<br />

sscanf()<br />

sscanf_s()<br />

Number of characters that<br />

would be written (nonnegative)<br />

Number of characters that<br />

would be written (nonnegative)<br />

Number of non-null characters<br />

written<br />

Number of non-null characters<br />

written<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Negative<br />

Negative<br />

Negative<br />

Negative<br />

strchr() Pointer to located character NULL<br />

EOF (negative)<br />

EOF (negative)<br />

strerror_s() 0 Nonzero<br />

strftime() Number of non-null characters 0<br />

strpbrk() Pointer to located character NULL<br />

strrchr() Pointer to located character NULL<br />

strstr() Pointer to located string NULL<br />

strtod() Converted value 0, errno == ERANGE<br />

strtof() Converted value 0, errno == ERANGE<br />

strtoimax() Converted value INTMAX_MAX or INTMAX_MIN,<br />

strtok()<br />

Pointer to first character of a<br />

token<br />

errno == ERANGE<br />

NULL<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 389<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

strtok_s()<br />

Pointer to first character of a<br />

token<br />

NULL<br />

strtol() Converted value LONG_MAX or LONG_MIN,<br />

errno == ERANGE<br />

strtold() Converted value 0, errno == ERANGE<br />

strtoll() Converted value LLONG_MAX or LLONG_MIN,<br />

errno == ERANGE<br />

strtoumax() Converted value UINTMAX_MAX, errno ==<br />

ERANGE<br />

strtoul() Converted value ULONG_MAX, errno ==<br />

ERANGE<br />

strtoull() Converted value ULLONG_MAX, errno ==<br />

ERANGE<br />

strxfrm() Length of transformed string >= n<br />

swprintf()<br />

swprintf_s()<br />

swscanf()<br />

swscanf_s()<br />

Number of non-null wide characters<br />

Number of non-null wide characters<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Negative<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

thrd_create() thrd_success thrd_nomem or thrd_error<br />

thrd_detach() thrd_success thrd_error<br />

thrd_join() thrd_success thrd_error<br />

thrd_sleep() 0 Negative<br />

time() Calendar time (time_t)(-1)<br />

timespec_get() Base 0<br />

tmpfile() Pointer to stream NULL<br />

tmpfile_s() 0 Nonzero<br />

tmpnam() Non-null pointer NULL<br />

tmpnam_s() 0 Nonzero<br />

tss_create() thrd_success thrd_error<br />

tss_get()<br />

Value of thread-specific storage<br />

tss_set() thrd_success thrd_error<br />

0<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 390<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

ungetc() Character pushed back EOF 8<br />

ungetwc() Character pushed back WEOF<br />

vfprintf()<br />

vfprintf_s()<br />

vfscanf()<br />

vfscanf_s()<br />

vfwprintf()<br />

vfwprintf_s()<br />

vfwscanf()<br />

vfwscanf_s()<br />

vprintf_s()<br />

vscanf()<br />

vscanf_s()<br />

vsnprintf()<br />

vsnprintf_s()<br />

vsprintf()<br />

vsprintf_s()<br />

Number of characters<br />

(nonnegative)<br />

Number of characters<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of wide characters<br />

(nonnegative)<br />

Number of wide characters<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of characters<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of characters that<br />

would be written (nonnegative)<br />

Number of characters that<br />

would be written (nonnegative)<br />

Number of non-null characters<br />

(nonnegative)<br />

Number of non-null characters<br />

(nonnegative)<br />

Negative<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

Negative<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

Negative<br />

Negative<br />

Negative<br />

Negative<br />

______________________<br />

8<br />

The ungetc() function does not set the error indicator even when it fails, so it is not possible to check for<br />

errors reliably unless it is known that the argument is not equal to EOF. The C <strong>Standard</strong> [ISO/IEC 9899:2011]<br />

states that “one character of pushback is guaranteed,” so this should not be an issue if, at most, one character<br />

is ever pushed back before reading again. (See FIO13-C. Never push back anything other than one read character.)<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 391<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

vsscanf()<br />

vsscanf_s()<br />

vswprintf()<br />

vswprintf_s()<br />

vswscanf()<br />

vswscanf_s()<br />

vwprintf_s()<br />

vwscanf()<br />

vwscanf_s()<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of non-null wide characters<br />

Number of non-null wide characters<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of wide characters<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

EOF (negative)<br />

EOF (negative)<br />

Negative<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

wcrtomb() Number of bytes stored (size_t)(-1)<br />

wcschr()<br />

wcsftime()<br />

wcspbrk()<br />

wcsrchr()<br />

Pointer to located wide character<br />

Number of non-null wide characters<br />

Pointer to located wide character<br />

Pointer to located wide character<br />

NULL<br />

0<br />

NULL<br />

NULL<br />

wcsrtombs() Number of non-null bytes (size_t)(-1), errno ==<br />

EILSEQ<br />

wcsrtombs_s() 0 Nonzero<br />

wcsstr() Pointer to located wide string NULL<br />

wcstod() Converted value 0, errno == ERANGE<br />

wcstof() Converted value 0, errno == ERANGE<br />

wcstoimax() Converted value INTMAX_MAX or INTMAX_MIN,<br />

wcstok()<br />

Pointer to first wide character<br />

of a token<br />

errno == ERANGE<br />

NULL<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 392<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

wcstok_s()<br />

Pointer to first wide character<br />

of a token<br />

NULL<br />

wcstol() Converted value LONG_MAX or LONG_MIN,<br />

errno == ERANGE<br />

wcstold() Converted value 0, errno == ERANGE<br />

wcstoll() Converted value LLONG_MAX or LLONG_MIN,<br />

errno == ERANGE<br />

wcstombs() Number of non-null bytes (size_t)(-1)<br />

wcstombs_s() 0 Nonzero<br />

wcstoumax() Converted value UINTMAX_MAX, errno ==<br />

ERANGE<br />

wcstoul() Converted value ULONG_MAX, errno ==<br />

ERANGE<br />

wcstoull() Converted value ULLONG_MAX, errno ==<br />

wcsxfrm()<br />

Length of transformed wide<br />

string<br />

ERANGE<br />

>= n<br />

wctob() Converted character EOF<br />

wctomb(), s != NULL Number of bytes stored −1<br />

wctomb_s(), s != NULL Number of bytes stored −1<br />

wctrans()<br />

Valid argument to<br />

towctrans<br />

wctype() Valid argument to iswctype 0<br />

wmemchr()<br />

wprintf_s()<br />

wscanf()<br />

wscanf_s()<br />

Pointer to located wide character<br />

Number of wide characters<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

Number of conversions<br />

(nonnegative)<br />

0<br />

NULL<br />

Negative<br />

EOF (negative)<br />

EOF (negative)<br />

Note: According to FIO35-C. Use feof() and ferror() to detect end-of-file and file errors when<br />

sizeof(int) == sizeof(char), callers should verify end-of-file and file errors for the functions in this<br />

table as follows:<br />

1 By calling ferror() and feof()<br />

2 By calling ferror()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 393<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

13.3.1 Noncompliant Code Example (setlocale())<br />

In this noncompliant code example, the function utf8_to_wcs() attempts to convert a sequence<br />

of UTF-8 characters to wide characters. It first invokes setlocale() to set the global locale to<br />

the implementation-defined “en_US.UTF-8” but does not check for failure. The setlocale()<br />

function will fail by returning a null pointer, for example, when the locale is not installed. The<br />

function may fail for other reasons as well, such as the lack of resources. Depending on the sequence<br />

of characters pointed to by utf8, the subsequent call to mbstowcs() may fail or result in<br />

the function storing an unexpected sequence of wide characters in the supplied buffer wcs.<br />

#include <br />

#include <br />

int utf8_to_wcs(wchar_t *wcs, size_t n, const char *utf8,<br />

size_t *size) {<br />

if (NULL == size) {<br />

return -1;<br />

}<br />

setlocale(LC_CTYPE, "en_US.UTF-8");<br />

*size = mbstowcs(wcs, utf8, n);<br />

return 0;<br />

}<br />

13.3.2 Compliant Solution (setlocale())<br />

This compliant solution checks the value returned by setlocale() and avoids calling<br />

mbstowcs() if the function fails. The function also takes care to restore the locale to its initial<br />

setting before returning control to the caller.<br />

#include <br />

#include <br />

int utf8_to_wcs(wchar_t *wcs, size_t n, const char *utf8,<br />

size_t *size) {<br />

if (NULL == size) {<br />

return -1;<br />

}<br />

const char *save = setlocale(LC_CTYPE, "en_US.UTF-8");<br />

if (NULL == save) {<br />

return -1;<br />

}<br />

*size = mbstowcs(wcs, utf8, n);<br />

if (NULL == setlocale(LC_CTYPE, save)) {<br />

return -1;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 394<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

}<br />

return 0;<br />

13.3.3 Noncompliant Code Example (calloc())<br />

In this noncompliant code example, temp_num, tmp2, and num_of_records are derived from a<br />

tainted source. Consequently, an attacker can easily cause calloc() to fail by providing a large<br />

value for num_of_records.<br />

#include <br />

#include <br />

enum { SIG_DESC_SIZE = 32 };<br />

typedef struct {<br />

char sig_desc[SIG_DESC_SIZE];<br />

} signal_info;<br />

void func(size_t num_of_records, size_t temp_num,<br />

const char *tmp2, size_t tmp2_size_bytes) {<br />

signal_info *start = (signal_info *)calloc(num_of_records,<br />

sizeof(signal_info));<br />

if (tmp2 == NULL) {<br />

/* Handle error */<br />

} else if (temp_num > num_of_records) {<br />

/* Handle error */<br />

} else if (tmp2_size_bytes < SIG_DESC_SIZE) {<br />

/* Handle error */<br />

}<br />

}<br />

signal_info *point = start + temp_num - 1;<br />

memcpy(point->sig_desc, tmp2, SIG_DESC_SIZE);<br />

point->sig_desc[SIG_DESC_SIZE - 1] = '\0';<br />

/* ... */<br />

free(start);<br />

When calloc() fails, it returns a null pointer that is assigned to start. If start is null, an attacker<br />

can provide a value for temp_num that, when scaled by sizeof(signal_info), references<br />

a writable address to which control is eventually transferred. The contents of the string referenced<br />

by tmp2 can then be used to overwrite the address, resulting in an arbitrary code<br />

execution vulnerability.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 395<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

13.3.4 Compliant Solution (calloc())<br />

To correct this error, ensure the pointer returned by calloc() is not null:<br />

#include <br />

#include <br />

enum { SIG_DESC_SIZE = 32 };<br />

typedef struct {<br />

char sig_desc[SIG_DESC_SIZE];<br />

} signal_info;<br />

void func(size_t num_of_records, size_t temp_num,<br />

const char *tmp2, size_t tmp2_size_bytes) {<br />

signal_info *start = (signal_info *)calloc(num_of_records,<br />

sizeof(signal_info));<br />

if (start == NULL) {<br />

/* Handle allocation error */<br />

} else if (tmp2 == NULL) {<br />

/* Handle error */<br />

} else if (temp_num > num_of_records) {<br />

/* Handle error */<br />

} else if (tmp2_size_bytes < SIG_DESC_SIZE) {<br />

/* Handle error */<br />

}<br />

}<br />

signal_info *point = start + temp_num - 1;<br />

memcpy(point->sig_desc, tmp2, SIG_DESC_SIZE);<br />

point->sig_desc[SIG_DESC_SIZE - 1] = '\0';<br />

/* ... */<br />

free(start);<br />

13.3.5 Noncompliant Code Example (realloc())<br />

This noncompliant code example calls realloc() to resize the memory referred to by p. However,<br />

if realloc() fails, it returns a null pointer and the connection between the original block of<br />

memory and p is lost, resulting in a memory leak.<br />

#include <br />

void *p;<br />

void func(size_t new_size) {<br />

if (new_size == 0) {<br />

/* Handle error */<br />

}<br />

p = realloc(p, new_size);<br />

if (p == NULL) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 396<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

}<br />

}<br />

This code example complies with MEM04-C. Do not perform zero-length allocations.<br />

13.3.6 Compliant Solution (realloc())<br />

In this compliant solution, the result of realloc() is assigned to the temporary pointer q and<br />

validated before it is assigned to the original pointer p:<br />

#include <br />

void *p;<br />

void func(size_t new_size) {<br />

void *q;<br />

if (new_size == 0) {<br />

/* Handle error */<br />

}<br />

}<br />

q = realloc(p, new_size);<br />

if (q == NULL) {<br />

/* Handle error */<br />

} else {<br />

p = q;<br />

}<br />

13.3.7 Noncompliant Code Example (fseek())<br />

In this noncompliant code example, the fseek() function is used to set the file position to a location<br />

offset in the file referred to by file prior to reading a sequence of bytes from the file.<br />

However, if an I/O error occurs during the seek operation, the subsequent read will fill the buffer<br />

with the wrong contents.<br />

#include <br />

size_t read_at(FILE *file, long offset,<br />

void *buf, size_t nbytes) {<br />

fseek(file, offset, SEEK_SET);<br />

return fread(buf, 1, nbytes, file);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 397<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

13.3.8 Compliant Solution (fseek())<br />

According to the C <strong>Standard</strong>, the fseek() function returns a nonzero value to indicate that an error<br />

occurred. This compliant solution tests for this condition before reading from a file to eliminate<br />

the chance of operating on the wrong portion of the file if fseek() fails:<br />

#include <br />

size_t read_at(FILE *file, long offset,<br />

void *buf, size_t nbytes) {<br />

if (fseek(file, offset, SEEK_SET) != 0) {<br />

/* Indicate error to caller */<br />

return 0;<br />

}<br />

return fread(buf, 1, nbytes, file);<br />

}<br />

13.3.9 Noncompliant Code Example (snprintf())<br />

In this noncompliant code example, snprintf() is assumed to succeed. However, if the call<br />

fails (for example, because of insufficient memory, as described in GNU libc bug 441945), the<br />

subsequent call to log_message() has undefined behavior because the character buffer is uninitialized<br />

and need not be null-terminated.<br />

#include <br />

extern void log_message(const char *);<br />

void f(int i, int width, int prec) {<br />

char buf[40];<br />

snprintf(buf, sizeof(buf), "i = %*.*i", width, prec, i);<br />

log_message(buf);<br />

/* ... */<br />

}<br />

13.3.10 Compliant Solution (snprintf())<br />

This compliant solution does not assume that snprintf() will succeed regardless of its arguments.<br />

It tests the return value of snprintf() before subsequently using the formatted buffer.<br />

This compliant solution also treats the case where the static buffer is not large enough for<br />

snprintf() to append the terminating null character as an error.<br />

#include <br />

#include <br />

extern void log_message(const char *);<br />

void f(int i, int width, int prec) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 398<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

}<br />

char buf[40];<br />

int n;<br />

n = snprintf(buf, sizeof(buf), "i = %*.*i", width, prec, i);<br />

if (n < 0 || n >= sizeof(buf)) {<br />

/* Handle snprintf() error */<br />

strcpy(buf, "unknown error");<br />

}<br />

log_message(buf);<br />

13.3.11 Compliant Solution (snprintf(null))<br />

If unknown, the length of the formatted string can be discovered by invoking snprintf() with a<br />

null buffer pointer to determine the size required for the output, then dynamically allocating a<br />

buffer of sufficient size, and finally calling snprintf() again to format the output into the dynamically<br />

allocated buffer. Even with this approach, the success of all calls still needs to be tested,<br />

and any errors must be appropriately handled. A possible optimization is to first attempt to format<br />

the string into a reasonably small buffer allocated on the stack and, only when the buffer turns out<br />

to be too small, dynamically allocate one of a sufficient size:<br />

#include <br />

#include <br />

#include <br />

extern void log_message(const char *);<br />

void f(int i, int width, int prec) {<br />

char buffer[20];<br />

char *buf = buffer;<br />

int n = sizeof(buffer);<br />

const char fmt[] = "i = %*.*i";<br />

n = snprintf(buf, n, fmt, width, prec, i);<br />

if (n < 0) {<br />

/* Handle snprintf() error */<br />

strcpy(buffer, "unknown error");<br />

goto write_log;<br />

}<br />

if (n < sizeof(buffer)) {<br />

goto write_log;<br />

}<br />

buf = (char *)malloc(n + 1);<br />

if (NULL == buf) {<br />

/* Handle malloc() error */<br />

strcpy(buffer, "unknown error");<br />

goto write_log;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 399<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

n = snprintf(buf, n, fmt, width, prec, i);<br />

if (n < 0) {<br />

/* Handle snprintf() error */<br />

strcpy(buffer, "unknown error");<br />

}<br />

write_log:<br />

log_message(buf);<br />

}<br />

if (buf != buffer) {<br />

free(buf);<br />

}<br />

This solution uses the goto statement, as suggested in MEM12-C. Consider using a goto chain<br />

when leaving a function on error when using and releasing resources.<br />

13.3.12 Exceptions<br />

ERR33-C-EX1: It is acceptable to ignore the return value of a function that cannot fail, or a function<br />

whose return value is inconsequential, or when an error condition need not be diagnosed. The<br />

function’s results should be explicitly cast to void to signify programmer intent. Return values<br />

from the functions in the following table do not need to be checked because their historical use<br />

has overwhelmingly omitted error checking and the consequences are not relevant to security.<br />

Functions for Which Return Values Need Not Be Checked<br />

Function Successful Return Error Return<br />

putchar() Character written EOF<br />

putwchar() Wide character written WEOF<br />

puts() Nonnegative EOF (negative)<br />

printf(), vprintf() Number of characters Negative<br />

(nonnegative)<br />

wprintf(), vwprintf() Number of wide characters Negative<br />

(nonnegative)<br />

kill_dependency() The input parameter NA<br />

memcpy(), wmemcpy() The destination input parameter<br />

NA<br />

memmove(), wmemmove() The destination input parameter<br />

NA<br />

strcpy(), wcscpy() The destination input parameter<br />

NA<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 400<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

Function Successful Return Error Return<br />

strncpy(), wcsncpy()<br />

strcat(), wcscat()<br />

strncat(), wcsncat()<br />

memset(), wmemset()<br />

The destination input parameter<br />

The destination input parameter<br />

The destination input parameter<br />

The destination input parameter<br />

NA<br />

NA<br />

NA<br />

NA<br />

13.3.13 Risk Assessment<br />

Failing to detect error conditions can lead to unpredictable results, including abnormal program<br />

termination and denial-of-service attacks or, in some situations, could even allow an attacker to<br />

run arbitrary code.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

ERR33-C High Likely Medium P18 L1<br />

13.3.13.1 Related Vulnerabilities<br />

The vulnerability in Adobe Flash [VU#159523] arises because Flash neglects to check the return<br />

value from calloc(). Even when calloc() returns a null pointer, Flash writes to an offset<br />

from the return value. Dereferencing a null pointer usually results in a program crash, but dereferencing<br />

an offset from a null pointer allows an exploit to succeed without crashing the program.<br />

13.3.14 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ISO/IEC TS 17961:2013<br />

ERR00-C. Adopt and implement a consistent<br />

and comprehensive error-handling policy<br />

EXP34-C. Do not dereference null pointers<br />

FIO13-C. Never push back anything other than<br />

one read character<br />

MEM04-C. Do not perform zero-length allocations<br />

MEM12-C. Consider using a goto chain when<br />

leaving a function on error when using and releasing<br />

resources<br />

ERR10-CPP. Check for error conditions<br />

FIO04-CPP. Detect and handle input and output<br />

errors<br />

Failing to detect and handle standard library errors<br />

[liberr]<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 401<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Error Handling (ERR) - ERR33-C. Detect and handle standard library errors<br />

MITRE CWE<br />

CWE-252, Unchecked Return Value<br />

CWE-253, Incorrect Check of Function Return<br />

Value<br />

CWE-390, Detection of Error Condition without<br />

Action<br />

CWE-391, Unchecked Error Condition<br />

CWE-476, NULL Pointer Dereference<br />

13.3.15 Bibliography<br />

[DHS 2006]<br />

[Henricson 1997]<br />

[ISO/IEC 9899:2011]<br />

[VU#159523]<br />

Handle All Errors Safely<br />

Recommendation 12.1, “Check for All Errors<br />

Reported from Functions”<br />

Subclause 7.21.7.10, “The ungetc Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 402<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON30-C. Clean up thread-specific storage<br />

14 Concurrency (CON)<br />

14.1 CON30-C. Clean up thread-specific storage<br />

The tss_create() function creates a thread-specific storage pointer identified by a key.<br />

Threads can allocate thread-specific storage and associate the storage with a key that uniquely<br />

identifies the storage by calling the tss_set() function. If not properly freed, this memory may<br />

be leaked. Ensure that thread-specific storage is freed.<br />

14.1.1 Noncompliant Code Example<br />

In this noncompliant code example, each thread dynamically allocates storage in the get_data()<br />

function, which is then associated with the global key by the call to tss_set() in the<br />

add_data() function. This memory is subsequently leaked when the threads terminate.<br />

#include <br />

#include <br />

/* Global key to the thread-specific storage */<br />

tss_t key;<br />

enum { MAX_THREADS = 3 };<br />

int *get_data(void) {<br />

int *arr = (int *)malloc(2 * sizeof(int));<br />

if (arr == NULL) {<br />

return arr; /* Report error */<br />

}<br />

arr[0] = 10;<br />

arr[1] = 42;<br />

return arr;<br />

}<br />

int add_data(void) {<br />

int *data = get_data();<br />

if (data == NULL) {<br />

return -1; /* Report error */<br />

}<br />

}<br />

if (thrd_success != tss_set(key, (void *)data)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

void print_data(void) {<br />

/* Get this thread's global data from key */<br />

int *data = tss_get(key);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 403<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON30-C. Clean up thread-specific storage<br />

}<br />

if (data != NULL) {<br />

/* Print data */<br />

}<br />

int function(void *dummy) {<br />

if (add_data() != 0) {<br />

return -1; /* Report error */<br />

}<br />

print_data();<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t thread_id[MAX_THREADS];<br />

/* Create the key before creating the threads */<br />

if (thrd_success != tss_create(&key, NULL)) {<br />

/* Handle error */<br />

}<br />

{<br />

/* Create threads that would store specific storage */<br />

for (size_t i = 0; i < MAX_THREADS; i++) {<br />

if (thrd_success != thrd_create(&thread_id[i], function, NULL))<br />

}<br />

}<br />

/* Handle error */<br />

for (size_t i = 0; i < MAX_THREADS; i++) {<br />

if (thrd_success != thrd_join(thread_id[i], NULL)) {<br />

/* Handle error */<br />

}<br />

}<br />

}<br />

tss_delete(key);<br />

return 0;<br />

14.1.2 Compliant Solution<br />

In this compliant solution, each thread explicitly frees the thread-specific storage returned by the<br />

tss_get() function before terminating:<br />

#include <br />

#include <br />

/* Global key to the thread-specific storage */<br />

tss_t key;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 404<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON30-C. Clean up thread-specific storage<br />

int function(void *dummy) {<br />

if (add_data() != 0) {<br />

return -1; /* Report error */<br />

}<br />

print_data();<br />

free(tss_get(key));<br />

return 0;<br />

}<br />

/* ... Other functions are unchanged */<br />

14.1.3 Compliant Solution<br />

This compliant solution invokes a destructor function registered during the call to tss_create()<br />

to automatically free any thread-specific storage:<br />

#include <br />

#include <br />

/* Global key to the thread-specific storage */<br />

tss_t key;<br />

enum { MAX_THREADS = 3 };<br />

/* ... Other functions are unchanged */<br />

void destructor(void *data) {<br />

free(data);<br />

}<br />

int main(void) {<br />

thrd_t thread_id[MAX_THREADS];<br />

/* Create the key before creating the threads */<br />

if (thrd_success != tss_create(&key, destructor)) {<br />

/* Handle error */<br />

}<br />

{<br />

/* Create threads that would store specific storage */<br />

for (size_t i = 0; i < MAX_THREADS; i++) {<br />

if (thrd_success != thrd_create(&thread_id[i], function, NULL))<br />

}<br />

}<br />

/* Handle error */<br />

for (size_t i = 0; i < MAX_THREADS; i++) {<br />

if (thrd_success != thrd_join(thread_id[i], NULL)) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 405<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON30-C. Clean up thread-specific storage<br />

}<br />

}<br />

tss_delete(key);<br />

return 0;<br />

14.1.4 Risk Assessment<br />

Failing to free thread-specific objects results in memory leaks and could result in a denial-of-service<br />

attack.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON30-C Medium Unlikely Medium P4 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 406<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON31-C. Do not destroy a mutex while it is locked<br />

14.2 CON31-C. Do not destroy a mutex while it is locked<br />

Mutexes are used to protect shared data structures being concurrently accessed. If a mutex is destroyed<br />

while a thread is blocked waiting for that mutex, critical sections and shared data are no<br />

longer protected.<br />

The C <strong>Standard</strong>, 7.26.4.1, paragraph 2 [ISO/IEC 9899:2011], states<br />

The mtx_destroy function releases any resources used by the mutex pointed to by<br />

mtx. No threads can be blocked waiting for the mutex pointed to by mtx.<br />

This statement implies that destroying a mutex while a thread is waiting on it is undefined behavior.<br />

14.2.1 Noncompliant Code Example<br />

This noncompliant code example creates several threads that each invoke the do_work() function,<br />

passing a unique number as an ID. The do_work() function initializes the lock mutex if<br />

the argument is 0 and destroys the mutex if the argument is max_threads - 1. In all other<br />

cases, the do_work() function provides normal processing. Each thread, except the final cleanup<br />

thread, increments the atomic completed variable when it is finished.<br />

Unfortunately, this code contains several race conditions, allowing the mutex to be destroyed before<br />

it is unlocked. Additionally, there is no guarantee that lock will be initialized before it is<br />

passed to mtx_lock(). Each of these behaviors is undefined.<br />

#include <br />

#include <br />

#include <br />

mtx_t lock;<br />

/* Atomic so multiple threads can modify safely */<br />

atomic_int completed = ATOMIC_VAR_INIT(0);<br />

enum { max_threads = 5 };<br />

int do_work(void *arg) {<br />

int *i = (int *)arg;<br />

if (*i == 0) { /* Creation thread */<br />

if (thrd_success != mtx_init(&lock, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

atomic_store(&completed, 1);<br />

} else if (*i < max_threads - 1) { /* Worker thread */<br />

if (thrd_success != mtx_lock(&lock)) {<br />

/* Handle error */<br />

}<br />

/* Access data protected by the lock */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 407<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON31-C. Do not destroy a mutex while it is locked<br />

}<br />

atomic_fetch_add(&completed, 1);<br />

if (thrd_success != mtx_unlock(&lock)) {<br />

/* Handle error */<br />

}<br />

} else { /* Destruction thread */<br />

mtx_destroy(&lock);<br />

}<br />

return 0;<br />

int main(void) {<br />

thrd_t threads[max_threads];<br />

}<br />

for (size_t i = 0; i < max_threads; i++) {<br />

if (thrd_success != thrd_create(&threads[i], do_work, &i)) {<br />

/* Handle error */<br />

}<br />

}<br />

for (size_t i = 0; i < max_threads; i++) {<br />

if (thrd_success != thrd_join(threads[i], 0)) {<br />

/* Handle error */<br />

}<br />

}<br />

return 0;<br />

14.2.2 Compliant Solution<br />

This compliant solution eliminates the race conditions by initializing the mutex in main() before<br />

creating the threads and by destroying the mutex in main() after joining the threads:<br />

#include <br />

#include <br />

#include <br />

mtx_t lock;<br />

/* Atomic so multiple threads can increment safely */<br />

atomic_int completed = ATOMIC_VAR_INIT(0);<br />

enum { max_threads = 5 };<br />

int do_work(void *dummy) {<br />

if (thrd_success != mtx_lock(&lock)) {<br />

/* Handle error */<br />

}<br />

/* Access data protected by the lock */<br />

atomic_fetch_add(&completed, 1);<br />

if (thrd_success != mtx_unlock(&lock)) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 408<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON31-C. Do not destroy a mutex while it is locked<br />

}<br />

return 0;<br />

int main(void) {<br />

thrd_t threads[max_threads];<br />

if (thrd_success != mtx_init(&lock, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

for (size_t i = 0; i < max_threads; i++) {<br />

if (thrd_success != thrd_create(&threads[i], do_work, NULL)) {<br />

/* Handle error */<br />

}<br />

}<br />

for (size_t i = 0; i < max_threads; i++) {<br />

if (thrd_success != thrd_join(threads[i], 0)) {<br />

/* Handle error */<br />

}<br />

}<br />

}<br />

mtx_destroy(&lock);<br />

return 0;<br />

14.2.3 Risk Assessment<br />

Destroying a mutex while it is locked may result in invalid control flow and data corruption.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON31-C Medium Probable High P4 L3<br />

14.2.4 Related Guidelines<br />

MITRE CWE<br />

CWE-667, Improper Locking<br />

14.2.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.26.4.1, “The mtx_destroy Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 409<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON32-C. Prevent data races when accessing bit-fields from multiple threads<br />

14.3 CON32-C. Prevent data races when accessing bit-fields from<br />

multiple threads<br />

When accessing a bit-field, a thread may inadvertently access a separate bit-field in adjacent<br />

memory. This is because compilers are required to store multiple adjacent bit-fields in one storage<br />

unit whenever they fit. Consequently, data races may exist not just on a bit-field accessed by multiple<br />

threads but also on other bit-fields sharing the same byte or word. A similar problem is discussed<br />

in CON00-C. Avoid race conditions with multiple threads, but the issue described by this<br />

rule can be harder to diagnose because it may not be obvious that the same memory location is being<br />

modified by multiple threads.<br />

One approach for preventing data races in concurrent programming is to use a mutex. When<br />

properly observed by all threads, a mutex can provide safe and secure access to a shared object.<br />

However, mutexes provide no guarantees with regard to other objects that might be accessed<br />

when the mutex is not controlled by the accessing thread. Unfortunately, there is no portable way<br />

to determine which adjacent bit-fields may be stored along with the desired bit-field.<br />

Another approach is to insert a non-bit-field member between any two bit-fields to ensure that<br />

each bit-field is the only one accessed within its storage unit. This technique effectively guarantees<br />

that no two bit-fields are accessed simultaneously.<br />

14.3.1 Noncompliant Code Example (Bit-field)<br />

Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent<br />

bit-fields in different threads is undefined behavior, as shown in this noncompliant code example:<br />

struct multi_threaded_flags {<br />

unsigned int flag1 : 2;<br />

unsigned int flag2 : 2;<br />

};<br />

struct multi_threaded_flags flags;<br />

int thread1(void *arg) {<br />

flags.flag1 = 1;<br />

return 0;<br />

}<br />

int thread2(void *arg) {<br />

flags.flag2 = 2;<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 410<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON32-C. Prevent data races when accessing bit-fields from multiple threads<br />

The C <strong>Standard</strong>, 3.14, paragraph 3 [ISO/IEC 9899:2011], states<br />

NOTE 2 A bit-field and an adjacent non-bit-field member are in separate memory locations.<br />

The same applies to two bit-fields, if one is declared inside a nested structure declaration<br />

and the other is not, or if the two are separated by a zero-length bit-field declaration,<br />

or if they are separated by a non-bit-field member declaration. It is not safe to<br />

concurrently update two non-atomic bit-fields in the same structure if all members declared<br />

between them are also (non-zero-length) bit-fields, no matter what the sizes of<br />

those intervening bit-fields happen to be.<br />

For example, the following instruction sequence is possible:<br />

Thread 1: register 0 = flags<br />

Thread 1: register 0 &= ~mask(flag1)<br />

Thread 2: register 0 = flags<br />

Thread 2: register 0 &= ~mask(flag2)<br />

Thread 1: register 0 |= 1


Concurrency (CON) - CON32-C. Prevent data races when accessing bit-fields from multiple threads<br />

}<br />

return 0;<br />

int thread2(void *arg) {<br />

if (thrd_success != mtx_lock(&flags.mutex)) {<br />

/* Handle error */<br />

}<br />

flags.s.flag2 = 2;<br />

if (thrd_success != mtx_unlock(&flags.mutex)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

14.3.3 Compliant Solution (C11)<br />

In this compliant solution, two threads simultaneously modify two distinct non-bit-field members<br />

of a structure. Because the members occupy different bytes in memory, no concurrency protection<br />

is required.<br />

struct multi_threaded_flags {<br />

unsigned char flag1;<br />

unsigned char flag2;<br />

};<br />

struct multi_threaded_flags flags;<br />

int thread1(void *arg) {<br />

flags.flag1 = 1;<br />

return 0;<br />

}<br />

int thread2(void *arg) {<br />

flags.flag2 = 2;<br />

return 0;<br />

}<br />

Unlike C99, C11 explicitly defines a memory location and provides the following note in subclause<br />

3.14.2 [ISO/IEC 9899:2011]:<br />

NOTE 1 Two threads of execution can update and access separate memory locations<br />

without interfering with each other.<br />

It is almost certain that flag1 and flag2 are stored in the same word. Using a compiler that conforms<br />

to C99 or earlier, if both assignments occur on a thread-scheduling interleaving that ends<br />

with both stores occurring after one another, it is possible that only one of the flags will be set as<br />

intended. The other flag will contain its previous value because both members are represented by<br />

the same word, which is the smallest unit the processor can work on. Before the changes were<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 412<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON32-C. Prevent data races when accessing bit-fields from multiple threads<br />

made to the C <strong>Standard</strong> for C11, there were no guarantees that these flags could be modified concurrently.<br />

14.3.4 Risk Assessment<br />

Although the race window is narrow, an assignment or an expression can evaluate improperly because<br />

of misinterpreted data resulting in a corrupted running state or unintended information disclosure.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON32-C Medium Probable Medium P8 L2<br />

14.3.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

3.14, “Memory Location”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 413<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON33-C. Avoid race conditions when using library functions<br />

14.4 CON33-C. Avoid race conditions when using library functions<br />

Some C standard library functions are not guaranteed to be reentrant with respect to threads.<br />

Functions such as strtok() and asctime() return a pointer to the result stored in function-allocated<br />

memory on a per-process basis. Other functions such as rand() store state information in<br />

function-allocated memory on a per-process basis. Multiple threads invoking the same function<br />

can cause concurrency problems, which often result in abnormal behavior and can cause more serious<br />

vulnerabilities, such as abnormal termination, denial-of-service attack, and data integrity violations.<br />

According to the C <strong>Standard</strong>, the library functions listed in the following table may contain data<br />

races when invoked by multiple threads.<br />

Functions<br />

rand(), srand()<br />

getenv(), getenv_s()<br />

strtok()<br />

strerror()<br />

asctime(), ctime(),<br />

localtime(), gmtime()<br />

setlocale()<br />

ATOMIC_VAR_INIT, atomic_init()<br />

tmpnam()<br />

mbrtoc16(), c16rtomb(),<br />

mbrtoc32(), c32rtomb()<br />

Remediation<br />

MSC30-C. Do not use the rand() function for<br />

generating pseudorandom numbers<br />

ENV34-C. Do not store pointers returned by<br />

certain functions<br />

strtok_s() in C11 Annex K<br />

strtok_r() in POSIX<br />

strerror_s() in C11 Annex K<br />

strerror_r() in POSIX<br />

asctime_s(), ctime_s(), localtime_s(),<br />

gmtime_s() in C11 Annex K<br />

Protect multithreaded access to locale-specific<br />

functions with a mutex<br />

Do not attempt to initialize an atomic variable<br />

from multiple threads<br />

tmpnam_s() in C11 Annex K<br />

tmpnam_r() in POSIX<br />

Do not call with a null mbstate_t * argument<br />

Section 2.9.1 of the Portable Operating System Interface (POSIX®), Base Specifications, Issue 7<br />

[IEEE Std 1003.1:2013] extends the list of functions that are not required to be thread-safe.<br />

14.4.1 Noncompliant Code Example<br />

In this noncompliant code example, the function f() is called from within a multithreaded application<br />

but encounters an error while calling a system function. The strerror() function returns<br />

a human-readable error string given an error number. The C <strong>Standard</strong>, 7.24.6.2 [ISO/IEC<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 414<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON33-C. Avoid race conditions when using library functions<br />

9899:2011], specifically states that strerror() is not required to avoid data races. An implementation<br />

could write the error string into a static array and return a pointer to it, and that array<br />

might be accessible and modifiable by other threads.<br />

#include <br />

#include <br />

#include <br />

void f(FILE *fp) {<br />

fpos_t pos;<br />

errno = 0;<br />

}<br />

if (0 != fgetpos(fp, &pos)) {<br />

char *errmsg = strerror(errno);<br />

printf("Could not get the file position: %s\n", errmsg);<br />

}<br />

This code first sets errno to 0 to comply with ERR30-C. Set errno to zero before calling a library<br />

function known to set errno, and check errno only after the function returns a value indicating failure.<br />

14.4.2 Compliant Solution (Annex K, strerror_s())<br />

This compliant solution uses the strerror_s() function from Annex K of the C <strong>Standard</strong>,<br />

which has the same functionality as strerror() but guarantees thread-safety:<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

#include <br />

#include <br />

enum { BUFFERSIZE = 64 };<br />

void f(FILE *fp) {<br />

fpos_t pos;<br />

errno = 0;<br />

}<br />

if (0 != fgetpos(fp, &pos)) {<br />

char errmsg[BUFFERSIZE];<br />

if (strerror_s(errmsg, BUFFERSIZE, errno) != 0) {<br />

/* Handle error */<br />

}<br />

printf("Could not get the file position: %s\n", errmsg);<br />

}<br />

Because Annex K is optional, strerror_s() may not be available in all implementations.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 415<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON33-C. Avoid race conditions when using library functions<br />

14.4.3 Compliant Solution (POSIX,strerror_r())<br />

This compliant solution uses the POSIX strerror_r() function, which has the same functionality<br />

as strerror() but guarantees thread safety:<br />

#include <br />

#include <br />

#include <br />

enum { BUFFERSIZE = 64 };<br />

void f(FILE *fp) {<br />

fpos_t pos;<br />

errno = 0;<br />

}<br />

if (0 != fgetpos(fp, &pos)) {<br />

char errmsg[BUFFERSIZE];<br />

if (strerror_r(errno, errmsg, BUFFERSIZE) != 0) {<br />

/* Handle error */<br />

}<br />

printf("Could not get the file position: %s\n", errmsg);<br />

}<br />

Linux provides two versions of strerror_r(), known as the XSI-compliant version and the<br />

GNU-specific version. This compliant solution assumes the XSI-compliant version, which is the<br />

default when an application is compiled as required by POSIX (that is, by defining<br />

_POSIX_C_SOURCE or _XOPEN_SOURCE appropriately). The strerror_r() manual page lists<br />

versions that are available on a particular system.<br />

14.4.4 Risk Assessment<br />

Race conditions caused by multiple threads invoking the same library function can lead to abnormal<br />

termination of the application, data integrity violations, or a denial-of-service attack.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON33-C Medium Probable High P4 L3<br />

14.4.5 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

ERR30-C. Set errno to zero before calling a library<br />

function known to set errno, and check<br />

errno only after the function returns a value indicating<br />

failure<br />

CON00-CPP. Avoid assuming functions are<br />

thread safe unless otherwise specified<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 416<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON33-C. Avoid race conditions when using library functions<br />

14.4.6 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

Section 2.9.1, “Thread Safety”<br />

Subclause 7.24.6.2, “The strerror Function”<br />

[Open Group 1997b] Section 10.12, “Thread-Safe POSIX.1 and C-<br />

Language Functions”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 417<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

14.5 CON34-C. Declare objects shared between threads with<br />

appropriate storage durations<br />

Accessing the automatic or thread-local variables of one thread from another thread is implementation-defined<br />

behavior and can cause invalid memory accesses because the execution of threads<br />

can be interwoven within the constraints of the synchronization model. As a result, the referenced<br />

stack frame or thread-local variable may no longer be valid when another thread tries to access it.<br />

Shared static variables can be protected by thread synchronization mechanisms.<br />

However, automatic (local) variables cannot be shared in the same manner because the referenced<br />

stack frame’s thread would need to stop executing, or some other mechanism must be employed<br />

to ensure that the referenced stack frame is still valid. Do not access automatic or thread-local objects<br />

from a thread other than the one with which the object is associated. See DCL30-C. Declare<br />

objects with appropriate storage durations for information on how to declare objects with appropriate<br />

storage durations when data is not being shared between threads.<br />

14.5.1 Noncompliant Code Example (Automatic Storage Duration)<br />

This noncompliant code example passes the address of a variable to a child thread, which prints it<br />

out. The variable has automatic storage duration. Depending on the execution order, the child<br />

thread might reference the variable after the variable’s lifetime in the parent thread. This would<br />

cause the child thread to access an invalid memory location.<br />

#include <br />

#include <br />

int child_thread(void *val) {<br />

int *res = (int *)val;<br />

printf("Result: %d\n", *res);<br />

return 0;<br />

}<br />

void create_thread(thrd_t *tid) {<br />

int val = 1;<br />

if (thrd_success != thrd_create(tid, child_thread, &val)) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

thrd_t tid;<br />

create_thread(&tid);<br />

}<br />

if (thrd_success != thrd_join(tid, NULL)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 418<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

14.5.2 Noncompliant Code Example (Automatic Storage Duration )<br />

One solution is to ensure that all objects with automatic storage duration shared between threads<br />

are declared such that their lifetime extends past the lifetime of the threads. This can be accomplished<br />

using a thread synchronization mechanism, such as thrd_join(). In this code example,<br />

val is declared in main(), where thrd_join() is called. Because the parent thread waits until<br />

the child thread completes before continuing its execution, the shared objects have a lifetime at<br />

least as great as the thread. However, this example relies on implementation-defined behavior and<br />

is nonportable.<br />

#include <br />

#include <br />

int child_thread(void *val) {<br />

int *result = (int *)val;<br />

printf("Result: %d\n", *result); /* Correctly prints 1 */<br />

return 0;<br />

}<br />

void create_thread(thrd_t *tid, int *val) {<br />

if (thrd_success != thrd_create(tid, child_thread, val)) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

int val = 1;<br />

thrd_t tid;<br />

create_thread(&tid, &val);<br />

if (thrd_success != thrd_join(tid, NULL)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

14.5.3 Compliant Solution (Static Storage Duration)<br />

This compliant solution stores the value in an object having static storage duration. The lifetime<br />

of this object is the entire execution of the program; consequently, it can be safely accessed by<br />

any thread.<br />

#include <br />

#include <br />

int child_thread(void *v) {<br />

int *result = (int *)v;<br />

printf("Result: %d\n", *result); /* Correctly prints 1 */<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 419<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

void create_thread(thrd_t *tid) {<br />

static int val = 1;<br />

if (thrd_success != thrd_create(tid, child_thread, &val)) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

thrd_t tid;<br />

create_thread(&tid);<br />

if (thrd_success != thrd_join(tid, NULL)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

14.5.4 Compliant Solution (Allocated Storage Duration)<br />

This compliant solution stores the value passed to the child thread in a dynamically allocated object.<br />

Because this object will persist until explicitly freed, the child thread can safely access its<br />

value.<br />

#include <br />

#include <br />

#include <br />

int child_thread(void *val) {<br />

int *result = (int *)val;<br />

printf("Result: %d\n", *result); /* Correctly prints 1 */<br />

return 0;<br />

}<br />

void create_thread(thrd_t *tid, int *value) {<br />

*value = 1;<br />

if (thrd_success != thrd_create(tid, child_thread,<br />

value)) {<br />

/* Handle error */<br />

}<br />

}<br />

int main(void) {<br />

thrd_t tid;<br />

int *value = (int *)malloc(sizeof(int));<br />

if (!value) {<br />

/* Handle error */<br />

}<br />

create_thread(&tid, value);<br />

if (thrd_success != thrd_join(tid, NULL)) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 420<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

}<br />

}<br />

free(value);<br />

return 0;<br />

14.5.5 Noncompliant Code Example (Thread-Specific Storage)<br />

In this noncompliant code example, the value is stored in thread-specific storage of the parent<br />

thread. However, because thread-specific data is available only to the thread that stores it, the<br />

child_thread() function will set result to a null value.<br />

#include <br />

#include <br />

#include <br />

static tss_t key;<br />

int child_thread(void *v) {<br />

void *result = tss_get(*(tss_t *)v);<br />

printf("Result: %d\n", *(int *)result);<br />

return 0;<br />

}<br />

int create_thread(void *thrd) {<br />

int *val = (int *)malloc(sizeof(int));<br />

if (val == NULL) {<br />

/* Handle error */<br />

}<br />

*val = 1;<br />

if (thrd_success != tss_set(key, val)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_create((thrd_t *)thrd,<br />

child_thread, &key)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t parent_tid, child_tid;<br />

if (thrd_success != tss_create(&key, free)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_create(&parent_tid, create_thread,<br />

&child_tid)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_join(parent_tid, NULL)) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 421<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

}<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_join(child_tid, NULL)) {<br />

/* Handle error */<br />

}<br />

tss_delete(key);<br />

return 0;<br />

14.5.6 Compliant Solution (Thread-Specific Storage)<br />

This compliant solution illustrates how thread-specific storage can be combined with a call to a<br />

thread synchronization mechanism, such as thrd_join(). Because the parent thread waits until<br />

the child thread completes before continuing its execution, the child thread is guaranteed to access<br />

a valid live object.<br />

#include <br />

#include <br />

#include <br />

static tss_t key;<br />

int child_thread(void *v) {<br />

int *result = v;<br />

printf("Result: %d\n", *result); /* Correctly prints 1 */<br />

return 0;<br />

}<br />

int create_thread(void *thrd) {<br />

int *val = (int *)malloc(sizeof(int));<br />

if (val == NULL) {<br />

/* Handle error */<br />

}<br />

*val = 1;<br />

if (thrd_success != tss_set(key, val)) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

void *v = tss_get(key);<br />

if (thrd_success != thrd_create((thrd_t *)thrd,<br />

child_thread, v)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t parent_tid, child_tid;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 422<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

if (thrd_success != tss_create(&key, free)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_create(&parent_tid, create_thread,<br />

&child_tid)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_join(parent_tid, NULL)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != thrd_join(child_tid, NULL)) {<br />

/* Handle error */<br />

}<br />

tss_delete(key);<br />

return 0;<br />

}<br />

This compliant solution uses pointer-to-integer and integer-to-pointer conversions, which have<br />

implementation-defined behavior. (See INT36-C. Converting a pointer to integer or integer to<br />

pointer.)<br />

14.5.7 Compliant Solution (Thread-Local Storage, Windows, Visual Studio)<br />

Similar to the preceding compliant solution, this compliant solution uses thread-local storage<br />

combined with thread synchronization to ensure the child thread is accessing a valid live object. It<br />

uses the Visual Studio–specific __declspec(thread) language extension to provide the threadlocal<br />

storage and the WaitForSingleObject() API to provide the synchronization.<br />

#include <br />

#include <br />

DWORD WINAPI child_thread(LPVOID v) {<br />

int *result = (int *)v;<br />

printf("Result: %d\n", *result); /* Correctly prints 1 */<br />

return NULL;<br />

}<br />

int create_thread(HANDLE *tid) {<br />

/* Declare val as a thread-local value */<br />

__declspec(thread) int val = 1;<br />

*tid = create_thread(NULL, 0, child_thread, &val, 0, NULL);<br />

return *tid == NULL;<br />

}<br />

int main(void) {<br />

HANDLE tid;<br />

if (create_thread(&tid)) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 423<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

}<br />

if (WAIT_OBJECT_0 != WaitForSingleObject(tid, INFINITE)) {<br />

/* Handle error */<br />

}<br />

CloseHandle(tid);<br />

}<br />

return 0;<br />

14.5.8 Noncompliant Code Example (OpenMP, parallel)<br />

It is important to note that local data can be used securely with threads when using other thread<br />

interfaces, so the programmer need not always copy data into nonlocal memory when sharing data<br />

with threads. For example, the shared keyword in The OpenMP® API Specification for Parallel<br />

Programming [OpenMP] can be used in combination with OpenMP’s threading interface to share<br />

local memory without having to worry about whether local automatic variables remain valid.<br />

In this noncompliant code example, a variable j is declared outside a parallel#pragma and not<br />

listed as a private variable. In OpenMP, variables outside a parallel #pragma are shared unless<br />

designated as private.<br />

#include <br />

#include <br />

int main(void) {<br />

int j = 0;<br />

#pragma omp parallel<br />

{<br />

int t = omp_get_thread_num();<br />

printf("Running thread - %d\n", t);<br />

for (int i = 0; i < 5050; i++) {<br />

j++; /* j not private; could be a race condition */<br />

}<br />

printf("Just ran thread - %d\n", t);<br />

printf("loop count %d\n", j);<br />

}<br />

return 0;<br />

}<br />

14.5.9 Compliant Solution (OpenMP, parallel, private)<br />

In this compliant solution, the variable j is declared outside of the parallel#pragma but is explicitly<br />

labeled as private:<br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 424<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON34-C. Declare objects shared between threads with appropriate storage durations<br />

int main(void) {<br />

int j = 0;<br />

#pragma omp parallel private(j)<br />

{<br />

int t = omp_get_thread_num();<br />

printf("Running thread - %d\n", t);<br />

for (int i = 0; i < 5050; i++) {<br />

j++;<br />

}<br />

printf("Just ran thread - %d\n", t);<br />

printf("loop count %d\n", j);<br />

}<br />

return 0;<br />

}<br />

14.5.10 Risk Assessment<br />

Threads that reference the stack of other threads can potentially overwrite important information<br />

on the stack, such as function pointers and return addresses. The compiler may not generate warnings<br />

if the programmer allows one thread to access another thread’s local variables, so a programmer<br />

may not catch a potential error at compile time. The remediation cost for this error is high because<br />

analysis tools have difficulty diagnosing problems with concurrency and race conditions.<br />

Recommendation Severity Likelihood Remediation Cost Priority Level<br />

CON34-C Medium Probable High P4 L3<br />

14.5.11 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

DCL30-C. Declare objects with appropriate<br />

storage durations<br />

14.5.12 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[OpenMP]<br />

6.2.4, “Storage Durations of Objects”<br />

The OpenMP® API Specification for Parallel<br />

Programming<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 425<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON35-C. Avoid deadlock by locking in a predefined order<br />

14.6 CON35-C. Avoid deadlock by locking in a predefined order<br />

Mutexes are used to prevent multiple threads from causing a data race by accessing shared resources<br />

at the same time. Sometimes, when locking mutexes, multiple threads hold each other’s<br />

lock, and the program consequently deadlocks. Four conditions are required for deadlock to occur:<br />

• Mutual exclusion<br />

• Hold and wait<br />

• No preemption<br />

• Circular wait<br />

Deadlock needs all four conditions, so preventing deadlock requires preventing any one of the<br />

four conditions. One simple solution is to lock the mutexes in a predefined order, which prevents<br />

circular wait.<br />

14.6.1 Noncompliant Code Example<br />

The behavior of this noncompliant code example depends on the runtime environment and the<br />

platform’s scheduler. The program is susceptible to deadlock if thread thr1 attempts to lock<br />

ba2’s mutex at the same time thread thr2 attempts to lock ba1’s mutex in the deposit() function.<br />

#include <br />

#include <br />

typedef struct {<br />

int balance;<br />

mtx_t balance_mutex;<br />

} bank_account;<br />

typedef struct {<br />

bank_account *from;<br />

bank_account *to;<br />

int amount;<br />

} transaction;<br />

void create_bank_account(bank_account **ba,<br />

int initial_amount) {<br />

bank_account *nba = (bank_account *)malloc(<br />

sizeof(bank_account)<br />

);<br />

if (nba == NULL) {<br />

/* Handle error */<br />

}<br />

nba->balance = initial_amount;<br />

if (thrd_success<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 426<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON35-C. Avoid deadlock by locking in a predefined order<br />

}<br />

!= mtx_init(&nba->balance_mutex, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

*ba = nba;<br />

int deposit(void *ptr) {<br />

transaction *args = (transaction *)ptr;<br />

if (thrd_success != mtx_lock(&args->from->balance_mutex)) {<br />

/* Handle error */<br />

}<br />

/* Not enough balance to transfer */<br />

if (args->from->balance < args->amount) {<br />

if (thrd_success<br />

!= mtx_unlock(&args->from->balance_mutex)) {<br />

/* Handle error */<br />

}<br />

return -1; /* Indicate error */<br />

}<br />

if (thrd_success != mtx_lock(&args->to->balance_mutex)) {<br />

/* Handle error */<br />

}<br />

args->from->balance -= args->amount;<br />

args->to->balance += args->amount;<br />

if (thrd_success<br />

!= mtx_unlock(&args->from->balance_mutex)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success<br />

!= mtx_unlock(&args->to->balance_mutex)) {<br />

/* Handle error */<br />

}<br />

}<br />

free(ptr);<br />

return 0;<br />

int main(void) {<br />

thrd_t thr1, thr2;<br />

transaction *arg1;<br />

transaction *arg2;<br />

bank_account *ba1;<br />

bank_account *ba2;<br />

create_bank_account(&ba1, 1000);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 427<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON35-C. Avoid deadlock by locking in a predefined order<br />

create_bank_account(&ba2, 1000);<br />

arg1 = (transaction *)malloc(sizeof(transaction));<br />

if (arg1 == NULL) {<br />

/* Handle error */<br />

}<br />

arg2 = (transaction *)malloc(sizeof(transaction));<br />

if (arg2 == NULL) {<br />

/* Handle error */<br />

}<br />

arg1->from = ba1;<br />

arg1->to = ba2;<br />

arg1->amount = 100;<br />

arg2->from = ba2;<br />

arg2->to = ba1;<br />

arg2->amount = 100;<br />

}<br />

/* Perform the deposits */<br />

if (thrd_success<br />

!= thrd_create(&thr1, deposit, (void *)arg1)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success<br />

!= thrd_create(&thr2, deposit, (void *)arg2)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

14.6.2 Compliant Solution<br />

This compliant solution eliminates the circular wait condition by establishing a predefined order<br />

for locking in the deposit() function. Each thread will lock on the basis of the bank_account<br />

ID, which is set when the bank_account struct is initialized.<br />

#include <br />

#include <br />

typedef struct {<br />

int balance;<br />

mtx_t balance_mutex;<br />

/* Should not change after initialization */<br />

unsigned int id;<br />

} bank_account;<br />

typedef struct {<br />

bank_account *from;<br />

bank_account *to;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 428<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON35-C. Avoid deadlock by locking in a predefined order<br />

int amount;<br />

} transaction;<br />

unsigned int global_id = 1;<br />

void create_bank_account(bank_account **ba,<br />

int initial_amount) {<br />

bank_account *nba = (bank_account *)malloc(<br />

sizeof(bank_account)<br />

);<br />

if (nba == NULL) {<br />

/* Handle error */<br />

}<br />

nba->balance = initial_amount;<br />

if (thrd_success<br />

!= mtx_init(&nba->balance_mutex, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

}<br />

nba->id = global_id++;<br />

*ba = nba;<br />

int deposit(void *ptr) {<br />

transaction *args = (transaction *)ptr;<br />

int result = -1;<br />

mtx_t *first;<br />

mtx_t *second;<br />

if (args->from->id == args->to->id) {<br />

return -1; /* Indicate error */<br />

}<br />

/* Ensure proper ordering for locking */<br />

if (args->from->id < args->to->id) {<br />

first = &args->from->balance_mutex;<br />

second = &args->to->balance_mutex;<br />

} else {<br />

first = &args->to->balance_mutex;<br />

second = &args->from->balance_mutex;<br />

}<br />

if (thrd_success != mtx_lock(first)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != mtx_lock(second)) {<br />

/* Handle error */<br />

}<br />

/* Not enough balance to transfer */<br />

if (args->from->balance >= args->amount) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 429<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON35-C. Avoid deadlock by locking in a predefined order<br />

}<br />

args->from->balance -= args->amount;<br />

args->to->balance += args->amount;<br />

result = 0;<br />

}<br />

if (thrd_success != mtx_unlock(second)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != mtx_unlock(first)) {<br />

/* Handle error */<br />

}<br />

free(ptr);<br />

return result;<br />

14.6.3 Risk Assessment<br />

Deadlock prevents multiple threads from progressing, halting program execution. A denial-of-service<br />

attack is possible if the attacker can create the conditions for deadlock.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON35-C Low Probable Medium P4 L3<br />

14.6.4 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java LCK07-J. Avoid deadlock by requesting and<br />

releasing locks in the same order<br />

MITRE CWE<br />

CWE-764, Multiple Locks of a Critical Resource<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 430<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON36-C. Wrap functions that can spuriously wake up in a loop<br />

14.7 CON36-C. Wrap functions that can spuriously wake up in a loop<br />

The cnd_wait() and cnd_timedwait() functions temporarily cede possession of a mutex so<br />

that other threads that may be requesting the mutex can proceed. These functions must always be<br />

called from code that is protected by locking a mutex. The waiting thread resumes execution only<br />

after it has been notified, generally as the result of the invocation of the cnd_signal() or<br />

cnd_broadcast() function invoked by another thread. The cnd_wait() function must be invoked<br />

from a loop that checks whether a condition predicate holds. A condition predicate is an expression<br />

constructed from the variables of a function that must be true for a thread to be allowed<br />

to continue execution. The thread pauses execution, via cnd_wait(), cnd_timedwait(), or<br />

some other mechanism, and is resumed later, presumably when the condition predicate is true and<br />

the thread is notified.<br />

#include <br />

#include <br />

extern bool until_finish(void);<br />

extern mtx_t lock;<br />

extern cnd_t condition;<br />

void func(void) {<br />

if (thrd_success != mtx_lock(&lock)) {<br />

/* Handle error */<br />

}<br />

while (until_finish()) { /* Predicate does not hold */<br />

if (thrd_success != cnd_wait(&condition, &lock)) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Resume when condition holds */<br />

}<br />

if (thrd_success != mtx_unlock(&lock)) {<br />

/* Handle error */<br />

}<br />

The notification mechanism notifies the waiting thread and allows it to check its condition predicate.<br />

The invocation of cnd_broadcast() in another thread cannot precisely determine which<br />

waiting thread will be resumed. Condition predicate statements allow notified threads to determine<br />

whether they should resume upon receiving the notification.<br />

14.7.1 Noncompliant Code Example<br />

This noncompliant code example monitors a linked list and assigns one thread to consume list elements<br />

when the list is nonempty.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 431<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON36-C. Wrap functions that can spuriously wake up in a loop<br />

This thread pauses execution using cnd_wait() and resumes when notified, presumably when<br />

the list has elements to be consumed. It is possible for the thread to be notified even if the list is<br />

still empty, perhaps because the notifying thread used cnd_broadcast(), which notifies all<br />

threads. Notification using cnd_broadcast() is frequently preferred over using cnd_signal().<br />

(See CON38-C. Preserve thread safety and liveness when using condition variables for<br />

more information.)<br />

A condition predicate is typically the negation of the condition expression in the loop. In this noncompliant<br />

code example, the condition predicate for removing an element from a linked list is<br />

(list->next != NULL), whereas the condition expression for the while loop condition is<br />

(list->next == NULL).<br />

This noncompliant code example nests the cnd_wait() function inside an if block and consequently<br />

fails to check the condition predicate after the notification is received. If the notification<br />

was spurious or malicious, the thread would wake up prematurely.<br />

#include <br />

#include <br />

struct node_t {<br />

void *node;<br />

struct node_t *next;<br />

};<br />

struct node_t list;<br />

static mtx_t lock;<br />

static cnd_t condition;<br />

void consume_list_element(void) {<br />

if (thrd_success != mtx_lock(&lock)) {<br />

/* Handle error */<br />

}<br />

}<br />

if (list.next == NULL) {<br />

if (thrd_success != cnd_wait(&condition, &lock)) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Proceed when condition holds */<br />

if (thrd_success != mtx_unlock(&lock)) {<br />

/* Handle error */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 432<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON36-C. Wrap functions that can spuriously wake up in a loop<br />

14.7.2 Compliant Solution<br />

This compliant solution calls the cnd_wait() function from within a while loop to check the<br />

condition both before and after the call to cnd_wait():<br />

#include <br />

#include <br />

struct node_t {<br />

void *node;<br />

struct node_t *next;<br />

};<br />

struct node_t list;<br />

static mtx_t lock;<br />

static cnd_t condition;<br />

void consume_list_element(void) {<br />

if (thrd_success != mtx_lock(&lock)) {<br />

/* Handle error */<br />

}<br />

while (list.next == NULL) {<br />

if (thrd_success != cnd_wait(&condition, &lock)) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Proceed when condition holds */<br />

}<br />

if (thrd_success != mtx_unlock(&lock)) {<br />

/* Handle error */<br />

}<br />

14.7.3 Risk Assessment<br />

Failure to enclose calls to the cnd_wait() or cnd_timedwait() functions inside a while loop<br />

can lead to indefinite blocking and denial of service (DoS).<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON36-C Low Unlikely Medium P2 L3<br />

14.7.4 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java THI03-J. Always invoke wait() and await()<br />

methods inside a loop<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 433<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON36-C. Wrap functions that can spuriously wake up in a loop<br />

14.7.5 Bibliography<br />

[ISO/IEC 9899:2011]<br />

[Lea 2000]<br />

7.17.7.4, “The atomic_compare_exchange<br />

Generic Functions”<br />

1.3.2, “Liveness”<br />

3.2.2, “Monitor Mechanics”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 434<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON37-C. Do not call signal() in a multithreaded program<br />

14.8 CON37-C. Do not call signal() in a multithreaded program<br />

Calling the signal() function in a multithreaded program is undefined behavior. (See undefined<br />

behavior 135.)<br />

14.8.1 Noncompliant Code Example<br />

This noncompliant code example invokes the signal() function from a multithreaded program:<br />

#include <br />

#include <br />

#include <br />

volatile sig_atomic_t flag = 0;<br />

void handler(int signum) {<br />

flag = 1;<br />

}<br />

/* Runs until user sends SIGUSR1 */<br />

int func(void *data) {<br />

while (!flag) {<br />

/* ... */<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

signal(SIGUSR1, handler); /* Undefined behavior */<br />

thrd_t tid;<br />

}<br />

if (thrd_success != thrd_create(&tid, func, NULL)) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

return 0;<br />

NOTE: The SIGUSR1 signal value is not defined in the C <strong>Standard</strong>; consequently, this is not a C-<br />

compliant code example.<br />

14.8.2 Compliant Solution<br />

This compliant solution uses an object of type atomic_bool to indicate when the child thread<br />

should terminate its loop:<br />

#include <br />

#include <br />

#include <br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 435<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON37-C. Do not call signal() in a multithreaded program<br />

#include <br />

atomic_bool flag = ATOMIC_VAR_INIT(false);<br />

int func(void *data) {<br />

while (!flag) {<br />

/* ... */<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t tid;<br />

if (thrd_success != thrd_create(&tid, func, NULL)) {<br />

/* Handle error */<br />

}<br />

/* ... */<br />

/* Set flag when done */<br />

flag = true;<br />

}<br />

return 0;<br />

14.8.3 Exceptions<br />

CON37-C-EX1: Implementations such as POSIX that provide defined behavior when multithreaded<br />

programs use custom signal handlers are exempt from this rule [IEEE Std 1003.1-2013].<br />

14.8.4 Risk Assessment<br />

Mixing signals and threads causes undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON37-C Low Probable Low P6 L2<br />

14.8.5 Bibliography<br />

[IEEE Std 1003.1-2013]<br />

XSH 2.9.1, “Thread Safety”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 436<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

14.9 CON38-C. Preserve thread safety and liveness when using<br />

condition variables<br />

Both thread safety and liveness are concerns when using condition variables. The thread-safety<br />

property requires that all objects maintain consistent states in a multithreaded environment [Lea<br />

2000]. The liveness property requires that every operation or function invocation execute to completion<br />

without interruption; for example, there is no deadlock.<br />

Condition variables must be used inside a while loop. (See CON36-C. Wrap functions that can<br />

spuriously wake up in a loop for more information.) To guarantee liveness, programs must test the<br />

while loop condition before invoking the cnd_wait() function. This early test checks whether<br />

another thread has already satisfied the condition predicate and has sent a notification. Invoking<br />

the cnd_wait() function after the notification has been sent results in indefinite blocking.<br />

To guarantee thread safety, programs must test the while loop condition after returning from the<br />

cnd_wait() function. When a given thread invokes the cnd_wait() function, it will attempt to<br />

block until its condition variable is signaled by a call to cnd_broadcast() or to cnd_signal().<br />

The cnd_signal() function unblocks one of the threads that are blocked on the specified condition<br />

variable at the time of the call. If multiple threads are waiting on the same condition variable,<br />

the scheduler can select any of those threads to be awakened (assuming that all threads have the<br />

same priority level). The cnd_broadcast() function unblocks all of the threads that are blocked<br />

on the specified condition variable at the time of the call. The order in which threads execute following<br />

a call to cnd_broadcast() is unspecified. Consequently, an unrelated thread could start<br />

executing, discover that its condition predicate is satisfied, and resume execution even though it<br />

was supposed to remain dormant. For these reasons, threads must check the condition predicate<br />

after the cnd_wait() function returns. A while loop is the best choice for checking the condition<br />

predicate both before and after invoking cnd_wait().<br />

The use of cnd_signal() is safe if each thread uses a unique condition variable. If multiple<br />

threads share a condition variable, the use of cnd_signal() is safe only if the following conditions<br />

are met:<br />

• All threads must perform the same set of operations after waking up, which means that any<br />

thread can be selected to wake up and resume for a single invocation of cnd_signal().<br />

• Only one thread is required to wake upon receiving the signal.<br />

The cnd_broadcast() function can be used to unblock all of the threads that are blocked on the<br />

specified condition variable if the use of cnd_signal() is unsafe.<br />

14.9.1 Noncompliant Code Example (cnd_signal())<br />

This noncompliant code example uses five threads that are intended to execute sequentially according<br />

to the step level assigned to each thread when it is created (serialized processing). The<br />

current_step variable holds the current step level and is incremented when the respective<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 437<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

thread completes. Finally, another thread is signaled so that the next step can be executed. Each<br />

thread waits until its step level is ready, and the cnd_wait() function call is wrapped inside a<br />

while loop, in compliance with CON36-C. Wrap functions that can spuriously wake up in a loop.<br />

#include <br />

#include <br />

enum { NTHREADS = 5 };<br />

mtx_t mutex;<br />

cnd_t cond;<br />

int run_step(void *t) {<br />

static int current_step = 0;<br />

size_t my_step = *(size_t *)t;<br />

if (thrd_success != mtx_lock(&mutex)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu has the lock\n", my_step);<br />

while (current_step != my_step) {<br />

printf("Thread %zu is sleeping...\n", my_step);<br />

if (thrd_success != cnd_wait(&cond, &mutex)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu woke up\n", my_step);<br />

}<br />

/* Do processing ... */<br />

printf("Thread %zu is processing...\n", my_step);<br />

current_step++;<br />

/* Signal awaiting task */<br />

if (thrd_success != cnd_signal(&cond)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu is exiting...\n", my_step);<br />

if (thrd_success != mtx_unlock(&mutex)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t threads[NTHREADS];<br />

size_t step[NTHREADS];<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 438<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

if (thrd_success != mtx_init(&mutex, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

if (thrd_success != cnd_init(&cond)) {<br />

/* Handle error */<br />

}<br />

/* Create threads */<br />

for (size_t i = 0; i < NTHREADS; ++i) {<br />

step[i] = i;<br />

}<br />

if (thrd_success != thrd_create(&threads[i], run_step,<br />

&step[i])) {<br />

/* Handle error */<br />

}<br />

/* Wait for all threads to complete */<br />

for (size_t i = NTHREADS; i != 0; --i) {<br />

if (thrd_success != thrd_join(threads[i-1], NULL)) {<br />

/* Handle error */<br />

}<br />

}<br />

}<br />

mtx_destroy(&mutex);<br />

cnd_destroy(&cond);<br />

return 0;<br />

In this example, all threads share a condition variable. Each thread has its own distinct condition<br />

predicate because each thread requires current_step to have a different value before proceeding.<br />

When the condition variable is signaled, any of the waiting threads can wake up.<br />

The following table illustrates a possible scenario in which the liveness property is violated. If, by<br />

chance, the notified thread is not the thread with the next step value, that thread will wait again.<br />

No additional notifications can occur, and eventually the pool of available threads will be exhausted.<br />

Deadlock: Out-of-Sequence Step Value<br />

Time Thread #<br />

(my_step)<br />

current_step<br />

Action<br />

0 3 0 Thread 3 executes first time: predicate is FALSE -<br />

> wait()<br />

1 2 0 Thread 2 executes first time: predicate is FALSE -<br />

> wait()<br />

2 4 0 Thread 4 executes first time: predicate is FALSE -<br />

> wait()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 439<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

Time Thread #<br />

(my_step)<br />

current_step<br />

Action<br />

3 0 0 Thread 0 executes first time: predicate is TRUE -><br />

current_step++; cnd_signal()<br />

4 1 1 Thread 1 executes first time: predicate is TRUE -><br />

current_step++; cnd_signal()<br />

5 3 2 Thread 3 wakes up (scheduler choice): predicate is<br />

FALSE -> wait()<br />

6 — — Thread exhaustion! No more threads to run, and a<br />

conditional variable signal is needed to wake up the<br />

others<br />

This noncompliant code example violates the liveness property.<br />

14.9.2 Compliant Solution (cnd_broadcast())<br />

This compliant solution uses the cnd_broadcast() function to signal all waiting threads instead<br />

of a single random thread. Only the run_step() thread code from the noncompliant code example<br />

is modified, as follows:<br />

#include <br />

#include <br />

mtx_t mutex;<br />

cnd_t cond;<br />

int run_step(void *t) {<br />

static size_t current_step = 0;<br />

size_t my_step = *(size_t *)t;<br />

if (thrd_success != mtx_lock(&mutex)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu has the lock\n", my_step);<br />

while (current_step != my_step) {<br />

printf("Thread %zu is sleeping...\n", my_step);<br />

if (thrd_success != cnd_wait(&cond, &mutex)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu woke up\n", my_step);<br />

}<br />

/* Do processing ... */<br />

printf("Thread %zu is processing...\n", my_step);<br />

current_step++;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 440<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

/* Signal ALL waiting tasks */<br />

if (thrd_success != cnd_broadcast(&cond)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu is exiting...\n", my_step);<br />

}<br />

if (thrd_success != mtx_unlock(&mutex)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

Awakening all threads solves and guarantees the liveness property because each thread will execute<br />

its condition predicate test, and exactly one will succeed and continue execution.<br />

14.9.3 Compliant Solution (Using cnd_signal() with a Unique Condition<br />

Variable per Thread)<br />

Another compliant solution is to use a unique condition variable for each thread (all associated<br />

with the same mutex). In this case, cnd_signal() wakes up only the thread that is waiting on it.<br />

This solution is more efficient than using cnd_broadcast() because only the desired thread is<br />

awakened.<br />

The condition predicate of the signaled thread must be true; otherwise, a deadlock will occur.<br />

#include <br />

#include <br />

enum { NTHREADS = 5 };<br />

mtx_t mutex;<br />

cnd_t cond[NTHREADS];<br />

int run_step(void *t) {<br />

static size_t current_step = 0;<br />

size_t my_step = *(size_t *)t;<br />

if (thrd_success != mtx_lock(&mutex)) {<br />

/* Handle error */<br />

}<br />

printf("Thread %zu has the lock\n", my_step);<br />

while (current_step != my_step) {<br />

printf("Thread %zu is sleeping...\n", my_step);<br />

if (thrd_success != cnd_wait(&cond[my_step], &mutex)) {<br />

/* Handle error */<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 441<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

}<br />

}<br />

printf("Thread %zu woke up\n", my_step);<br />

/* Do processing ... */<br />

printf("Thread %zu is processing...\n", my_step);<br />

current_step++;<br />

/* Signal next step thread */<br />

if ((my_step + 1) < NTHREADS) {<br />

if (thrd_success != cnd_signal(&cond[my_step + 1])) {<br />

/* Handle error */<br />

}<br />

}<br />

printf("Thread %zu is exiting...\n", my_step);<br />

}<br />

if (thrd_success != mtx_unlock(&mutex)) {<br />

/* Handle error */<br />

}<br />

return 0;<br />

int main(void) {<br />

thrd_t threads[NTHREADS];<br />

size_t step[NTHREADS];<br />

if (thrd_success != mtx_init(&mutex, mtx_plain)) {<br />

/* Handle error */<br />

}<br />

for (size_t i = 0; i< NTHREADS; ++i) {<br />

if (thrd_success != cnd_init(&cond[i])) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Create threads */<br />

for (size_t i = 0; i < NTHREADS; ++i) {<br />

step[i] = i;<br />

if (thrd_success != thrd_create(&threads[i], run_step,<br />

&step[i])) {<br />

/* Handle error */<br />

}<br />

}<br />

/* Wait for all threads to complete */<br />

for (size_t i = NTHREADS; i != 0; --i) {<br />

if (thrd_success != thrd_join(threads[i-1], NULL)) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 442<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

}<br />

}<br />

/* Handle error */<br />

mtx_destroy(&mutex);<br />

}<br />

for (size_t i = 0; i < NTHREADS; ++i) {<br />

cnd_destroy(&cond[i]);<br />

}<br />

return 0;<br />

14.9.4 Compliant Solution (Windows, Condition Variables)<br />

This compliant solution uses a CONDITION_VARIABLE object, available on Microsoft Windows<br />

(Vista and later):<br />

#include <br />

#include <br />

CRITICAL_SECTION lock;<br />

CONDITION_VARIABLE cond;<br />

DWORD WINAPI run_step(LPVOID t) {<br />

static size_t current_step = 0;<br />

size_t my_step = (size_t)t;<br />

EnterCriticalSection(&lock);<br />

printf("Thread %zu has the lock\n", my_step);<br />

while (current_step != my_step) {<br />

printf("Thread %zu is sleeping...\n", my_step);<br />

if (!SleepConditionVariableCS(&cond, &lock, INFINITE)) {<br />

/* Handle error */<br />

}<br />

}<br />

printf("Thread %zu woke up\n", my_step);<br />

/* Do processing ... */<br />

printf("Thread %zu is processing...\n", my_step);<br />

current_step++;<br />

LeaveCriticalSection(&lock);<br />

/* Signal ALL waiting tasks */<br />

WakeAllConditionVariable(&cond);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 443<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON38-C. Preserve thread safety and liveness when using condition variables<br />

}<br />

printf("Thread %zu is exiting...\n", my_step);<br />

return 0;<br />

enum { NTHREADS = 5 };<br />

int main(void) {<br />

HANDLE threads[NTHREADS];<br />

InitializeCriticalSection(&lock);<br />

InitializeConditionVariable(&cond);<br />

/* Create threads */<br />

for (size_t i = 0; i < NTHREADS; ++i) {<br />

threads[i] = CreateThread(NULL, 0, run_step, (LPVOID)i, 0,<br />

NULL);<br />

}<br />

/* Wait for all threads to complete */<br />

WaitForMultipleObjects(NTHREADS, threads, TRUE, INFINITE);<br />

DeleteCriticalSection(&lock);<br />

}<br />

return 0;<br />

14.9.5 Risk Assessment<br />

Failing to preserve the thread safety and liveness of a program when using condition variables can<br />

lead to indefinite blocking and denial of service (DoS).<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON38-C Low Unlikely Medium P2 L3<br />

14.9.6 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java THI02-J. Notify all waiting threads rather than<br />

a single thread<br />

14.9.7 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[Lea 2000]<br />

XSH, System Interfaces,<br />

pthread_cond_broadcast<br />

XSH, System Interfaces,<br />

pthread_cond_signal<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 444<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON39-C. Do not join or detach a thread that was previously joined or detached<br />

14.10 CON39-C. Do not join or detach a thread that was previously<br />

joined or detached<br />

The C <strong>Standard</strong>, 7.26.5.6 [ISO/IEC 9899:2011], states that a thread shall not be joined once it was<br />

previously joined or detached. Similarly, subclause 7.26.5.3 states that a thread shall not be detached<br />

once it was previously joined or detached. Violating either of these subclauses results in<br />

undefined behavior.<br />

14.10.1 Noncompliant Code Example<br />

This noncompliant code example detaches a thread that is later joined.<br />

#include <br />

#include <br />

int thread_func(void *arg) {<br />

/* Do work */<br />

thrd_detach(thrd_current());<br />

return 0;<br />

}<br />

int main(void) {<br />

thrd_t t;<br />

if (thrd_success != thrd_create(&t, thread_func, NULL)) {<br />

/* Handle error */<br />

return 0;<br />

}<br />

}<br />

if (thrd_success != thrd_join(t, 0)) {<br />

/* Handle error */<br />

return 0;<br />

}<br />

return 0;<br />

14.10.2 Compliant Solution<br />

This compliant solution does not detach the thread. Its resources are released upon successfully<br />

joining with the main thread:<br />

#include <br />

#include <br />

int thread_func(void *arg) {<br />

/* Do work */<br />

return 0;<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 445<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON39-C. Do not join or detach a thread that was previously joined or detached<br />

int main(void) {<br />

thrd_t t;<br />

if (thrd_success != thrd_create(&t, thread_func, NULL)) {<br />

/* Handle error */<br />

return 0;<br />

}<br />

}<br />

if (thrd_success != thrd_join(t, 0)) {<br />

/* Handle error */<br />

return 0;<br />

}<br />

return 0;<br />

14.10.3 Risk Assessment<br />

Joining or detaching a previously joined or detached thread is undefined behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON39-C Low Likely Medium P6 L2<br />

14.10.4 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.26.5.3, “The thrd_detach Function”<br />

Subclause 7.26.5.6, “The thrd_join Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 446<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON40-C. Do not refer to an atomic variable twice in an expression<br />

14.11 CON40-C. Do not refer to an atomic variable twice in an<br />

expression<br />

A consistent locking policy guarantees that multiple threads cannot simultaneously access or<br />

modify shared data. Atomic variables eliminate the need for locks by guaranteeing thread safety<br />

when certain operations are performed on them. The thread-safe operations on atomic variables<br />

are specified in the C <strong>Standard</strong>, subclauses 7.17.7 and 7.17.8 [ISO/IEC 9899:2011]. While atomic<br />

operations can be combined, combined operations do not provide the thread safety provided by<br />

individual atomic operations.<br />

Every time an atomic variable appears on the left side of an assignment operator, including a compound<br />

assignment operator such as *=, an atomic write is performed on the variable. The use of<br />

the increment (++) or decrement (--) operators on an atomic variable constitutes an atomic<br />

read-and-write operation and is consequently thread-safe. Any reference of an atomic variable anywhere<br />

else in an expression indicates a distinct atomic read on the variable.<br />

If the same atomic variable appears twice in an expression, then two atomic reads, or an atomic<br />

read and an atomic write, are required. Such a pair of atomic operations is not thread-safe, as another<br />

thread can modify the atomic variable between the two operations. Consequently, an atomic<br />

variable must not be referenced twice in the same expression.<br />

14.11.1 Noncompliant Code Example (atomic_bool)<br />

This noncompliant code example declares a shared atomic_boolflag variable and provides a<br />

toggle_flag() method that negates the current value of flag:<br />

#include <br />

#include <br />

static atomic_bool flag = ATOMIC_VAR_INIT(false);<br />

void init_flag(void) {<br />

atomic_init(&flag, false);<br />

}<br />

void toggle_flag(void) {<br />

bool temp_flag = atomic_load(&flag);<br />

temp_flag = !temp_flag;<br />

atomic_store(&flag, temp_flag);<br />

}<br />

bool get_flag(void) {<br />

return atomic_load(&flag);<br />

}<br />

Execution of this code may result in a data race because the value of flag is read, negated, and<br />

written back. This occurs even though the read and write are both atomic.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 447<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON40-C. Do not refer to an atomic variable twice in an expression<br />

Consider, for example, two threads that call toggle_flag(). The expected effect of toggling<br />

flag twice is that it is restored to its original value. However, the scenario in the following table<br />

leaves flag in the incorrect state.<br />

toggle_flag() without Compare-and-Exchange<br />

Time flag Thread Action<br />

1 true t1 Reads the current value<br />

of flag, true, into a<br />

cache<br />

2 true t2 Reads the current value<br />

of flag, (still) true,<br />

into a different cache<br />

3 true t1 Toggles the temporary<br />

variable in the cache to<br />

false<br />

4 true t2 Toggles the temporary<br />

variable in the different<br />

cache to false<br />

5 false t1 Writes the cache variable’s<br />

value to flag<br />

6 false t2 Writes the different cache<br />

variable’s value to flag<br />

As a result, the effect of the call by t2 is not reflected in flag; the program behaves as if toggle_flag()<br />

was called only once, not twice.<br />

14.11.2 Compliant Solution (atomic_compare_exchange_weak())<br />

This compliant solution uses a compare-and-exchange to guarantee that the correct value is stored<br />

in flag. All updates are visible to other threads. The call to atomic_compare_exchange_weak()<br />

is in a loop in conformance with CON41-C. Wrap functions that can fail spuriously<br />

in a loop.<br />

#include <br />

#include <br />

static atomic_bool flag = ATOMIC_VAR_INIT(false);<br />

void init_flag(void) {<br />

atomic_init(&flag, false);<br />

}<br />

void toggle_flag(void) {<br />

bool old_flag = atomic_load(&flag);<br />

bool new_flag;<br />

do {<br />

new_flag = !old_flag;<br />

} while (!atomic_compare_exchange_weak(&flag, &old_flag,<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 448<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON40-C. Do not refer to an atomic variable twice in an expression<br />

new_flag));<br />

}<br />

bool get_flag(void) {<br />

return atomic_load(&flag);<br />

}<br />

An alternative solution is to use the atomic_flag data type for managing Boolean values atomically.<br />

However, atomic_flag does not support a toggle operation.<br />

14.11.3 Compliant Solution (Compound Assignment)<br />

This compliant solution uses the ^= assignment operation to toggle flag. This operation is guaranteed<br />

to be atomic, according to the C <strong>Standard</strong>, 6.5.16.2, paragraph 3. This operation performs a<br />

bitwise-exclusive-or between its arguments, but for Boolean arguments, this is equivalent to negation.<br />

#include <br />

#include <br />

static atomic_bool flag = ATOMIC_VAR_INIT(false);<br />

void toggle_flag(void) {<br />

flag ^= 1;<br />

}<br />

bool get_flag(void) {<br />

return flag;<br />

}<br />

An alternative solution is to use a mutex to protect the atomic operation, but this solution loses the<br />

performance benefits of atomic variables.<br />

14.11.4 Noncompliant Code Example<br />

This noncompliant code example takes an atomic global variable n and computes n + (n - 1)<br />

+ (n - 2) + ... + 1, using the formula n * (n + 1) / 2:<br />

#include <br />

atomic_int n = ATOMIC_VAR_INIT(0);<br />

int compute_sum(void) {<br />

return n * (n + 1) / 2;<br />

}<br />

The value of n may change between the two atomic reads of n in the expression, yielding an incorrect<br />

result.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 449<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON40-C. Do not refer to an atomic variable twice in an expression<br />

14.11.5 Compliant Solution<br />

This compliant solution passes the atomic variable as a function parameter, forcing the variable to<br />

be copied and guaranteeing a correct result:<br />

#include <br />

int compute_sum(atomic_int n) {<br />

return n * (n + 1) / 2;<br />

}<br />

14.11.6 Risk Assessment<br />

When operations on atomic variables are assumed to be atomic, but are not atomic, surprising data<br />

races can occur, leading to corrupted data and invalid control flow.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON40-C Medium Probable Medium P8 L2<br />

14.11.7 Related Guidelines<br />

MITRE CWE<br />

CWE-366, Race Condition within a Thread<br />

CWE-413, Improper Resource Locking<br />

CWE-567, Unsynchronized Access to Shared<br />

Data in a Multithreaded Context<br />

CWE-667, Improper Locking<br />

14.11.8 Bibliography<br />

[ISO/IEC 9899:2011]<br />

6.5.16.2, “Compound Assignment”<br />

7.17, “Atomics”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 450<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON41-C. Wrap functions that can fail spuriously in a loop<br />

14.12 CON41-C. Wrap functions that can fail spuriously in a loop<br />

Functions that can fail spuriously should be wrapped in a loop. The atomic_compare_exchange_weak()<br />

and atomic_compare_exchange_weak_explicit() functions both attempt<br />

to set an atomic variable to a new value but only if it currently possesses a known old value. Unlike<br />

the related functions atomic_compare_exchange_strong() and atomic_compare_exchange_strong_explicit(),<br />

these functions are permitted to fail spuriously. This makes<br />

these functions faster on some platforms—for example, on architectures that implement compareand-exchange<br />

using load-linked/store-conditional instructions, such as Alpha, ARM, MIPS, and<br />

PowerPC. The C <strong>Standard</strong>, 7.17.7.4, paragraph 4 [ISO/IEC 9899:2011], describes this behavior:<br />

A weak compare-and-exchange operation may fail spuriously. That is, even when the<br />

contents of memory referred to by expected and object are equal, it may return zero<br />

and store back to expected the same memory contents that were originally there.<br />

14.12.1 Noncompliant Code Example<br />

In this noncompliant code example, reorganize_data_structure() is to be used as an argument<br />

to thrd_create(). After reorganizing, the function attempts to replace the head pointer<br />

so that it points to the new version. If no other thread has changed the head pointer since it was<br />

originally loaded, reorganize_data_structure() is intended to exit the thread with a result<br />

of true, indicating success. Otherwise, the new reorganization attempt is discarded and the<br />

thread is exited with a result of false. However, atomic_compare_exchange_weak() may<br />

fail even when the head pointer has not changed. Therefore, reorganize_data_structure()<br />

may perform the work and then discard it unnecessarily.<br />

#include <br />

#include <br />

struct data {<br />

struct data *next;<br />

/* ... */<br />

};<br />

extern void cleanup_data_structure(struct data *head);<br />

int reorganize_data_structure(void *thread_arg) {<br />

struct data *_Atomic *ptr_to_head = thread_arg;<br />

struct data *old_head = atomic_load(ptr_to_head);<br />

struct data *new_head;<br />

bool success;<br />

/* ... Reorganize the data structure ... */<br />

success = atomic_compare_exchange_weak(ptr_to_head,<br />

&old_head, new_head);<br />

if (!success) {<br />

cleanup_data_structure(new_head);<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 451<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON41-C. Wrap functions that can fail spuriously in a loop<br />

}<br />

}<br />

return success; /* Exit the thread */<br />

14.12.2 Compliant Solution (atomic_compare_exchange_weak())<br />

To recover from spurious failures, a loop must be used. However, atomic_compare_exchange_weak()<br />

might fail because the head pointer changed, or the failure may be spurious. In<br />

either case, the thread must perform the work repeatedly until the compare-and-exchange succeeds,<br />

as shown in this compliant solution:<br />

#include <br />

#include <br />

#include <br />

struct data {<br />

struct data *next;<br />

/* ... */<br />

};<br />

extern void cleanup_data_structure(struct data *head);<br />

int reorganize_data_structure(void *thread_arg) {<br />

struct data *_Atomic *ptr_to_head = thread_arg;<br />

struct data *old_head = atomic_load(ptr_to_head);<br />

struct data *new_head = NULL;<br />

struct data *saved_old_head;<br />

bool success;<br />

do {<br />

if (new_head != NULL) {<br />

cleanup_data_structure(new_head);<br />

}<br />

saved_old_head = old_head;<br />

/* ... Reorganize the data structure ... */<br />

}<br />

} while (!(success = atomic_compare_exchange_weak(<br />

ptr_to_head, &old_head, new_head<br />

)) && old_head == saved_old_head);<br />

return success; /* Exit the thread */<br />

This loop could also be part of a larger control flow; for example, the thread from the noncompliant<br />

code example could be retried if it returns false.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 452<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON41-C. Wrap functions that can fail spuriously in a loop<br />

14.12.3 Compliant Solution (atomic_compare_exchange_strong())<br />

When a weak compare-and-exchange would require a loop and a strong one would not, the strong<br />

one is preferable, as in this compliant solution:<br />

#include <br />

#include <br />

struct data {<br />

struct data *next;<br />

/* ... */<br />

};<br />

extern void cleanup_data_structure(struct data *head);<br />

int reorganize_data_structure(void *thread_arg) {<br />

struct data *_Atomic *ptr_to_head = thread_arg;<br />

struct data *old_head = atomic_load(ptr_to_head);<br />

struct data *new_head;<br />

bool success;<br />

/* ... Reorganize the data structure ... */<br />

}<br />

success = atomic_compare_exchange_strong(<br />

ptr_to_head, &old_head, new_head<br />

);<br />

if (!success) {<br />

cleanup_data_structure(new_head);<br />

}<br />

return success; /* Exit the thread */<br />

14.12.4 Risk Assessment<br />

Failing to wrap the atomic_compare_exchange_weak() and atomic_compare_exchange_weak_explicit()<br />

functions in a loop can result in incorrect values and control flow.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

CON41-C Low Unlikely Medium P2 L3<br />

14.12.5 Related Guidelines<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java THI03-J. Always invoke wait() and await()<br />

methods inside a loop<br />

14.12.6 Bibliography<br />

[ISO/IEC 9899:2011]<br />

7.17.7.4, “The atomic_compare_exchange<br />

Generic Functions”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 453<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Concurrency (CON) - CON41-C. Wrap functions that can fail spuriously in a loop<br />

[Lea 2000]<br />

1.3.2, “Liveness”<br />

3.2.2, “Monitor Mechanics”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 454<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC30-C. Do not use the rand() function for generating pseudorandom numbers<br />

15 Miscellaneous (MSC)<br />

15.1 MSC30-C. Do not use the rand() function for generating<br />

pseudorandom numbers<br />

Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers<br />

with good statistical properties, but the numbers produced are not genuinely random.<br />

The C <strong>Standard</strong> rand() function makes no guarantees as to the quality of the random sequence<br />

produced. The numbers generated by some implementations of rand() have a comparatively<br />

short cycle and the numbers can be predictable. Applications that have strong pseudorandom<br />

number requirements must use a generator that is known to be sufficient for their needs.<br />

15.1.1 Noncompliant Code Example<br />

The following noncompliant code generates an ID with a numeric part produced by calling the<br />

rand() function. The IDs produced are predictable and have limited randomness.<br />

#include <br />

#include <br />

enum { len = 12 };<br />

void func(void) {<br />

/*<br />

* id will hold the ID, starting with the characters<br />

* "ID" followed by a random integer.<br />

*/<br />

char id[len];<br />

int r;<br />

int num;<br />

/* ... */<br />

r = rand(); /* Generate a random integer */<br />

num = snprintf(id, len, "ID%-d", r); /* Generate the ID */<br />

/* ... */<br />

}<br />

15.1.2 Compliant Solution (POSIX)<br />

This compliant solution replaces the rand() function with the POSIX random() function:<br />

#include <br />

#include <br />

#include <br />

enum { len = 12 };<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 455<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC30-C. Do not use the rand() function for generating pseudorandom numbers<br />

void func(void) {<br />

/*<br />

* id will hold the ID, starting with the characters<br />

* "ID" followed by a random integer.<br />

*/<br />

char id[len];<br />

int r;<br />

int num;<br />

/* ... */<br />

struct timespec ts;<br />

if (timespec_get(&ts, TIME_UTC) == 0) {<br />

/* Handle error */<br />

}<br />

srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */<br />

/* ... */<br />

r = random(); /* Generate a random integer */<br />

num = snprintf(id, len, "ID%-d", r); /* Generate the ID */<br />

/* ... */<br />

}<br />

The POSIX random() function is a better pseudorandom number generator. Although on some<br />

platforms the low dozen bits generated by rand() go through a cyclic pattern, all the bits generated<br />

by random() are usable. The rand48 family of functions provides another alternative for<br />

pseudorandom numbers.<br />

Although not specified by POSIX, arc4random() is another possibility for systems that support<br />

it. The arc4random(3) manual page [OpenBSD] states<br />

... provides higher quality of data than those described in rand(3), random(3), and<br />

drand48(3).<br />

To achieve the best random numbers possible, an implementation-specific function must be used.<br />

When unpredictability is crucial and speed is not an issue, as in the creation of strong cryptographic<br />

keys, use a true entropy source, such as /dev/random, or a hardware device capable of<br />

generating random numbers. The /dev/random device can block for a long time if there are not<br />

enough events going on to generate sufficient entropy.<br />

15.1.3 Compliant Solution (Windows)<br />

On Windows platforms, the CryptGenRandom() function can be used to generate cryptographically<br />

strong random numbers. The exact details of the implementation are unknown, including,<br />

for example, what source of entropy CryptGenRandom() uses. The Microsoft Developer Network<br />

CryptGenRandom() reference [MSDN] states<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 456<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC30-C. Do not use the rand() function for generating pseudorandom numbers<br />

If an application has access to a good random source, it can fill the pbBuffer buffer<br />

with some random data before calling CryptGenRandom(). The CSP [cryptographic service<br />

provider] then uses this data to further randomize its internal seed. It is acceptable<br />

to omit the step of initializing the pbBuffer buffer before calling CryptGenRandom().<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

HCRYPTPROV prov;<br />

if (CryptAcquireContext(&prov, NULL, NULL,<br />

PROV_RSA_FULL, 0)) {<br />

long int li = 0;<br />

if (CryptGenRandom(prov, sizeof(li), (BYTE *)&li)) {<br />

printf("Random number: %ld\n", li);<br />

} else {<br />

/* Handle error */<br />

}<br />

if (!CryptReleaseContext(prov, 0)) {<br />

/* Handle error */<br />

}<br />

} else {<br />

/* Handle error */<br />

}<br />

}<br />

15.1.4 Risk Assessment<br />

The use of the rand() function can result in predictable random numbers.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC30-C Medium Unlikely Low P6 L2<br />

15.1.5 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

MSC50-CPP. Do not use std::rand() for generating<br />

pseudorandom numbers<br />

<strong>CERT</strong> Oracle Secure <strong>Coding</strong> <strong>Standard</strong> for Java MSC02-J. Generate strong random numbers<br />

MITRE CWE<br />

CWE-327, Use of a Broken or Risky Cryptographic<br />

Algorithm<br />

CWE-330, Use of Insufficiently Random Values<br />

CWE-331, Insufficient Entropy<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 457<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC30-C. Do not use the rand() function for generating pseudorandom numbers<br />

CWE-338, Use of Cryptographically Weak<br />

Pseudo-Random Number Generator (PRNG)<br />

15.1.6 Bibliography<br />

[MSDN]<br />

[OpenBSD]<br />

“CryptGenRandom Function“<br />

arc4random()<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 458<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC32-C. Properly seed pseudorandom number generators<br />

15.2 MSC32-C. Properly seed pseudorandom number generators<br />

A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences<br />

of numbers that approximate the properties of random numbers. Each sequence is completely<br />

determined by the initial state of the PRNG and the algorithm for changing the state. Most<br />

PRNGs make it possible to set the initial state, also called the seed state. Setting the initial state is<br />

called seeding the PRNG.<br />

Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with<br />

the same value, results in generating the same sequence of random numbers in different runs of<br />

the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively<br />

called to produce a sequence of random numbers, S. If the PRNG is subsequently seeded<br />

with the same initial seed value, then it will generate the same sequence S.<br />

As a result, after the first run of an improperly seeded PRNG, an attacker can predict the sequence<br />

of random numbers that will be generated in the future runs. Improperly seeding or failing to seed<br />

the PRNG can lead to vulnerabilities, especially in security protocols.<br />

The solution is to ensure that the PRNG is always properly seeded. A properly seeded PRNG will<br />

generate a different sequence of random numbers each time it is run.<br />

Not all random number generators can be seeded. True random number generators that rely on<br />

hardware to produce completely unpredictable results do not need to be and cannot be seeded.<br />

Some high-quality PRNGs, such as the /dev/random device on some UNIX systems, also cannot<br />

be seeded. This rule applies only to algorithmic pseudorandom number generators that can be<br />

seeded.<br />

15.2.1 Noncompliant Code Example (POSIX)<br />

This noncompliant code example generates a sequence of 10 pseudorandom numbers using the<br />

random() function. When random() is not seeded, it behaves like rand(), producing the same<br />

sequence of random numbers each time any program that uses it is run.<br />

#include <br />

#include <br />

void func(void) {<br />

for (unsigned int i = 0; i < 10; ++i) {<br />

/* Always generates the same sequence */<br />

printf("%ld, ", random());<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 459<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC32-C. Properly seed pseudorandom number generators<br />

The output is as follows:<br />

1st run: 1804289383, 846930886, 1681692777, 1714636915,<br />

1957747793, 424238335, 719885386, 1649760492,<br />

596516649, 1189641421,<br />

2nd run: 1804289383, 846930886, 1681692777, 1714636915,<br />

1957747793, 424238335, 719885386, 1649760492,<br />

596516649, 1189641421,<br />

...<br />

nth run: 1804289383, 846930886, 1681692777, 1714636915,<br />

1957747793, 424238335, 719885386, 1649760492,<br />

596516649, 1189641421,<br />

15.2.2 Compliant Solution (POSIX)<br />

Call srandom() before invoking random() to seed the random sequence generated by random().<br />

This compliant solution produces different random number sequences each time the function<br />

is called, depending on the resolution of the system clock:<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

struct timespec ts;<br />

if (timespec_get(&ts, TIME_UTC) == 0) {<br />

/* Handle error */<br />

} else {<br />

srandom(ts.tv_nsec ^ ts.tv_sec);<br />

for (unsigned int i = 0; i < 10; ++i) {<br />

/* Generates different sequences at different runs */<br />

printf("%ld, ", random());<br />

}<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 460<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC32-C. Properly seed pseudorandom number generators<br />

The output is as follows:<br />

1st run: 198682410, 2076262355, 910374899, 428635843,<br />

2084827500, 1558698420, 4459146, 733695321,<br />

2044378618, 1649046624,<br />

2nd run: 1127071427, 252907983, 1358798372, 2101446505,<br />

1514711759, 229790273, 954268511, 1116446419,<br />

368192457,<br />

1297948050,<br />

3rd run: 2052868434, 1645663878, 731874735, 1624006793,<br />

938447420, 1046134947, 1901136083, 418123888,<br />

836428296,<br />

2017467418,<br />

This output may not be sufficiently random for concurrent execution, which may lead to correlated<br />

generated series in different threads. Depending on the application and the desired level of<br />

security, a programmer may choose alternative ways to seed PRNGs. In general, hardware is more<br />

capable than software of generating real random numbers (for example, by sampling the thermal<br />

noise of a diode).<br />

15.2.3 Compliant Solution (Windows)<br />

The CryptGenRandom() function does not run the risk of not being properly seeded because its<br />

arguments serve as seeders:<br />

#include <br />

#include <br />

#include <br />

void func(void) {<br />

HCRYPTPROV hCryptProv;<br />

long rand_buf;<br />

/* Example of instantiating the CSP */<br />

if (CryptAcquireContext(&hCryptProv, NULL, NULL,<br />

PROV_RSA_FULL, 0)) {<br />

printf("CryptAcquireContext succeeded.\n");<br />

} else {<br />

printf("Error during CryptAcquireContext!\n");<br />

}<br />

for (unsigned int i = 0; i < 10; ++i) {<br />

if (!CryptGenRandom(hCryptProv, sizeof(rand_buf),<br />

(BYTE *)&rand_buf)) {<br />

printf("Error\n");<br />

} else {<br />

printf("%ld, ", rand_buf);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 461<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC32-C. Properly seed pseudorandom number generators<br />

}<br />

}<br />

The output is as follows:<br />

1st run: -1597837311, 906130682, -1308031886, 1048837407, -<br />

931041900, -658114613, -1709220953, -1019697289,<br />

1802206541,406505841,<br />

2nd run: 885904119, -687379556, -1782296854, 1443701916, -<br />

624291047, 2049692692, -990451563, -142307804,<br />

1257079211,897185104,<br />

3rd run: 190598304, -1537409464, 1594174739, -424401916, -<br />

1975153474, 826912927, 1705549595, -1515331215,<br />

474951399, 1982500583,<br />

15.2.4 Risk Assessment<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC32-C Medium Likely Low P18 L1<br />

15.2.5 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

<strong>SEI</strong> <strong>CERT</strong> C++ <strong>Coding</strong> <strong>Standard</strong><br />

MITRE CWE<br />

MSC30-C. Do not use the rand() function for<br />

generating pseudorandom numbers<br />

MSC51-CPP. Ensure your random number<br />

generator is properly seeded<br />

CWE-327, Use of a Broken or Risky Cryptographic<br />

Algorithm<br />

CWE-330, Use of Insufficiently Random Values<br />

CWE-331, Insufficient Entropy<br />

CWE-338, Use of Cryptographically Weak<br />

Pseudo-Random Number Generator (PRNG)<br />

15.2.6 Bibliography<br />

[MSDN]<br />

“CryptGenRandom Function“<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 462<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC33-C. Do not pass invalid data to the asctime() function<br />

15.3 MSC33-C. Do not pass invalid data to the asctime() function<br />

The C <strong>Standard</strong>, 7.27.3.1 [ISO/IEC 9899:2011], provides the following sample implementation of<br />

the asctime() function:<br />

char *asctime(const struct tm *timeptr) {<br />

static const char wday_name[7][3] = {<br />

"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"<br />

};<br />

static const char mon_name[12][3] = {<br />

"Jan", "Feb", "Mar", "Apr", "May", "Jun",<br />

"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"<br />

};<br />

static char result[26];<br />

sprintf(<br />

result,<br />

"%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",<br />

wday_name[timeptr->tm_wday],<br />

mon_name[timeptr->tm_mon],<br />

timeptr->tm_mday, timeptr->tm_hour,<br />

timeptr->tm_min, timeptr->tm_sec,<br />

1900 + timeptr->tm_year<br />

);<br />

return result;<br />

}<br />

This function is supposed to output a character string of 26 characters at most, including the terminating<br />

null character. If we count the length indicated by the format directives, we arrive at 25.<br />

Taking into account the terminating null character, the array size of the string appears sufficient.<br />

However, this implementation assumes that the values of the struct tm data are within normal<br />

ranges and does nothing to enforce the range limit. If any of the values print more characters than<br />

expected, the sprintf() function may overflow the result array. For example, if tm_year has<br />

the value 12345, then 27 characters (including the terminating null character) are printed, resulting<br />

in a buffer overflow.<br />

The POSIX® Base Specifications [IEEE Std 1003.1:2013] says the following about the<br />

asctime() and asctime_r() functions:<br />

These functions are included only for compatibility with older implementations. They<br />

have undefined behavior if the resulting string would be too long, so the use of these<br />

functions should be discouraged. On implementations that do not detect output string<br />

length overflow, it is possible to overflow the output buffers in such a way as to cause<br />

applications to fail, or possible system security violations. Also, these functions do not<br />

support localized date and time formats. To avoid these problems, applications should<br />

use strftime() to generate strings from broken-down times.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 463<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC33-C. Do not pass invalid data to the asctime() function<br />

The C <strong>Standard</strong>, Annex K, also defines asctime_s(), which can be used as a secure substitute<br />

for asctime().<br />

The asctime() function appears in the list of obsolescent functions in MSC24-C. Do not use<br />

deprecated or obsolescent functions.<br />

15.3.1 Noncompliant Code Example<br />

This noncompliant code example invokes the asctime() function with potentially unsanitized<br />

data:<br />

#include <br />

void func(struct tm *time_tm) {<br />

char *time = asctime(time_tm);<br />

/* ... */<br />

}<br />

15.3.2 Compliant Solution (strftime())<br />

The strftime() function allows the programmer to specify a more rigorous format and also to<br />

specify the maximum size of the resulting time string:<br />

#include <br />

enum { maxsize = 26 };<br />

void func(struct tm *time) {<br />

char s[maxsize];<br />

/* Current time representation for locale */<br />

const char *format = "%c";<br />

}<br />

size_t size = strftime(s, maxsize, format, time);<br />

This call has the same effects as asctime() but also ensures that no more than maxsize characters<br />

are printed, preventing buffer overflow.<br />

15.3.3 Compliant Solution (asctime_s())<br />

The C <strong>Standard</strong>, Annex K, defines the asctime_s() function, which serves as a close replacement<br />

for the asctime() function but requires an additional argument that specifies the maximum<br />

size of the resulting time string:<br />

#define __STDC_WANT_LIB_EXT1__ 1<br />

#include <br />

enum { maxsize = 26 };<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 464<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC33-C. Do not pass invalid data to the asctime() function<br />

void func(struct tm *time_tm) {<br />

char buffer[maxsize];<br />

}<br />

if (asctime_s(buffer, maxsize, &time_tm)) {<br />

/* Handle error */<br />

}<br />

15.3.4 Risk Assessment<br />

On implementations that do not detect output-string-length overflow, it is possible to overflow the<br />

output buffers.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC33-C High Likely Low P27 L1<br />

15.3.5 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

MSC24-C. Do not use deprecated or obsolescent<br />

functions<br />

15.3.6 Bibliography<br />

[IEEE Std 1003.1:2013]<br />

[ISO/IEC 9899:2011]<br />

XSH, System Interfaces, asctime<br />

7.27.3.1, “The asctime Function”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 465<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC37-C. Ensure that control never reaches the end of a non-void function<br />

15.4 MSC37-C. Ensure that control never reaches the end of a non-void<br />

function<br />

If control reaches the closing curly brace (}) of a non-void function without evaluating a return<br />

statement, using the return value of the function call is undefined behavior. (See undefined behavior<br />

88.)<br />

15.4.1 Noncompliant Code Example<br />

In this noncompliant code example, control reaches the end of the checkpass() function when<br />

the two strings passed to strcmp() are not equal, resulting in undefined behavior. Many compilers<br />

will generate code for the checkpass() function, returning various values along the execution<br />

path where no return statement is defined.<br />

#include <br />

#include <br />

int checkpass(const char *password) {<br />

if (strcmp(password, "pass") == 0) {<br />

return 1;<br />

}<br />

}<br />

void func(const char *userinput) {<br />

if (checkpass(userinput)) {<br />

printf("Success\n");<br />

}<br />

}<br />

This error is frequently diagnosed by compilers. (See MSC00-C. Compile cleanly at high warning<br />

levels.)<br />

15.4.2 Compliant Solution<br />

This compliant solution ensures that the checkpass() function always returns a value:<br />

#include <br />

#include <br />

int checkpass(const char *password) {<br />

if (strcmp(password, "pass") == 0) {<br />

return 1;<br />

}<br />

return 0;<br />

}<br />

void func(const char *userinput) {<br />

if (checkpass(userinput)) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 466<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC37-C. Ensure that control never reaches the end of a non-void function<br />

}<br />

}<br />

printf("Success!\n");<br />

15.4.3 Noncompliant Code Example<br />

In this noncompliant code example, control reaches the end of the getlen() function when input<br />

does not contain the integer delim. Because the potentially undefined return value of<br />

getlen() is later used as an index into an array, a buffer overflow may occur.<br />

#include <br />

size_t getlen(const int *input, size_t maxlen, int delim) {<br />

for (size_t i = 0; i < maxlen; ++i) {<br />

if (input[i] == delim) {<br />

return i;<br />

}<br />

}<br />

}<br />

void func(int userdata) {<br />

size_t i;<br />

int data[] = { 1, 1, 1 };<br />

i = getlen(data, sizeof(data), 0);<br />

data[i] = userdata;<br />

}<br />

15.4.3.1 Implementation Details (GCC)<br />

Violating this rule can have unexpected consequences, as in the following example:<br />

#include <br />

size_t getlen(const int *input, size_t maxlen, int delim) {<br />

for (size_t i = 0; i < maxlen; ++i) {<br />

if (input[i] == delim) {<br />

return i;<br />

}<br />

}<br />

}<br />

int main(int argc, char **argv) {<br />

size_t i;<br />

int data[] = { 1, 1, 1 };<br />

i = getlen(data, sizeof(data), 0);<br />

printf("Returned: %zu\n", i);<br />

data[i] = 0;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 467<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC37-C. Ensure that control never reaches the end of a non-void function<br />

}<br />

return 0;<br />

When this program is compiled with -Wall on most versions of the GCC compiler, the following<br />

warning is generated:<br />

example.c: In function 'getlen':<br />

example.c:12: warning: control reaches end of non-void function<br />

None of the inputs to the function equal the delimiter, so when run with GCC 5.3 on Linux, control<br />

reaches the end of the getlen() function, which is undefined behavior and in this test returns<br />

3, causing an out-of-bounds write to the data array.<br />

15.4.4 Compliant Solution<br />

This compliant solution changes the interface of getlen() to store the result in a user-provided<br />

pointer and return an error code to indicate any error conditions. The best method for handling<br />

this type of error is specific to the application and the type of error. (See ERR00-C. Adopt and implement<br />

a consistent and comprehensive error-handling policy for more on error handling.)<br />

#include <br />

int getlen(const int *input, size_t maxlen, int delim,<br />

size_t *result) {<br />

for (size_t i = 0; i < maxlen; ++i) {<br />

if (input[i] == delim) {<br />

if (result != NULL) {<br />

*result = i;<br />

}<br />

return 0;<br />

}<br />

}<br />

return -1;<br />

}<br />

void func(int userdata) {<br />

size_t i;<br />

int data[] = {1, 1, 1};<br />

if (getlen(data, sizeof(data), 0, &i) != 0) {<br />

/* Handle error */<br />

} else {<br />

data[i] = userdata;<br />

}<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 468<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC37-C. Ensure that control never reaches the end of a non-void function<br />

15.4.5 Exceptions<br />

MSC37-C-EX1: According to the C <strong>Standard</strong>, 5.1.2.2.3, paragraph 1 [ISO/IEC 9899:2011],<br />

“Reaching the } that terminates the main function returns a value of 0.” As a result, it is permissible<br />

for control to reach the end of the main() function without executing a return statement.<br />

15.4.6 Risk Assessment<br />

Using the return value from a non-void function where control reaches the end of the function<br />

without evaluating a return statement can lead to buffer overflow vulnerabilities as well as other<br />

unexpected program behaviors.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC37-C High Unlikely Low P9 L2<br />

15.4.7 Related Guidelines<br />

<strong>CERT</strong> C Secure <strong>Coding</strong> <strong>Standard</strong><br />

MSC01-C. Strive for logical completeness<br />

15.4.8 Bibliography<br />

[ISO/IEC 9899:2011]<br />

5.1.2.2.3, “Program Termination”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 469<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC38-C. Do not treat a predefined identifier as an object if it might only be implemented as a macro<br />

15.5 MSC38-C. Do not treat a predefined identifier as an object if it<br />

might only be implemented as a macro<br />

The C <strong>Standard</strong>, 7.1.4 paragraph 1, [ISO/IEC 9899:2011] states<br />

Any function declared in a header may be additionally implemented as a function-like<br />

macro defined in the header, so if a library function is declared explicitly when its header<br />

is included, one of the techniques shown below can be used to ensure the declaration is<br />

not affected by such a macro. Any macro definition of a function can be suppressed locally<br />

by enclosing the name of the function in parentheses, because the name is then<br />

not followed by the left parenthesis that indicates expansion of a macro function name.<br />

For the same syntactic reason, it is permitted to take the address of a library function<br />

even if it is also defined as a macro. 185<br />

185<br />

This means that an implementation shall provide an actual function for each library<br />

function, even if it also provides a macro for that function.<br />

However, the C <strong>Standard</strong> enumerates specific exceptions in which the behavior of accessing an<br />

object or function expanded to be a standard library macro definition is undefined. The macros are<br />

assert, errno, math_errhandling, setjmp, va_arg, va_copy, va_end, and va_start.<br />

These cases are described by undefined behaviors110, 114, 122, 124, and 138. Programmers must<br />

not suppress these macros to access the underlying object or function.<br />

15.5.1 Noncompliant Code Example (assert)<br />

In this noncompliant code example, the standard assert() macro is suppressed in an attempt to<br />

pass it as a function pointer to the execute_handler() function. Attempting to suppress the<br />

assert() macro is undefined behavior.<br />

#include <br />

typedef void (*handler_type)(int);<br />

void execute_handler(handler_type handler, int value) {<br />

handler(value);<br />

}<br />

void func(int e) {<br />

execute_handler(&(assert), e < 0);<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 470<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC38-C. Do not treat a predefined identifier as an object if it might only be implemented as a macro<br />

15.5.2 Compliant Solution (assert)<br />

In this compliant solution, the assert() macro is wrapped in a helper function, removing the undefined<br />

behavior:<br />

#include <br />

typedef void (*handler_type)(int);<br />

void execute_handler(handler_type handler, int value) {<br />

handler(value);<br />

}<br />

static void assert_handler(int value) {<br />

assert(value);<br />

}<br />

void func(int e) {<br />

execute_handler(&assert_handler, e < 0);<br />

}<br />

15.5.3 Noncompliant Code Example (Redefining errno)<br />

Legacy code is apt to include an incorrect declaration, such as the following in this noncompliant<br />

code example:<br />

extern int errno;<br />

15.5.4 Compliant Solution (Declaring errno)<br />

This compliant solution demonstrates the correct way to declare errno by including the header<br />

:<br />

#include <br />

C-conforming implementations are required to declare errno in , although some historic<br />

implementations failed to do so.<br />

15.5.5 Risk Assessment<br />

Accessing objects or functions underlying the specific macros enumerated in this rule is undefined<br />

behavior.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC38-C Low Unlikely Medium P2 L3<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 471<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC38-C. Do not treat a predefined identifier as an object if it might only be implemented as a macro<br />

15.5.6 Related Guidelines<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong><br />

DCL37-C. Do not declare or define a reserved<br />

identifier<br />

15.5.7 Bibliography<br />

ISO/IEC 9899:2011<br />

7.1.4, “Use of Library Functions”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 472<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC39-C. Do not call va_arg() on a va_list that has an indeterminate value<br />

15.6 MSC39-C. Do not call va_arg() on a va_list that has an<br />

indeterminate value<br />

Variadic functions access their variable arguments by using va_start() to initialize an object of<br />

type va_list, iteratively invoking the va_arg() macro, and finally calling va_end(). The<br />

va_list may be passed as an argument to another function, but calling va_arg() within that<br />

function causes the va_list to have an indeterminate value in the calling function. As a result,<br />

attempting to read variable arguments without reinitializing the va_list can have unexpected<br />

behavior. According to the C <strong>Standard</strong>, 7.16, paragraph 3 [ISO/IEC 9899:2011],<br />

If access to the varying arguments is desired, the called function shall declare an object<br />

(generally referred to as ap in this subclause) having type va_list. The object ap may<br />

be passed as an argument to another function; if that function invokes the va_arg<br />

macro with parameter ap, the value of ap in the calling function is indeterminate and<br />

shall be passed to the va_end macro prior to any further reference to ap. 253<br />

253<br />

It is permitted to create a pointer to a va_list and pass that pointer to another function,<br />

in which case the original function may take further use of the original list after<br />

the other function returns.<br />

15.6.1 Noncompliant Code Example<br />

This noncompliant code example attempts to check that none of its variable arguments are zero by<br />

passing a va_list to helper function contains_zero(). After the call to contains_zero(),<br />

the value of ap is indeterminate.<br />

#include <br />

#include <br />

int contains_zero(size_t count, va_list ap) {<br />

for (size_t i = 1; i < count; ++i) {<br />

if (va_arg(ap, double) == 0.0) {<br />

return 1;<br />

}<br />

}<br />

return 0;<br />

}<br />

int print_reciprocals(size_t count, ...) {<br />

va_list ap;<br />

va_start(ap, count);<br />

if (contains_zero(count, ap)) {<br />

va_end(ap);<br />

return 1;<br />

}<br />

for (size_t i = 0; i < count; ++i) {<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 473<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC39-C. Do not call va_arg() on a va_list that has an indeterminate value<br />

}<br />

printf("%f ", 1.0 / va_arg(ap, double));<br />

}<br />

va_end(ap);<br />

return 0;<br />

15.6.2 Compliant Solution<br />

The compliant solution modifies contains_zero() to take a pointer to a va_list. It then uses<br />

the va_copy macro to make a copy of the list, traverses the copy, and cleans it up. Consequently,<br />

the print_reciprocals() function is free to traverse the original va_list.<br />

#include <br />

#include <br />

int contains_zero(size_t count, va_list *ap) {<br />

va_list ap1;<br />

va_copy(ap1, *ap);<br />

for (size_t i = 1; i < count; ++i) {<br />

if (va_arg(ap1, double) == 0.0) {<br />

return 1;<br />

}<br />

}<br />

va_end(ap1);<br />

return 0;<br />

}<br />

int print_reciprocals(size_t count, ...) {<br />

int status;<br />

va_list ap;<br />

va_start(ap, count);<br />

}<br />

if (contains_zero(count, &ap)) {<br />

printf("0 in arguments!\n");<br />

status = 1;<br />

} else {<br />

for (size_t i = 0; i < count; i++) {<br />

printf("%f ", 1.0 / va_arg(ap, double));<br />

}<br />

printf("\n");<br />

status = 0;<br />

}<br />

va_end(ap);<br />

return status;<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 474<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC39-C. Do not call va_arg() on a va_list that has an indeterminate value<br />

15.6.3 Risk Assessment<br />

Reading variable arguments using a va_list that has an indeterminate value can have unexpected<br />

results.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC39-C Low Unlikely Low P3 L3<br />

15.6.4 Bibliography<br />

[ISO/IEC 9899:2011]<br />

Subclause 7.16, “Variable Arguments<br />

”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 475<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC40-C. Do not violate constraints<br />

15.7 MSC40-C. Do not violate constraints<br />

According to the C <strong>Standard</strong>, 3.8 [ISO/IEC 9899:2011], a constraint is a “restriction, either syntactic<br />

or semantic, by which the exposition of language elements is to be interpreted.” Despite the<br />

similarity of the terms, a runtime constraint is not a kind of constraint.<br />

Violating any shall statement within a constraint clause in the C <strong>Standard</strong> requires an implementation<br />

to issue a diagnostic message, the C <strong>Standard</strong>, 5.1.1.3 [ISO/IEC 9899:2011] states<br />

A conforming implementation shall produce at least one diagnostic message (identified<br />

in an implementation-defined manner) if a preprocessing translation unit or translation<br />

unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly<br />

specified as undefined or implementation-defined. Diagnostic messages need not<br />

be produced in other circumstances.<br />

The C <strong>Standard</strong> further explains in a footnote<br />

The intent is that an implementation should identify the nature of, and where possible localize,<br />

each violation. Of course, an implementation is free to produce any number of diagnostics<br />

as long as a valid program is still correctly translated. It may also successfully<br />

translate an invalid program.<br />

Any constraint violation is a violation of this rule because it can result in an invalid program.<br />

15.7.1 Noncompliant Code Example (Inline, Internal Linkage)<br />

The C <strong>Standard</strong>, 6.7.4, paragraph 3 [ISO/IEC 9899:2011], states<br />

An inline definition of a function with external linkage shall not contain a definition of a<br />

modifiable object with static or thread storage duration, and shall not contain a reference<br />

to an identifier with internal linkage.<br />

The motivation behind this constraint lies in the semantics of inline definitions. Paragraph 7 of<br />

subclause 6.7.4 reads, in part:<br />

An inline definition provides an alternative to an external definition, which a translator<br />

may use to implement any call to the function in the same translation unit. It is unspecified<br />

whether a call to the function uses the inline definition or the external definition.<br />

That is, if a function has an external and inline definition, implementations are free to choose<br />

which definition to invoke (two distinct invocations of the function may call different definitions,<br />

one the external definition, the other the inline definition). Therefore, issues can arise when these<br />

definitions reference internally linked objects or mutable objects with static or thread storage duration.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 476<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC40-C. Do not violate constraints<br />

This noncompliant code example refers to a static variable with file scope and internal linkage<br />

from within an external inline function:<br />

static int I = 12;<br />

extern inline void func(int a) {<br />

int b = a * I;<br />

/* ... */<br />

}<br />

15.7.2 Compliant Solution (Inline, Internal Linkage)<br />

This compliant solution omits the static qualifier; consequently, the variable I has external<br />

linkage by default:<br />

int I = 12;<br />

extern inline void func(int a) {<br />

int b = a * I;<br />

/* ... */<br />

}<br />

15.7.3 Noncompliant Code Example (inline, Modifiable Static)<br />

This noncompliant code example defines a modifiable static variable within an extern inline<br />

function.<br />

extern inline void func(void) {<br />

static int I = 12;<br />

/* Perform calculations which may modify I */<br />

}<br />

15.7.4 Compliant Solution (Inline, Modifiable Static)<br />

This compliant solution removes the static keyword from the local variable definition. If the<br />

modifications to I must be retained between invocations of func(), it must be declared at file<br />

scope so that it will be defined with external linkage.<br />

extern inline void func(void) {<br />

int I = 12;<br />

/* Perform calculations which may modify I */<br />

}<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 477<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Miscellaneous (MSC) - MSC40-C. Do not violate constraints<br />

15.7.5 Noncompliant Code Example (Inline, Modifiable static)<br />

This noncompliant code example includes two translation units: file1.c and file2.c. The first<br />

file, file1.c, defines a pseudorandom number generation function:<br />

/* file1.c */<br />

/* Externally linked definition of the function get_random() */<br />

extern unsigned int get_random(void) {<br />

/* Initialize the seeds */<br />

static unsigned int m_z = 0xdeadbeef;<br />

static unsigned int m_w = 0xbaddecaf;<br />

}<br />

/* Compute the next pseudorandom value and update the seeds */<br />

m_z = 36969 * (m_z & 65535) + (m_z >> 16);<br />

m_w = 18000 * (m_w & 65535) + (m_w >> 16);<br />

return (m_z > 16);<br />

m_w = 18000 * (m_w & 65535) + (m_w >> 16);<br />

return (m_z


Miscellaneous (MSC) - MSC40-C. Do not violate constraints<br />

the<br />

}<br />

/*<br />

* Get a pseudorandom number. Implementation defined whether<br />

* inline definition in this file or the external definition<br />

* in file2.c is called.<br />

*/<br />

rand_no = get_random();<br />

/* Use rand_no... */<br />

/* ... */<br />

}<br />

/*<br />

* Get another pseudorandom number. Behavior is<br />

* implementation defined.<br />

*/<br />

rand_no = get_random();<br />

/* Use rand_no... */<br />

return 0;<br />

15.7.6 Compliant Solution (Inline, Modifiable static)<br />

This compliant solution adds the static modifier to the inline function definition in file2.c,<br />

giving it internal linkage. All references to get_random() in file.2.c will now reference the<br />

internally linked definition. The first file, which was not changed, is not shown here.<br />

/* file2.c */<br />

/* Static inline definition of get_random function */<br />

static inline unsigned int get_random(void) {<br />

/*<br />

* Initialize the seeds.<br />

* No more constraint violation; the inline function is now<br />

* internally linked.<br />

*/<br />

static unsigned int m_z = 0xdeadbeef;<br />

static unsigned int m_w = 0xbaddecaf;<br />

}<br />

/* Compute the next pseudorandom value and update the seeds */<br />

m_z = 36969 * (m_z & 65535) + (m_z >> 16);<br />

m_w = 18000 * (m_w & 65535) + (m_w >> 16);<br />

return (m_z


Miscellaneous (MSC) - MSC40-C. Do not violate constraints<br />

15.7.7 Risk Assessment<br />

Constraint violations are a broad category of error that can result in unexpected control flow and<br />

corrupted data.<br />

Rule Severity Likelihood Remediation Cost Priority Level<br />

MSC40-C Low Unlikely Medium P2 L3<br />

15.7.8 Bibliography<br />

[ISO/IEC 9899:2011]<br />

4, “Conformance”<br />

5.1.1.3, “Diagnostics”<br />

6.7.4, “Function Specifiers”<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 480<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Appendix A: Bibliography<br />

[Acton 2006]<br />

Acton, Mike. “Understanding Strict Aliasing.” CellPerformance, June 1, 2006.<br />

[Apiki 2006]<br />

Apiki, Steve. “Lock-Free Programming on AMD Multi-Core System.” AMD Developer Central,<br />

2006.<br />

[Apple 2006]<br />

Apple, Inc. Secure <strong>Coding</strong> Guide. May 2006.<br />

[Asgher 2000]<br />

Asgher, Sarmad. “Practical Lock-Free Buffers.” Dr. Dobbs Go-Parallel, August 26, 2000.<br />

[Bailey 2014]<br />

Bailey, Don A. Raising Lazarus—The 20 Year Old Bug that Went to Mars. 2014.<br />

[Banahan 2003]<br />

Banahan, Mike. The C Book. 2003.<br />

[Barney 2010]<br />

Barney, Blaise. “Mutex Variables.” POSIX Threads Programming, 2010.<br />

[Becker 2008]<br />

Becker, Pete. Working Draft, <strong>Standard</strong> for Programming Language C++. April 2008.<br />

[Beebe 2005]<br />

Beebe, Nelson H. F. Re: Remainder (%) Operator and GCC. 2005.<br />

[Black 2007]<br />

Black, Paul E., Kass, Michael, & Koo, Michael. Source Code Security Analysis Tool Functional<br />

Specification Version 1.0. Special Publication 500-268. Information Technology Laboratory<br />

(ITL), Software Diagnostics and Conformance Testing Division, May 2007.<br />

[Brainbell.com]<br />

Brainbell.com. Advice and Warnings for C Tutorials.<br />

[Bryant 2003]<br />

Bryant, Randal E. & O’Halloran, David. Computer Systems: A Programmer’s Perspective. Upper<br />

Saddle River, NJ: Prentice Hall, 2003 (ISBN 0-13-034074-X).<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 481<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Burch 2006]<br />

Burch, Hal; Long, Fred; & Seacord, Robert C. Specifications for Managed Strings (CMU/<strong>SEI</strong>-<br />

2006-TR-006). Pittsburgh, PA: Software Engineering Institute, Carnegie Mellon University,<br />

2006.<br />

[Butenhof 1997]<br />

Butenhof, David R. Programming with POSIX® Threads. Boston: Addison-Wesley Professional,<br />

1997 (ISBN 0-201-63392-2).<br />

[C99 Rationale 2003]<br />

Rationale for International <strong>Standard</strong>—Programming Languages—C, Revision 5.10 (C99 Rationale),<br />

April 2003.<br />

[Callaghan 1995]<br />

Callaghan, B.; Pawlowski, B.; & Staubach, P. IETF RFC 1813 NFS Version 3 Protocol Specification,<br />

June 1995.<br />

[Cassidy 2014]<br />

Cassidy, Sean. existential type crisis : Diagnosis of the Heartbleed Bug [blog post]. April 2014.<br />

[<strong>CERT</strong> 2006a]<br />

<strong>CERT</strong>/CC. <strong>CERT</strong>/CC Statistics 1988–2006.<br />

[<strong>CERT</strong> 2006b]<br />

<strong>CERT</strong>/CC. US-<strong>CERT</strong>’s Technical Cyber Security Alerts.<br />

[<strong>CERT</strong> 2006c]<br />

<strong>CERT</strong>/CC. Secure <strong>Coding</strong> website.<br />

[Chen 2002]<br />

Chen, H.; Wagner, D.; & Dean, D. Setuid Demystified. USENIX Security Symposium, 2002.<br />

[Chess 2007]<br />

Chess, Brian, & West, Jacob. Secure Programming with Static Analysis. Boston: Addison-Wesley<br />

2007.<br />

[Corfield 1993]<br />

Corfield, Sean A. “Making String Literals 'const'.” November 1993.<br />

[Coverity 2007]<br />

Coverity Prevent User’s Manual (3.3.0). 2007.<br />

[CVE]<br />

Common Vulnerabilities and Exposures Website. http://cve.mitre.org<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 482<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[C++ Reference]<br />

<strong>Standard</strong> C Library, General C+, C+ <strong>Standard</strong> Template Library.<br />

[Dewhurst 2002]<br />

Dewhurst, Stephen C. C++ Gotchas: Avoiding Common Problems in <strong>Coding</strong> and Design. Boston:<br />

Addison-Wesley Professional, 2002.<br />

[Dewhurst 2005]<br />

Dewhurst, Stephen C. C++ Common Knowledge: Essential Intermediate Programming. Boston:<br />

Addison-Wesley Professional, 2005.<br />

[DHS 2006]<br />

U.S. Department of Homeland Security. Build Security In. 2006.<br />

[DISA 2015]<br />

DISA. Application Security and Development Security Technical Implementation Guide, Version<br />

3, Release 10. Accessed April 2016.<br />

[DOD 5220]<br />

U.S. Department of Defense. DoD <strong>Standard</strong> 5220.22-M (Word document).<br />

[Dowd 2006]<br />

Dowd, M.; McDonald, J.; & Schuh, J. The Art of Software Security Assessment: Identifying and<br />

Preventing Software Vulnerabilities. Boston: Addison-Wesley, 2006. (See http://taossa.com for<br />

updates and errata.)<br />

[Drepper 2006]<br />

Drepper, Ulrich. Defensive Programming for Red Hat Enterprise Linux (and What To Do If<br />

Something Goes Wrong). May 3, 2006.<br />

[Duff 1988]<br />

Duff, Tom. Tom Duff on Duff’s Device. August 29, 1988.<br />

[Dutta 2003]<br />

Dutta, Shiv. Best Practices for Programming in C. June 26, 2003.<br />

[Eckel 2007]<br />

Eckel, Bruce. Thinking in C++, Vol. 2. January 25, 2007.<br />

[ECTC 1998]<br />

Embedded C++ Technical Committee. The Embedded C++ Programming Guide Lines, Version<br />

WP-GU-003. January 6, 1998.<br />

[Eide and Regehr]<br />

Eide, E., & Regehr, J. Volatiles Are Miscompiled, and What to Do about It. 2008.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 483<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Feather 1997]<br />

Feather, Clive, D. W. Solving the struct Hack Problem. JTC1/SC22/WG14 N791, (1997).<br />

[Finlay 2003]<br />

Finlay, Ian A. <strong>CERT</strong> Advisory CA-2003-16, Buffer Overflow in Microsoft RPC. <strong>CERT</strong>/CC, July<br />

2003.<br />

[Fisher 1999]<br />

Fisher, David & Lipson, Howard. “Emergent Algorithms—A New Method for Enhancing Survivability<br />

in Unbounded Systems.” Proceedings of the 32nd Annual Hawaii International Conference<br />

on System Sciences (HICSS-32). Maui, HI, January 5–8, 1999.<br />

[Flake 2006]<br />

Flake, Halvar. “Attacks on Uninitialized Local Variables.” Black Hat Federal, 2006.<br />

[Fortify 2006]<br />

Fortify Software Inc. Fortify Taxonomy: Software Security Errors. 2006.<br />

[FSF 2005]<br />

Free Software Foundation. GCC Online Documentation. 2005.<br />

[Garfinkel 1996]<br />

Garfinkel, Simson & Spafford, Gene. Practical UNIX & Internet Security, 2nd ed. Sebastopol,<br />

CA: O’Reilly Media, April 1996 (ISBN 1-56592-148-8).<br />

[GCC Bugs]<br />

C Team. GCC Bugs. Free Software Foundation, Inc. (n.d.).<br />

[GNU 2010]<br />

GNU. <strong>Coding</strong> <strong>Standard</strong>s. GNU, 2010.<br />

[GNU Pth]<br />

Engelschall, Ralf S. GNU Portable Threads, 2006.<br />

[Goldberg 1991]<br />

Goldberg, David. What Every Computer Scientist Should Know about Floating-Point Arithmetic.<br />

Sun Microsystems, March 1991.<br />

[Goodin 2009]<br />

Goodin, Dan. Clever Attack Exploits Fully-Patched Linux Kernel. The Register, July 2009.<br />

[Gough 2005]<br />

Gough, Brian J. An Introduction to GCC. Network Theory Ltd. Revised August 2005 (ISBN 0-<br />

9541617-9-3).<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 484<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Graff 2003]<br />

Graff, Mark G. & Van Wyk, Kenneth R. Secure <strong>Coding</strong>: Principles and Practices. Cambridge,<br />

MA: O’Reilly, 2003 (ISBN 0596002424).<br />

[Greenman 1997]<br />

Greenman, David. Serious Security Bug in wu-ftpd v2.4. BUGTRAQ Mailing List (bugtraq@securityfocus.com),<br />

January 2, 1997.<br />

[Griffiths 2006]<br />

Griffiths, Andrew. Clutching at Straws: When You Can Shift the Stack Pointer. 2006.<br />

[Gutmann 1996]<br />

Gutmann, Peter. Secure Deletion of Data from Magnetic and Solid-State Memory. July 1996.<br />

[Haddad 2005]<br />

Haddad, Ibrahim. “Secure <strong>Coding</strong> in C and C++: An Interview with Robert Seacord, Senior Vulnerability<br />

Analyst at <strong>CERT</strong>.” Linux World Magazine, November 2005.<br />

[Hatton 1995]<br />

Hatton, Les. Safer C: Developing Software for High-Integrity and Safety-Critical Systems. New<br />

York: McGraw-Hill, 1995 (ISBN 0-07-707640-0).<br />

[Hatton 2003]<br />

Hatton, Les. EC-: A Measurement-Based Safer Subset of ISO C Suitable for Embedded System<br />

Development. November 5, 2003.<br />

[Henricson 1992]<br />

Henricson, Mats & Nyquist, Erik. Programming in C++, Rules and Recommendations. Ellemtel<br />

Telecommunication Systems Laboratories, 1992.<br />

[Horton 1990]<br />

Horton, Mark R. Portable C Software. Upper Saddle River, NJ: Prentice-Hall, 1990 (ISBN:0-13-<br />

868050-7).<br />

[Howard 2002]<br />

Howard, Michael & LeBlanc, David C. Writing Secure Code, 2nd ed. Redmond, WA: Microsoft<br />

Press, 2002.<br />

[HP 2003]<br />

Hewlett-Packard Company. Tru64 UNIX: Protecting Your System against File Name Spoofing<br />

Attacks. Houston, TX, January 2003.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 485<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[IEC 60812 2006]<br />

IEC (International Electrotechnical Commission). Analysis Techniques for System Reliability—<br />

Procedure for Failure Mode and Effects Analysis (FMEA), 2nd ed. (IEC 60812). Geneva, Switzerland:<br />

IEC, 2006.<br />

[IEC 61508-4]<br />

IEC (International Electrotechnical Commission). Functional Safety of Electrical/Electronic/Programmable<br />

Electronic Safety-Related Systems—Part 4: Definitions and Abbreviations. Geneva,<br />

Switzerland: IEC, 1998.<br />

[IEEE 754 2006]<br />

IEEE (Institute of Electrical and Electronics Engineers). <strong>Standard</strong> for Binary Floating-Point<br />

Arithmetic (IEEE 754-1985). New York: IEEE, 2006.<br />

[IEEE Std 610.12 1990]<br />

IEEE. IEEE <strong>Standard</strong> Glossary of Software Engineering Terminology. (1990).<br />

[IEEE Std 1003.1:2004]<br />

IEEE and The Open Group. The Open Group Base Specifications Issue 6 (IEEE Std 1003.1),<br />

2004 Edition. (See also ISO/IEC 9945-2004 and Open Group 04.)<br />

[IEEE Std 1003.1:2008]<br />

IEEE and The Open Group. The Open Group Base Specifications Issue 7 (IEEE Std 1003.1),<br />

2008 Edition. (See also ISO/IEC 9945-2008 and Open Group 2008.)<br />

[IEEE Std 1003.1:2013]<br />

IEEE and The Open Group. <strong>Standard</strong> for Information Technology—Portable Operating System<br />

Interface (POSIX), Base Specifications, Issue 7 (IEEE Std 1003.1, 2013 Edition).<br />

[IETF: RFC 6520]<br />

Internet Engineering Task Force (IETF). Request for Comments 6520: Transport Layer Security<br />

(TLS) and Datagram Transport Layer Security (DTLS) Heartbeat Extension. February 2012.<br />

[Intel 2001]<br />

Intel Corp. Floating-Point IEEE Filter for Microsoft Windows 2000 on the Intel Itanium Architecture.<br />

March 2001.<br />

[Internet Society 2000]<br />

The Internet Society. Internet Security Glossary (RFC 2828). 2000.<br />

[ISO/IEC 646:1991]<br />

ISO/IEC (International Organization for <strong>Standard</strong>ization/International Electrotechnical Commission).<br />

Information Technology: ISO 7-Bit Coded Character Set for Information Interchange<br />

(ISO/IEC 646-1991). Geneva, Switzerland: ISO, 1991.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 486<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[ISO/IEC 9899:1990]<br />

ISO/IEC. Programming Languages—C (ISO/IEC 9899:1990). Geneva, Switzerland: ISO, 1990.<br />

[ISO/IEC 9899:1999]<br />

ISO/IEC. Programming Languages—C, 2nd ed (ISO/IEC 9899:1999). Geneva, Switzerland: ISO,<br />

1999.<br />

[ISO/IEC 9899:2011]<br />

ISO/IEC. Programming Languages—C, 3rd ed (ISO/IEC 9899:2011). Geneva, Switzerland: ISO,<br />

2011.<br />

[ISO/IEC 9945:2003]<br />

ISO/IEC. Information Technology—Programming Languages, Their Environments and System<br />

Software Interfaces—Portable Operating System Interface (POSIX®) [including Technical Corrigendum<br />

1] (ISO/IEC 9945:2003). Geneva, Switzerland: ISO, 2003.<br />

[ISO/IEC 10646:2003]<br />

ISO/IEC. Information Technology—Universal Multiple-Octet Coded Character Set (UCS)<br />

(ISO/IEC 10646:2003). Geneva, Switzerland: International Organization for <strong>Standard</strong>ization,<br />

2003.<br />

[ISO/IEC 10646:2012]<br />

ISO/IEC. Information technology—Universal Multiple-Octet Coded Character Set (UCS)<br />

(ISO/IEC 10646:2012). Geneva, Switzerland: ISO, 2012.<br />

[ISO/IEC 11889-1:2009]<br />

ISO/IEC. Information Technology—Trusted Platform Module—Part 1: Overview (ISO/IEC<br />

11889-1:2009). Geneva, Switzerland: ISO, 2009.<br />

[ISO/IEC 14882:2003]<br />

ISO/IEC. Programming Languages—C++, Second Edition (ISO/IEC 14882-2003). Geneva,<br />

Switzerland: ISO, 2003.<br />

[ISO/IEC 14882:2011]<br />

ISO/IEC. Information Technology—Programming Languages—C++, Third Edition (ISO/IEC<br />

14882-2011). Geneva, Switzerland: ISO, 2011.<br />

[ISO/IEC 23360-1:2006]<br />

ISO/IEC. Linux <strong>Standard</strong> Base (LSB) Core Specification 3.1—Part 1: Generic Specification. Geneva,<br />

Switzerland: ISO, 2006.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 487<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[ISO/IEC/IEEE 9945:2008]<br />

ISO/IEC/IEEE. Information Technology—Programming Languages, Their Environments and System<br />

Software Interfaces—Portable Operating System Interface (POSIX®) (ISO/IEC/IEEE<br />

9945:2008). Geneva, Switzerland: ISO, 2008.<br />

[ISO/IEC/IEEE 24765:2010]<br />

ISO/IEC/IEEE. Systems and Software Engineering—Vocabulary (ISO/IEC/IEEE 24765:2010).<br />

Geneva, Switzerland: ISO, 2010.<br />

[ISO/IEC DTR 24732]<br />

ISO/IEC JTC1. Extension for the Programming Language C to Support Decimal Floating-Point<br />

Arithmetic (ISO/IEC JTC1 SC22 WG14 N1290). Geneva, Switzerland: ISO, March 2008.<br />

[ISO/IEC JTC1/SC22/WG11]<br />

ISO/IEC. Binding Techniques (ISO/IEC JTC1/SC22/WG11). Geneva, Switzerland: ISO, 2007.<br />

[ISO/IEC JTC1/SC22/WG14]<br />

ISO/IEC. Solving the Struct Hack Problem (ISO/IEC JTC1/SC22/WG14 N791). Geneva, Switzerland:<br />

ISO, 1997.<br />

[ISO/IEC TR 24731-1:2007]<br />

ISO/IEC. Extensions to the C Library—Part I: Bounds-Checking Interfaces (ISO/IEC TR 24731).<br />

Geneva, Switzerland: ISO, April 2006.<br />

[ISO/IEC PDTR 24731-2]<br />

ISO/IEC. Extensions to the C Library—Part II: Dynamic Allocation Functions (ISO/IEC PDTR<br />

24731-2). Geneva, Switzerland: ISO, August 2007.<br />

[ISO/IEC TR 24731-2:2010]<br />

ISO/IEC. Extensions to the C Library—Part II: Dynamic Allocation Functions (ISO/IEC TR<br />

24731). Geneva, Switzerland: ISO, April 2010.<br />

[ISO/IEC TR 24772:2010]<br />

ISO/IEC. Information Technology—Programming Languages—Guidance to Avoiding Vulnerabilities<br />

in Programming Languages through Language Selection and Use (ISO/IEC TR<br />

24772:2010). Geneva, Switzerland: ISO, October 2010.<br />

[ISO/IEC TR 24772:2013]<br />

ISO/IEC. Information Technology—Programming Languages—Guidance to Avoiding Vulnerabilities<br />

in Programming Languages through Language Selection and Use (ISO/IEC TR<br />

24772:2013). Geneva, Switzerland: ISO, March 2013.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 488<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[ISO/IEC TS 17961]<br />

ISO/IEC. Information Technology—Programming Languages, Their Environments and System<br />

Software Interfaces—C Secure <strong>Coding</strong> Rules (ISO/IEC TS 17961). Geneva, Switzerland: ISO,<br />

2012.<br />

[ISO/IEC WG14 N1173]<br />

ISO/IEC WG14 N1173. Rationale for TR 24731 Extensions to the C Library—Part I: Bounds-<br />

Checking Interfaces.<br />

[Jack 2007]<br />

Jack, Barnaby. Vector Rewrite Attack. May 2007.<br />

[Jones 2004]<br />

Jones, Nigel. Learn a New Trick with the offsetof() Macro. Embedded Systems Programming,<br />

March 2004.<br />

[Jones 2008]<br />

Jones, Derek M. The New C <strong>Standard</strong>: An Economic and Cultural Commentary. Knowledge Software<br />

Ltd., 2008.<br />

[Jones 2010]<br />

Jones, Larry. (2010). WG14 N1539 Committee Draft ISO/IEC 9899:201x.<br />

[Juric n.d.]<br />

Juric, Zeljko, et al. (n.d.). TIGCC Documentation, Latest Development Version<br />

(TIGCC/TIGCCLIB CVS): C Language Keywords.<br />

[Keaton 2009]<br />

Keaton, David; Plum, Thomas; Seacord, Robert C.; Svoboda, David; Volkovitsky, Alex; & Wilson,<br />

Timothy. As-if Infinitely Ranged Integer Model. CMU/<strong>SEI</strong>-2009-TN-023. July 2009.<br />

[Keil 2008]<br />

Keil, an ARM Company. “Floating Point Support.” RealView Libraries and Floating Point Support<br />

Guide, 2008.<br />

[Kennaway 2000]<br />

Kennaway, Kris. Re: /tmp topic. December 2000.<br />

[Kernighan 1988]<br />

Kernighan, Brian W. & Ritchie, Dennis M. The C Programming Language, 2nd ed. Englewood<br />

Cliffs, NJ: Prentice-Hall, 1988.<br />

[Kettlewell 2002]<br />

Kettlewell, Richard. C Language Gotchas. February 2002.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 489<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Kettlewell 2003]<br />

Kettlewell, Richard. Inline Functions in C. March 2003.<br />

[Kirch-Prinz 2002]<br />

Kirch-Prinz, Ulla & Prinz, Peter. C Pocket Reference. Sebastopol, CA: O’Reilly, November 2002<br />

(ISBN: 0-596-00436-2).<br />

[Klarer 2004]<br />

Klarer, R., Maddock, J.; Dawes, B.; & Hinnant, H. “Proposal to Add Static Assertions to the Core<br />

Language (Revision 3).” ISO C++ committee paper ISO/IEC JTC1/SC22/WG21/N1720, October<br />

2004.<br />

[Klein 2002]<br />

Klein, Jack. Bullet Proof Integer Input Using strtol(). 2002.<br />

[Koenig 1989]<br />

Koenig, Andrew. C Traps and Pitfalls. Addison-Wesley Professional, 1989.<br />

[Kuhn 2006]<br />

Kuhn, Markus. UTF-8 and Unicode FAQ for Unix/Linux. 2006.<br />

[Lai 2006]<br />

Lai, Ray. “Reading Between the Lines.” OpenBSD Journal, October 2006.<br />

[Lea 2000]<br />

Lea, Doug. Concurrent Programming in Java, 2nd ed., Addison-Wesley Professional, Boston,<br />

2000.<br />

[Lewis 2006]<br />

Lewis, Richard. “Security Considerations when Handling Sensitive Data.” Posted on the Application<br />

Security by Richard Lewis blog October 2006.<br />

[Linux 2008]<br />

Linux Programmer’s Manual. October 2008.<br />

[Lions 1996]<br />

Lions, J. L. ARIANE 5 Flight 501 Failure Report. Paris, France: European Space Agency (ESA)<br />

& National Center for Space Study (CNES) Inquiry Board, July 1996.<br />

[Lipson 2000]<br />

Lipson, Howard & Fisher, David. “Survivability: A New Technical and Business Perspective on<br />

Security,” 33–39. Proceedings of the 1999 New Security Paradigms Workshop. Caledon Hills,<br />

Ontario, Canada, Sept. 22–24, 1999. New York: Association for Computing Machinery, 2000.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 490<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Lipson 2006]<br />

Lipson, Howard. Evolutionary Systems Design: Recognizing Changes in Security and Survivability<br />

Risks (CMU/<strong>SEI</strong>-2006-TN-027). Pittsburgh, PA: Software Engineering Institute, Carnegie<br />

Mellon University, 2006.<br />

[Liu 2009]<br />

Likai Liu. Making NULL-pointer reference legal, Life of a Computer Science Student. January,<br />

2009.<br />

[Lockheed Martin 2005]<br />

Lockheed Martin. Joint Strike Fighter Air Vehicle C++ <strong>Coding</strong> <strong>Standard</strong>s for the System Development<br />

and Demonstration Program. Document Number 2RDU00001 Rev C., December 2005.<br />

[Loosemore 2007]<br />

Loosemore, Sandra; Stallman, Richard M.; McGrath, Roland; Oram, Andrew; & Drepper, Ulrich.<br />

The GNU C Library Reference Manual, Edition 0.11. September 2007.<br />

[McCluskey 2001]<br />

McCluskey, Glen. Flexible Array Members and Designators in C9X. ;login:, 26, 4 (July 2001):<br />

29–32.<br />

[Mell 2007]<br />

Mell, Peter; Scarfone, Karen; & Romanosky, Sasha. “A Complete Guide to the Common Vulnerability<br />

Scoring System Version 2.0.” FIRST, June 2007.<br />

[Mercy 2006]<br />

Mercy. Exploiting Uninitialized Data. January 2006.<br />

[Meyers 2004]<br />

Meyers, Randy. Limited size_t WG14 N1080. September 2004.<br />

[Michael 2004]<br />

Michael, M.M. “Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects.” IEEE<br />

Transactions on Parallel and Distributed Systems, 15, 8 (2004).<br />

[Microsoft 2003]<br />

Microsoft Security Bulletin MS03-026, “Buffer Overrun In RPC Interface Could Allow Code Execution<br />

(823980).” September 2003.<br />

[Microsoft 2007]<br />

Microsoft. C Language Reference, 2007.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 491<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Miller 1999]<br />

Miller, Todd C. & de Raadt, Theo. strlcpy and strlcat—Consistent, Safe, String Copy and Concatenation.<br />

In Proceedings of the FREENIX Track, 1999 USENIX Annual Technical Conference,<br />

June 6–11, 1999, Monterey, California, USA. Berkeley, CA: USENIX Association, 1999.<br />

[Miller 2004]<br />

Miller, Mark C.; Reus, James F.; Matzke, Robb P.; Koziol, Quincey A.; & Cheng, Albert P.<br />

“Smart Libraries: Best SQE Practices for Libraries with an Emphasis on Scientific Computing.”<br />

In Proceedings of the Nuclear Explosives Code Developer’s Conference. Livermore, CA: Lawrence<br />

Livermore National Laboratory, December 2004.<br />

[Miller 2007]<br />

Miller, Damien. “Security Measures in OpenSSH,” white paper. OpenSSH Project, 2007.<br />

[MISRA 2004]<br />

MISRA (Motor Industry Software Reliability Association). MISRA C: 2004 Guidelines for the<br />

Use of the C Language in Critical Systems. Nuneaton, UK: MIRA, 2004 (ISBN 095241564X).<br />

[MISRA 2008]<br />

MISRA. MISRA C++: 2008 Guidelines for the Use of the C++ Language in Critical Systems.<br />

Nuneaton, UK: MIRA, 2008 (ISBN 978-906400-03-3 [paperback], ISBN 978-906400-04-0<br />

[PDF]), 2008.<br />

[MISRA C:2012]<br />

MISRA. MISRA C3: Guidelines for the Use of the C Language in Critical Systems 2012. Nuneaton,<br />

UK: MIRA, 2012. ISBN 978-1-906400-10-1.<br />

[MIT 2004]<br />

MIT (Massachusetts Institute of Technology). “MIT krb5 Security Advisory 2004-002,” 2004.<br />

[MIT 2005]<br />

MIT. “MIT krb5 Security Advisory 2005-003.<br />

[MITRE 2010]<br />

MITRE. Common Weakness Enumeration, Version 1.8. February 2010.<br />

[MITRE 2007]<br />

MITRE. Common Weakness Enumeration, Draft 9. April 2008.<br />

[MKS]<br />

MKS, Inc. MKS Reference Pages.<br />

[MSDN]<br />

Microsoft Developer Network.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 492<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Murenin 2007]<br />

Murenin, Constantine A. cnst: 10-Year-Old Pointer-Arithmetic Bug in make(1) Is Now Gone,<br />

Thanks to malloc.conf and Some Debugging. LiveJournal, June 2007.<br />

[NAI 1998]<br />

Network Associates, Inc. Bugtraq: Network Associates Inc. Advisory (OpenBSD). 1998.<br />

[NASA-GB-1740.13]<br />

NASA Glenn Research Center, Office of Safety Assurance Technologies. NASA Software Safety<br />

Guidebook (NASA-GB-1740.13).<br />

[NIST 2006]<br />

NIST. SAMATE Reference Dataset. 2006.<br />

[OpenBSD]<br />

Berkley Software Design, Inc. Manual Pages. June 2008.<br />

[Open Group 1997a]<br />

The Open Group. The Single UNIX® Specification, Version 2. 1997.<br />

[Open Group 1997b]<br />

The Open Group. Go Solo 2—The Authorized Guide to Version 2 of the Single UNIX Specification.<br />

May 1997.<br />

[Open Group 2004]<br />

The Open Group. The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition.<br />

2004. (See also IEEE Std 1003.1-2004.)<br />

[Open Group 2008]<br />

The Open Group. The Open Group Base Specifications Issue 7, IEEE Std 1003.1, 2008 Edition.<br />

2008. (See also IEEE Std 1003.1-2008.)<br />

[OpenMP]<br />

The OpenMP API® Specification for Parallel Programming.<br />

[OWASP Double Free]<br />

Open Web Application Security Project, “Double Free.”<br />

[OWASP Freed Memory]<br />

Open Web Application Security Project, “Using Freed Memory.”<br />

[Pethia 2003]<br />

Pethia, Richard D. “Viruses and Worms: What Can We Do About Them?” September 10, 2003.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 493<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Pfaff 2004]<br />

Pfaff, Ken Thompson. “Casting (time_t)(-1).” Google Groups comps.lang.c, March 2, 2004.<br />

[Pike 1993]<br />

Pike, Rob & Thompson, Ken. “Hello World.” Proceedings of the USENIX Winter 1993 Technical<br />

Conference, San Diego, CA, January 25–29, 1993, pp3 43–50.<br />

[Plakosh 2005]<br />

Plakosh, Dan. “Consistent Memory Management Conventions.” Build Security In, 2005.<br />

[Plum 1985]<br />

Plum, Thomas. Reliable Data Structures in C. Kamuela, HI: Plum Hall, Inc., 1985 (ISBN 0-<br />

911537-04-X).<br />

[Plum 1989]<br />

Plum, Thomas & Saks, Dan. C Programming Guidelines, 2nd ed. Kamuela, HI: Plum Hall, 1989<br />

(ISBN 0911537074).<br />

[Plum 1991]<br />

Plum, Thomas. C++ Programming. Kamuela, HI: Plum Hall, 1991 (ISBN 0911537104).<br />

[Plum 2008]<br />

Plum, Thomas. “Static Assertions.” June 2008.<br />

[Plum 2012]<br />

Plum, Thomas. C Finally Gets a New <strong>Standard</strong>. Dr. Dobb’s, 2012.<br />

[Redwine 2006]<br />

Redwine, Samuel T., Jr., ed. Secure Software Assurance: A Guide to the Common Body of<br />

Knowledge to Produce, Acquire, and Sustain Secure Software Version 1.1. U.S. Department of<br />

Homeland Security, September 2006. (See Software Assurance Common Body of Knowledge on<br />

Build Security In.)<br />

[Roelker 2004]<br />

Roelker, Daniel. “HTTP IDS Evasions Revisited.” September 2004.<br />

[RUS-<strong>CERT</strong>]<br />

RUS-<strong>CERT</strong> Advisory 2002-08:02, “Flaw in calloc and Similar Routines.“ 2002.<br />

[Saks 1999]<br />

Saks, Dan. “const T vs.T const.” Embedded Systems Programming, February 1999, pp. 13–16.<br />

[Saks 2000]<br />

Saks, Dan. “Numeric Literals.” Embedded Systems Programming, September 2000.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 494<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Saks 2001a]<br />

Saks, Dan. “Symbolic Constants.” Embedded Systems Design, November 2001.<br />

[Saks 2001b]<br />

Saks, Dan. “Enumeration Constants vs. Constant Objects.” Embedded Systems Design, November<br />

2001.<br />

[Saks 2002]<br />

Saks, Dan. “Symbolic Constant Expressions.” Embedded Systems Design, February 2002.<br />

[Saks 2005]<br />

Saks, Dan. “Catching Errors Early with Compile-Time Assertions.” Embedded Systems Design,<br />

June 2005.<br />

[Saks 2007a]<br />

Saks, Dan. “Sequence Points.“ Embedded Systems Design, July 1, 2002.<br />

[Saks 2007b]<br />

Saks, Dan. “Bail, Return, Jump, or . . . Throw?” Embedded Systems Design, March 2007.<br />

[Saks 2007c]<br />

Saks, Dan. “<strong>Standard</strong> C’s Pointer Difference Type.” Embedded Systems Design, October 2007.<br />

[Saks 2008]<br />

Saks, Dan & Dewhurst, Stephen C. “Sooner Rather Than Later: Static Programming Techniques<br />

for C++” (presentation). March 2008.<br />

[Saltzer 1974]<br />

Saltzer, J. H. “Protection and the Control of Information Sharing in Multics.” Communications of<br />

the ACM 17, 7 (July 1974): 388–402.<br />

[Saltzer 1975]<br />

Saltzer, J. H. & Schroeder, M. D. “The Protection of Information in Computer Systems.” Proceedings<br />

of the IEEE 63, 9 (September 1975): 1278–1308.<br />

[Schwarz 2005]<br />

Schwarz, B.; Wagner, Hao Chen; Morrison, D.; West, G.; Lin, J.; & Tu, J. Wei. “Model Checking<br />

an Entire Linux Distribution for Security Violations.” Proceedings of the 21st Annual Computer<br />

Security Applications Conference, December 2005 (ISSN 1063-9527; ISBN 0-7695-2461-3).<br />

[Seacord 2003]<br />

Seacord, Robert C.; Plakosh, Daniel; & Lewis, Grace A. Modernizing Legacy Systems: Software<br />

Technologies, Engineering Processes, and Business Practices. Boston: Addison-Wesley, 2003.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 495<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Seacord 2005a]<br />

Seacord, Robert C. Secure <strong>Coding</strong> in C and C++. Boston: Addison-Wesley, 2005. (See<br />

http://www.cert.org/books/secure-coding for news and errata.)<br />

[Seacord 2005b]<br />

Seacord, Robert C. “Managed String Library for C, C/C++.” Users Journal, 23, 10 (October<br />

2005): 30–34.<br />

[Seacord 2005c]<br />

Seacord, Robert C. “Variadic Functions: How They Contribute to Security Vulnerabilities and<br />

How to Fix Them.” Linux World Magazine, November 2005.<br />

[Seacord 2013a]<br />

Seacord, Robert C. “C Secure <strong>Coding</strong> Rules: Past, Present, and Future.” InformIT, June 26, 2013..<br />

[Seacord 2013b]<br />

Seacord, Robert C. Secure <strong>Coding</strong> in C and C++. Boston: Addison-Wesley, 2013. (See<br />

http://www.cert.org/books/secure-coding for news and errata.)<br />

[Secunia]<br />

Secunia Advisory SA10635, “HP-UX calloc Buffer Size Miscalculation Vulnerability.” 2004.<br />

[SecuriTeam 2007]<br />

SecuriTeam. “Microsoft Visual C++ 8.0 <strong>Standard</strong> Library Time Functions Invalid Assertion DoS<br />

(Problem 3000).” February 13, 2007.<br />

[SecurityFocus 2007]<br />

SecurityFocus. “Linux Kernel Floating Point Exception Handler Local Denial of Service Vulnerability.”<br />

2001.<br />

[Sloss 2004]<br />

Sloss, Andrew, Symes, Dominic, & Wright, Chris. ARM System Developer’s Guide. San Francisco:<br />

Elsevier/Morgan Kauffman, 2004 (ISBN-10: 1558608745; ISBN-13: 978-1558608740).<br />

[Spinellis 2006]<br />

Spinellis, Diomidis. Code Quality: The Open Source Perspective. Boston: Addison-Wesley, 2006.<br />

[StackOvflw 2009]<br />

StackOverflow.com. “Should I return TRUE / FALSE values from a C function?” User Questions,<br />

March 15, 2010.<br />

[Steele 1977]<br />

Steele, G. L. “Arithmetic shifting considered harmful.” SIGPLAN Not. 12, 11 (November 1977):<br />

61–69.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 496<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[Stevens 2005]<br />

Stevens, W. Richard. Advanced Programming in the UNIX Environment. Boston: Addison-Wesley,<br />

1995 (ISBN 032152594-9).<br />

[Summit 1995]<br />

Summit, Steve. C Programming FAQs: Frequently Asked Questions. Boston: Addison-Wesley,<br />

1995 (ISBN 0201845199).<br />

[Summit 2005]<br />

Summit, Steve. comp.lang.c Frequently Asked Questions. 2005.<br />

[Sun 1993]<br />

Sun Microsystems. Sun Security Bulletin #00122 1993.<br />

[Sun 2005]<br />

Sun Microsystems. C User’s Guide. 819-3688-10. Sun Microsystems, 2005.<br />

[Sutter 2004]<br />

Sutter, Herb & Alexandrescu, Andrei. C++ <strong>Coding</strong> <strong>Standard</strong>s: 101 Rules, Guidelines, and Best<br />

Practices. Boston: Addison-Wesley Professional, 2004 (ISBN 0321113586).<br />

[Tsafrir 2008]<br />

Tsafrir, Dan; Da Silva, Dilma; & Wagner, David. The Murky Issue of Changing Process Identity:<br />

Revising “Setuid Demystified.” USENIX, June 2008, pp. 55–66<br />

[Unicode 2006]<br />

The Unicode Consortium. The Unicode <strong>Standard</strong>, Version 5.0, 5th ed. Boston: Addison-Wesley<br />

Professional, 2006 (ISBN: 0321480910).<br />

[Unicode 2012]<br />

The Unicode Consortium. The Unicode <strong>Standard</strong>, Version 6.2.<br />

[UNIX 1992]<br />

UNIX System Laboratories. System V Interface Definition, 3rd ed. Wokingham, MA: Addison-<br />

Wesley, 1992.<br />

[van de Voort 2007]<br />

van de Voort, Marco. Development Tutorial (a.k.a Build FAQ). January 29, 2007.<br />

[Vanegue 2010]<br />

Vanegue, Julien. Automated Vulnerability Analysis of Zero-Sized Head Allocations. Hackito<br />

Ergo Sum (HES’10) Conference, Paris, April 10, 2010.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 497<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[van Sprundel 2006]<br />

van Sprundel, Ilja. Unusualbugs. 2006.<br />

[Viega 2001]<br />

Viega, John. Protecting Sensitive Data in Memory. February 2001.<br />

[Viega 2003]<br />

Viega, John & Messier, Matt. Secure Programming Cookbook for C and C++: Recipes for Cryptography,<br />

Authentication, Networking, Input Validation & More. Sebastopol, CA: O’Reilly, 2003<br />

(ISBN 0-596-00394-3).<br />

[Viega 2005]<br />

Viega, John. CLASP Reference Guide Volume 1.1. Secure Software, 2005.<br />

[VU#159523]<br />

Giobbi, Ryan. Vulnerability Note VU#159523, Adobe Flash Player Integer Overflow Vulnerability.<br />

April 2008.<br />

[VU#162289]<br />

Dougherty, Chad. Vulnerability Note VU#162289, GCC Silently Discards Some Wraparound<br />

Checks. April 2008.<br />

[VU#196240]<br />

Taschner, Chris & Manion, Art. Vulnerability Note VU#196240, Sourcefire Snort DCE/RPC Preprocessor<br />

Does Not Properly Reassemble Fragmented Packets. 2007.<br />

[VU#286468]<br />

Burch, Hal. Vulnerability Note VU#286468, Ettercap Contains a Format String Error in the<br />

“curses_msg()” Function. 2007.<br />

[VU#439395]<br />

Lipson, Howard. Vulnerability Note VU#439395, Apache Web Server Performs Case Sensitive<br />

Filtering on Mac OS X HFS+ Case Insensitive Filesystem. 2001.<br />

[VU#551436]<br />

Giobbi, Ryan. Vulnerability Note VU#551436, Mozilla Firefox SVG Viewer Vulnerable to Buffer<br />

Overflow. 2007.<br />

[VU#568148]<br />

Finlay, Ian A. & Morda, Damon G. Vulnerability Note VU#568148, Microsoft Windows RPC<br />

Vulnerable to Buffer Overflow. 2003.<br />

[VU#623332]<br />

Mead, Robert. Vulnerability Note VU#623332, MIT Kerberos 5 Contains Double-Free Vulnerability<br />

in “krb5_recvauth()” Function. 2005.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 498<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[VU#649732]<br />

Gennari, Jeff. Vulnerability Note VU#649732, Samba AFS ACL Mapping VFS Plug-In Format<br />

String Vulnerability. 2007.<br />

[VU#654390]<br />

Rafail, Jason A. Vulnerability Note VU#654390 ISC DHCP Contains C Includes That Define vsnprintf()<br />

to vsprintf() Creating Potential Buffer Overflow Conditions. June 2004.<br />

[VU#720951]<br />

Dorman, Will. Vulnerability Note VU#720951, OpenSSL TLS Heartbeat Extension Read Overflow<br />

Discloses Sensitive Information. April 2014<br />

[VU#743092]<br />

Rafail, Jason A. & Havrilla, Jeffrey S. Vulnerability Note VU#743092, realpath(3) Function Contains<br />

Off-by-One Buffer Overflow. July 2003.<br />

[VU#834865]<br />

Gennari, Jeff. Vulnerability Note VU#834865, Sendmail Signal I/O Race Condition. March 2008.<br />

[VU#837857]<br />

Dougherty, Chad. Vulnerability Note VU#837857, SX.Org Server Fails to Properly Test for Effective<br />

User ID. August 2006.<br />

[VU#881872]<br />

Manion, Art & Taschner, Chris. Vulnerability Note VU#881872, Sun Solaris Telnet Authentication<br />

Bypass Vulnerability. 2007.<br />

[VU#925211]<br />

Dougherty, Chad. Vulnerability Note VU#925211, “Debian and Ubuntu OpenSSL Packages Contain<br />

a Predictable Random Number Generator.” June 2008.<br />

[Walfridsson 2003]<br />

Walfridsson, Krister. Aliasing, Pointer Casts and GCC 3.3. August 2003.<br />

[Walls 2006]<br />

Walls, Douglas. How to Use the Qualifier in C. Sun ONE Tools Group, Sun Microsystems.<br />

March 2006.<br />

[Wang 2012]<br />

Wang, Xi. More Randomness or Less. June 2012.<br />

[Warren 2002]<br />

Warren, Henry S. Hacker’s Delight. Boston: Addison Wesley, 2002 (ISBN 0201914654).<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 499<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


[WG14/N1396]<br />

Thomas, J. & Tydeman, F. “Wide function return values.”( WG14/N1396) September 2009.<br />

[Wheeler 2003]<br />

Wheeler, David. Secure Programming for Linux and Unix HOWTO, v3.010. March 2003.<br />

[Wheeler 2004]<br />

Wheeler, David. Secure Programmer: Call Components Safely. December 2004.<br />

[Wojtczuk 2008]<br />

Wojtczuk, Rafal. “Analyzing the Linux Kernel vmsplice Exploit.” McAfee Avert Labs Blog, February<br />

13, 2008.<br />

[xorl 2009]<br />

xorl. xorl %eax, %eax. 2009.<br />

[Yergeau 1998]<br />

Yergeau, F. RFC 2279 - UTF-8, a transformation format of ISO 10646. January 1998.<br />

[Zadegan 2009]<br />

Zadegan, B. “A Lesson on Infinite Loops.” WinJade (formerly AeroXperience), January 2009.<br />

[Zalewski 2001]<br />

Zalewski, Michal. Delivering Signals for Fun and Profit: Understanding, Exploiting and Preventing<br />

Signal-Handling Related Vulnerabilities. Bindview Corporation, May 2001.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 500<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Appendix B: Definitions<br />

abnormal end<br />

Termination of a process prior to completion [ISO/IEC/IEEE 24765:2010].<br />

abnormal program termination<br />

See abnormal end.<br />

analyzer<br />

Mechanism that diagnoses coding flaws in software programs [ISO/IEC 9899:2011].<br />

NOTE: Analyzers may include static analysis tools, tools within a compiler suite, or tools in other<br />

contexts.<br />

async-signal-safe function<br />

A function that may be invoked, without restriction, from signal-catching functions. No function<br />

(defined in ISO/IEC 9945) is async-signal-safe unless explicitly described as such. See asynchronous-safe<br />

[ISO/IEC 9945:2008].<br />

asynchronous-safe function<br />

A function is asynchronous-safe, or asynchronous-signal safe, if it can be called safely and without<br />

side effects from within a signal handler context. That is, it must be able to be interrupted at<br />

any point to run linearly out of sequence without causing an inconsistent state. It must also function<br />

properly when global data might itself be in an inconsistent state. Some asynchronous-safe<br />

operations are listed here:<br />

Call the signal() function to reinstall a signal handler:<br />

• Unconditionally modify a volatile sig_atomic_t variable (as modification to this type<br />

is atomic).<br />

• Call the _Exit() function to immediately terminate program execution.<br />

• Invoke an asynchronous-safe function, as specified by the implementation.<br />

Few functions are portably asynchronous-safe [GNU Pth].<br />

availability<br />

The degree to which a system or component is operational and accessible when required for use.<br />

Often expressed as a probability [IEEE Std 610.12 1990].<br />

condition predicate<br />

An expression constructed from the variables of a function that must be true for a thread to be allowed<br />

to continue execution.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 501<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


conforming<br />

Conforming programs may depend on nonportable features of a conforming implementation<br />

[ISO/IEC 9899:2011].<br />

critical sections<br />

Code that accesses shared data and would otherwise be protected from data races.<br />

dangling pointer<br />

A pointer to deallocated memory.<br />

data flow analysis<br />

Tracking of value constraints along nonexcluded paths through the code.<br />

NOTE: Tracking can be performed intraprocedurally, with various assumptions made about what<br />

happens at function call boundaries, or interprocedurally, where values are tracked flowing into<br />

function calls (directly or indirectly) as arguments and flowing back out either as return values or<br />

indirectly through arguments.<br />

Data flow analysis may or may not track values flowing into or out of the heap or take into account<br />

global variables. When this specification refers to values flowing, the key point is contrast<br />

with variables or expressions because a given variable or expression may hold different values<br />

along different paths and a given value may be held by multiple variables or expressions along a<br />

path.<br />

data race<br />

The execution of a program contains a data race if it contains two conflicting actions in different<br />

threads, at least one of which is not atomic, and neither happens before the other. Any such data<br />

race results in undefined behavior [ISO/IEC 9899:2011].<br />

denial-of-service attack<br />

Also DoS attack. An attempt to make a computer resource unavailable to its intended users.<br />

diagnostic message<br />

A message belonging to an implementation-defined subset of the implementation’s message output.<br />

A diagnostic message may indicate a constraint violation or a valid but questionable language<br />

construct. Messages typically include the file name and line number pointing to the offending<br />

code construct. In addition, implementations often indicate the severity of the problem. Although<br />

the C <strong>Standard</strong> does not specify any such requirement, the most severe problems often cause implementations<br />

to fail to fully translate a translation unit. Diagnostics output in such cases are<br />

termed errors. Other problems may cause implementations simply to issue a warning message and<br />

continue translating the rest of the program. See error message and warning message [ISO/IEC<br />

9899:2011].<br />

double-free vulnerability<br />

An exploitable error resulting from the same allocated object being freed more than once.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 502<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


error message<br />

A diagnostic message generated when source code is encountered that prevents an implementation<br />

from translating a translation unit. See diagnostic message and warning message.<br />

error tolerance<br />

The ability of a system or component to continue normal operation despite the presence of erroneous<br />

inputs [IEEE Std 610.12 1990].<br />

exploit<br />

Technique that takes advantage of a security vulnerability to violate an explicit or implicit security<br />

policy [ISO/IEC TS 17961:2013].<br />

fail safe<br />

Pertaining to a system or component that automatically places itself in a safe operating mode in<br />

the event of a failure—for example, a traffic light that reverts to blinking red in all directions<br />

when normal operation fails [IEEE Std 610.12 1990].<br />

fail soft<br />

Pertaining to a system or component that continues to provide partial operational capability in the<br />

event of certain failures—for example, a traffic light that continues to alternate between red and<br />

green if the yellow light fails [IEEE Std 610.12 1990].<br />

fatal diagnostic<br />

A diagnostic message that causes an implementation not to perform the translation.<br />

fault tolerance<br />

The ability of a system or component to continue normal operation despite the presence of hardware<br />

or software faults [IEEE Std 610.12 1990].<br />

freestanding environment<br />

An environment in which C program execution may take place without any benefit of an operating<br />

system. Program startup might occur at some function other than main(), complex types<br />

might not be implemented, and only certain minimal library facilities are guaranteed to be available<br />

[ISO/IEC 9899:2011].<br />

function-like macro<br />

A #define preprocessing directive that defines an identifier immediately followed by zero or<br />

more parameters, the ellipsis (...), or a combination of the two, enclosed in parentheses, similar<br />

syntactically to a function call. Subsequent instances of the macro name followed by a parenthesized<br />

list of arguments in a translation unit are replaced by the replacement list of preprocessing<br />

tokens that constitute the remainder of the directive. See object-like macro and unsafe functionlike<br />

macro [ISO/IEC 9899:2011].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 503<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


hosted environment<br />

An environment that is not freestanding. Program startup occurs at main(), complex types are<br />

implemented, and all C standard library facilities are available [ISO/IEC 9899:2011].<br />

implementation<br />

Particular set of software, running in a particular translation environment under particular control<br />

options, that performs translation of programs for, and supports execution of functions in, a particular<br />

execution environment [ISO/IEC 9899:2011].<br />

implementation-defined behavior<br />

Unspecified behavior whereby each implementation documents how the choice is made [ISO/IEC<br />

9899:2011].<br />

in-band error indicator<br />

A library function return value on error that can never be returned by a successful call to that library<br />

function [ISO/IEC 9899:2011].<br />

incomplete type<br />

A type that describes an identifier but lacks information needed to determine the size of the identifier<br />

[ISO/IEC 9899:2011].<br />

indeterminate value<br />

Either an unspecified value or a trap representation [ISO/IEC 9899:2011].<br />

invalid pointer<br />

A pointer that is not a valid pointer.<br />

liveness<br />

Every operation or method invocation executes to completion without interruptions, even if it<br />

goes against safety.<br />

locale-specific behavior<br />

Behavior that depends on local conventions of nationality, culture, and language that each implementation<br />

documents [ISO/IEC 9899:2011].<br />

lvalue<br />

An expression with an object type or an incomplete type other than void. The name lvalue comes<br />

originally from the assignment expression E1 = E2, in which the left operand E1 is required to<br />

be a (modifiable) lvalue. It is perhaps better considered as representing an object “locator value”<br />

[ISO/IEC 9899:2011].<br />

mitigation<br />

Methods, techniques, processes, tools, or runtime libraries that can prevent or limit exploits<br />

against vulnerabilities [Seacord 2005a].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 504<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


mutilated value<br />

Result of an operation performed on an untainted value that yields either an undefined result (such<br />

as the result of signed integer overflow), the result of right-shifting a negative number, implicit<br />

conversion to an integral type where the value cannot be represented in the destination type, or<br />

unsigned integer wrapping.<br />

EXAMPLE<br />

int j = INT_MAX + 1; // j is mutilated<br />

char c = 1234; // c is mutilated if char is eight bits<br />

unsigned int u = 0U - 1; // u is mutilated<br />

NOTE: A mutilated value can be just as dangerous as a tainted value because it can differ either in<br />

sign or magnitude from what the programmer expects.<br />

nonpersistent signal handler<br />

Signal handler running on an implementation that requires the program to again register the signal<br />

handler after occurrences of the signal to catch subsequent occurrences of that signal.<br />

normal program termination<br />

Normal termination occurs by a return from main(), when requested with the exit(), _exit(),<br />

or _Exit() functions, or when the last thread in the process terminates by returning from its start<br />

function, by calling the pthread_exit() function or through cancellation. See abnormal termination<br />

[IEEE Std 1003.1-2013].<br />

object-like macro<br />

A #define preprocessing directive that defines an identifier with no parentheses. Subsequent instances<br />

of the macro name in a translation unit are replaced by the replacement list of preprocessing<br />

tokens that constitute the remainder of the directive. See function-like macro [ISO/IEC<br />

9899:2011].<br />

out-of-band error indicator<br />

A library function return value used to indicate nothing but the error status [ISO/IEC TS<br />

17961:2013].<br />

out-of-domain value<br />

One of a set of values that is not in the domain of a particular operator or function [ISO/IEC TS<br />

17961:2013].<br />

reentrant<br />

Pertaining to a software module that can be entered as part of one process while also in execution<br />

as part of another process and still achieve the desired results [ISO/IEC/IEEE 24765:2010].<br />

reliability<br />

The ability of a system or component to perform its required functions under stated conditions for<br />

a specified period of time [IEEE Std 610.12 1990].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 505<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


estricted sink<br />

Operands and arguments whose domain is a subset of the domain described by their types<br />

[ISO/IEC 9899:2011].<br />

robustness<br />

The degree to which a system or component can function correctly in the presence of invalid inputs<br />

or stressful environmental conditions [IEEE Std 610.12 1990].<br />

rvalue<br />

Value of an expression [ISO/IEC 9899:2011].<br />

sanitize<br />

Assure by testing or replacement that a tainted or other value conforms to the constraints imposed<br />

by one or more restricted sinks into which it may flow [ISO/IEC TS 17961:2013].<br />

NOTE: If the value does not conform, either the path is diverted to avoid using the value or a different,<br />

known-conforming value is substituted—for example, adding a null character to the end of<br />

a buffer before passing it as an argument to the strlen function.<br />

security flaw<br />

Defect that poses a potential security risk [ISO/IEC TS 17961:2013].<br />

security policy<br />

Set of rules and practices that specify or regulate how a system or organization provides security<br />

services to protect sensitive and critical system resources [Internet Society 2000].<br />

sequence point<br />

Evaluation of an expression may produce side effects. At specific points in the execution sequence<br />

called sequence points, all side effects of previous evaluations have completed, and no<br />

side effects of subsequent evaluations have yet taken place [ISO/IEC 9899:2011].<br />

side effect<br />

Changes in the state of the execution environment achieved by accessing a volatile object, modifying<br />

an object, modifying a file, or calling a function that does any of those operations [ISO/IEC<br />

9899:2011].<br />

NOTE: The IEC 60559 standard for binary floating-point arithmetic requires certain user-accessible<br />

status flags and control modes. Floating-point operations implicitly set the status flags; modes<br />

affect result values of floating-point operations. Implementations that support such a floatingpoint<br />

state are required to regard changes to it as side effects. These are detailed in Annex F of the<br />

C <strong>Standard</strong>.<br />

static analysis<br />

Any process for assessing code without executing it [ISO/IEC TS 17961:2013].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 506<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


strictly conforming<br />

A strictly conforming program is one that uses only those features of the language and library<br />

specified in the international standard. Strictly conforming programs are intended to be maximally<br />

portable among conforming implementations and cannot, for example, depend on implementation-defined<br />

behavior [ISO/IEC 9899:2011].<br />

string<br />

A contiguous sequence of characters terminated by and including the first null character [ISO/IEC<br />

9899:2011].<br />

tainted source<br />

External source of untrusted data.<br />

NOTE: Tainted sources include<br />

• parameters to the main() function, the returned values from localeconv(), fgetc(),<br />

getc, getchar(), fgetwc(), getwc(), and getwchar(), and the strings produced by<br />

getenv(), fscanf(), vfscanf(), vscanf(), fgets(), fread(), fwscanf(), vfwscanf(),<br />

vwscanf(), wscanf(), and fgetws()<br />

• parameters to the main() function,<br />

• the returned values from localeconv(), fgetc(), getc, getchar(), fgetwc(),<br />

getwc(), and getwchar()<br />

• the strings produced by getenv(), fscanf(), vfscanf(), vscanf(), fgets(),<br />

fread(), fwscanf(), vfwscanf(), vwscanf(), wscanf(), and fgetws()[ISO/IEC TS<br />

17961:2013]<br />

tainted value<br />

Value derived from a tainted source that has not been sanitized [ISO/IEC TS 17961:2013].<br />

target implementation<br />

Implementation of the C programming language whose environmental limits and implementationdefined<br />

behavior are assumed by the analyzer during the analysis of a program [ISO/IEC TS<br />

17961:2013].<br />

TOCTOU, TOCTTOU<br />

Time-of-check, time-of-use (TOCTOU), also referred to as time-of-check-to-time-of-use<br />

(TOCTTOU), represents a vulnerability in which access control checks are nonatomic with the<br />

operations they protect, allowing an attacker to violate access control rules.<br />

trap representation<br />

Object representation that does not represent a value of the object type. Attempting to read the<br />

value of an object that has a trap representation other than by an expression that has a character<br />

type is undefined. Producing such a representation by a side effect that modifies all or any part of<br />

the object other than by an expression that has a character type is undefined [ISO/IEC<br />

9899:2011].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 507<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


undefined behavior (UB)<br />

Behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for<br />

which the C <strong>Standard</strong> imposes no requirements. An example of undefined behavior is the behavior<br />

on integer overflow [ISO/IEC 9899:2011].<br />

unexpected behavior<br />

Well-defined behavior that may be unexpected or unanticipated by the programmer; incorrect programming<br />

assumptions.<br />

unsafe function-like macro<br />

A function-like macro whose expansion causes one or more of its arguments not to be evaluated<br />

exactly once.<br />

unsigned integer wrapping<br />

Computation involving unsigned operands whose result is reduced modulo the number that is one<br />

greater than the largest value that can be represented by the resulting type.<br />

unspecified behavior<br />

Behavior for which the standard provides two or more possibilities and imposes no further requirements<br />

on which is chosen in any instance [ISO/IEC 9899:2011].<br />

unspecified value<br />

A valid value of the relevant type where the C <strong>Standard</strong> imposes no requirements on which value<br />

is chosen in any instance. An unspecified value cannot be a trap representation [ISO/IEC<br />

9899:2011].<br />

untrusted data<br />

Data originating from outside of a trust boundary [ISO/IEC 11889-1:2009].<br />

valid pointer<br />

Pointer that refers to an element within an array or one past the last element of an array. See invalid<br />

pointer [ISO/IEC TS 17961:2013].<br />

NOTE: For the purposes of this definition, a pointer to an object that is not an element of an array<br />

behaves the same as a pointer to the first element of an array of length one with the type of the object<br />

as its element type. (See C <strong>Standard</strong>, 6.5.8, paragraph 4.)<br />

For the purposes of this definition, an object can be considered to be an array of a certain number<br />

of bytes; that number is the size of the object, as produced by the sizeof operator. (See C <strong>Standard</strong>,<br />

6.3.2.3, paragraph 7.)<br />

validation<br />

Confirmation by examination and provision of objective evidence that the particular requirements<br />

for a specific intended use are fulfilled [IEC 61508-4].<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 508<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


verification<br />

Confirmation by examination and provision of objective evidence that the requirements have been<br />

fulfilled [IEC 61508-4].<br />

vulnerability<br />

Set of conditions that allows an attacker to violate an explicit or implicit security policy [ISO/IEC<br />

TS 17961:2013].<br />

warning message<br />

A diagnostic message generated when source code is encountered that does not prevent an implementation<br />

from translating a translation unit. See diagnostic message and error message.<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 509<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Appendix C: Undefined Behavior<br />

According to the C <strong>Standard</strong>, Annex J, J.2 [ISO/IEC 9899:2011], the behavior of a program is undefined<br />

in the circumstances outlined in the following table. The “Guideline” column in the table<br />

identifies the coding practices that address the specific case of undefined behavior (UB). The descriptions<br />

of undefined behaviors in the “Description” column are direct quotes from the standard.<br />

The parenthesized numbers refer to the subclause of the C <strong>Standard</strong> (C11) that identifies the undefined<br />

behavior.<br />

UB Description Guideline<br />

1 A “shall” or “shall not” requirement that appears outside of a constraint<br />

MSC15-C<br />

is violated (clause 4).<br />

2 A nonempty source file does not end in a new-line character which is<br />

not immediately preceded by a backslash character or ends in a partial<br />

preprocessing token or comment (5.1.1.2).<br />

3 Token concatenation produces a character sequence matching the PRE30-C<br />

syntax of a universal character name (5.1.1.2).<br />

4 A program in a hosted environment does not define a function named<br />

main using one of the specified forms (5.1.2.2.1).<br />

5 The execution of a program contains a data race (5.1.2.4).<br />

6 A character not in the basic source character set is encountered in a<br />

source file, except in an identifier, a character constant, a string literal,<br />

a header name, a comment, or a preprocessing token that is<br />

never converted to a token (5.2.1).<br />

7 An identifier, comment, string literal, character constant, or header<br />

name contains an invalid multibyte character or does not begin and<br />

end in the initial shift state (5.2.1.2).<br />

8 The same identifier has both internal and external linkage in the same DCL36-C<br />

translation unit (6.2.2).<br />

9 An object is referred to outside of its lifetime (6.2.4). DCL21-C,<br />

DCL30-C<br />

10 The value of a pointer to an object whose lifetime has ended is used<br />

(6.2.4).<br />

11 The value of an object with automatic storage duration is used while<br />

it is indeterminate (6.2.4, 6.7.9, 6.8).<br />

12 A trap representation is read by an lvalue expression that does not<br />

have character type (6.2.6.1).<br />

DCL30-C,<br />

EXP33-C<br />

EXP33-C,<br />

MSC22-C<br />

EXP33-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 510<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

13 A trap representation is produced by a side effect that modifies any<br />

part of the object using an lvalue expression that does not have character<br />

type (6.2.6.1).<br />

14 The operands to certain operators are such that they could produce a<br />

negative zero result, but the implementation does not support negative<br />

zeros (6.2.6.2).<br />

15 Two declarations of the same object or function specify types that are<br />

not compatible (6.2.7).<br />

16 A program requires the formation of a composite type from a variable<br />

length array type whose size is specified by an expression that is not<br />

evaluated (6.2.7).<br />

17 Conversion to or from an integer type produces a value outside the<br />

range that can be represented (6.3.1.4).<br />

18 Demotion of one real floating type to another produces a value outside<br />

the range that can be represented (6.3.1.5).<br />

19 An lvalue does not designate an object when evaluated (6.3.2.1).<br />

20 A non-array lvalue with an incomplete type is used in a context that<br />

requires the value of the designated object (6.3.2.1).<br />

21 An lvalue designation an object of automatic storage duration that<br />

could have been declared with the register storage class is used in<br />

a context that requires the value of the designated object, but the object<br />

is uninitialized (6.3.2.1).<br />

22 An lvalue having array type is converted to a pointer to the initial element<br />

of the array, and the array object has register storage class<br />

(6.3.2.1).<br />

23 An attempt is made to use the value of a void expression, or an implicit<br />

or explicit conversion (except to void) is applied to a void expression<br />

(6.3.2.2).<br />

24 Conversion of a pointer to an integer type produces a value outside<br />

the range that can be represented (6.3.2.3).<br />

25 Conversion between two pointer types produces a result that is incorrectly<br />

aligned (6.3.2.3).<br />

26 A pointer is used to call a function whose type is not compatible with<br />

the pointed-to type (6.3.2.3).<br />

27 An unmatched ' or " character is encountered on a logical source line<br />

during tokenization (6.4).<br />

28 A reserved keyword token is used in translation phase 7 or 8 for some<br />

purpose other than as a keyword (6.4.1).<br />

DCL23-C,<br />

DCL40-C<br />

FLP34-C<br />

FLP34-C<br />

INT36-C<br />

EXP36-C<br />

EXP37-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 511<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

29 A universal character name in an identifier does not designate a character<br />

whose encoding falls into one of the specified ranges (6.4.2.1).<br />

30 The initial character of an identifier is a universal character name designating<br />

a digit (6.4.2.1).<br />

31 Two identifiers differ only in nonsignificant characters (6.4.2.1). DCL23-C,<br />

DCL31-C<br />

32 The identifier func{} is explicitly declared (6.4.2.2).<br />

33 The program attempts to modify a string literal (6.4.5). STR30-C<br />

34 The characters ', back-slash, ", /, or /* occur in the sequence between<br />

the < and > delimiters, or the characters ', back-slash, //, or<br />

/* occur in the sequence between the " delimiters, in a header name<br />

preprocessing token (6.4.7).<br />

35 A side effect on a scalar object is unsequenced relative to either a different<br />

side effect on the same scalar object or a value computation using<br />

the value of the same scalar object (6.5).<br />

36 An exceptional condition occurs during the evaluation of an expression<br />

(6.5).<br />

37 An object has its stored value accessed other than by an lvalue of an<br />

allowable type (6.5).<br />

38 For a call to a function without a function prototype in scope, the<br />

number of arguments does not equal the number of parameters<br />

(6.5.2.2).<br />

39 For call to a function without a function prototype in scope where the<br />

function is defined with a function prototype, either the prototype<br />

ends with an ellipsis or the types of the arguments after promotion are<br />

not compatible with the types of the parameters (6.5.2.2).<br />

40 For a call to a function without a function prototype in scope where<br />

the function is not defined with a function prototype, the types of the<br />

arguments after promotion are not compatible with those of the parameters<br />

after promotion (with certain exceptions) (6.5.2.2).<br />

41 A function is defined with a type that is not compatible with the type<br />

(of the expression) pointed to by the expression that denotes the<br />

called function (6.5.2.2).<br />

42 A member of an atomic structure or union is accessed (6.5.2.3).<br />

43 The operand of the unary * operator has an invalid value (6.5.3.2).<br />

44 A pointer is converted to other than an integer or pointer type (6.5.4).<br />

EXP39-C<br />

EXP30-C<br />

INT32-C<br />

DCL40-<br />

C,EXP39-C<br />

EXP37-C<br />

EXP37-C<br />

EXP37-C<br />

DCL40-C,<br />

EXP37-C<br />

45 The value of the second operand of the / or % operator is zero (6.5.5). INT33-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 512<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

46 Addition or subtraction of a pointer into, or just beyond, an array object<br />

and an integer type produces a result that does not point into, or<br />

just beyond, the same array object (6.5.6).<br />

47 Addition or subtraction of a pointer into, or just beyond, an array object<br />

and an integer type produces a result that points just beyond the<br />

array object and is used as the operand of a unary * operator that is<br />

evaluated (6.5.6).<br />

48 Pointers that do not point into, or just beyond, the same array object<br />

are subtracted (6.5.6).<br />

49 An array subscript is out of range, even if an object is apparently accessible<br />

with the given subscript (as in the lvalue expression<br />

a[1][7] given the declaration int a[4][5]) (6.5.6).<br />

50 The result of subtracting two pointers is not representable in an object<br />

of type ptrdiff_t (6.5.6).<br />

51 An expression is shifted by a negative number or by an amount<br />

greater than or equal to the width of the promoted expression (6.5.7).<br />

52 An expression having signed promoted type is left-shifted and either<br />

the value of the expression is negative or the result of shifting would<br />

not be representable in the promoted type (6.5.7).<br />

53 Pointers that do not point to the same aggregate or union (nor just beyond<br />

the same array object) are compared using relational operators<br />

(6.5.8).<br />

54 An object is assigned to an inexactly overlapping object or to an exactly<br />

overlapping object with incompatible type (6.5.16.1).<br />

55 An expression that is required to be an integer constant expression<br />

does not have an integer type; has operands that are not integer constants,<br />

enumeration constants, character constants, sizeof expressions<br />

whose results are integer constants, or immediately-cast floating<br />

constants; or contains casts (outside operands to sizeof operators)<br />

other than conversions of arithmetic types to integer types (6.6).<br />

56 A constant expression in an initializer is not, or does not evaluate to,<br />

one of the following: an arithmetic constant expression, a null pointer<br />

constant, an address constant, or an address constant for an object<br />

type plus or minus an integer constant expression (6.6).<br />

57 An arithmetic constant expression does not have arithmetic type; has<br />

operands that are not integer constants, floating constants, enumeration<br />

constants, character constants, or sizeof expressions; or contains<br />

casts (outside operands to sizeof operators) other than conversions<br />

of arithmetic types to arithmetic types (6.6).<br />

ARR30-C<br />

ARR30-C<br />

ARR36-C<br />

ARR30-C<br />

INT34-C<br />

ARR36-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 513<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

58 The value of an object is accessed by an array-subscript [], memberaccess<br />

. or ->, address &, or indirection * operator or a pointer cast<br />

in creating an address constant (6.6).<br />

59 An identifier for an object is declared with no linkage and the type of<br />

the object is incomplete after its declarator, or after its init-declarator<br />

if it has an initializer (6.7).<br />

60 A function is declared at block scope with an explicit storage-class<br />

specifier other than extern (6.7.1).<br />

61 A structure or union is defined as containing no named members<br />

(6.7.2.1).<br />

62 An attempt is made to access, or generate a pointer to just past, a<br />

flexible array member of a structure when the referenced object provides<br />

no elements for that array (6.7.2.1).<br />

63 When the complete type is needed, an incomplete structure or union<br />

type is not completed in the same scope by another declaration of the<br />

tag that defines the content (6.7.2.3).<br />

64 An attempt is made to modify an object defined with a const-qualified<br />

type through use of an lvalue with non-const-qualified type<br />

(6.7.3).<br />

65 An attempt is made to refer to an object defined with a volatilequalified<br />

type through use of an lvalue with non-volatile-qualified<br />

type (6.7.3).<br />

66 The specification of a function type includes any type qualifiers<br />

(6.7.3).<br />

67 Two qualified types that are required to be compatible do not have<br />

the identically qualified version of a compatible type (6.7.3).<br />

68 An object which has been modified is accessed through a restrictqualified<br />

pointer to a const-qualified type, or through a restrictqualified<br />

pointer and another pointer that are not both based on the<br />

same object (6.7.3.1).<br />

69 A restrict-qualified pointer is assigned a value based on another<br />

restricted pointer whose associated block neither began execution before<br />

the block associated with this pointer, nor ended before the assignment<br />

(6.7.3.1).<br />

70 A function with external linkage is declared with an inline function<br />

specifier, but is not also defined in the same translation unit (6.7.4).<br />

71 A function declared with a _Noreturn function specifier returns to<br />

its caller (6.7.4).<br />

ARR30-C<br />

EXP05-C,<br />

EXP40-C<br />

EXP32-C<br />

EXP43-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 514<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

72 The definition of an object has an alignment specifier and another<br />

declaration of that object has a different alignment specifier (6.7.5).<br />

73 Declarations of an object in different translation units have different<br />

alignment specifiers (6.7.5).<br />

74 Two pointer types that are required to be compatible are not identically<br />

qualified, or are not pointers to compatible types (6.7.6.1).<br />

75 The size expression in an array declaration is not a constant expression<br />

and evaluates at program execution time to a nonpositive value<br />

(6.7.6.2).<br />

76 In a context requiring two array types to be compatible, they do not<br />

have compatible element types, or their size specifiers evaluate to unequal<br />

values (6.7.6.2).<br />

77 A declaration of an array parameter includes the keyword static<br />

within the [ and ] and the corresponding argument does not provide<br />

access to the first element of an array with at least the specified number<br />

of elements (6.7.6.3).<br />

78 A storage-class specifier or type qualifier modifies the keyword void<br />

as a function parameter type list (6.7.6.3).<br />

79 In a context requiring two function types to be compatible, they do<br />

not have compatible return types, or their parameters disagree in use<br />

of the ellipsis terminator or the number and type of parameters (after<br />

default argument promotion, when there is no parameter type list or<br />

when one type is specified by a function definition with an identifier<br />

list) (6.7.6.3).<br />

80 The value of an unnamed member of a structure or union is used<br />

(6.7.9).<br />

81 The initializer for a scalar is neither a single expression nor a single<br />

expression enclosed in braces (6.7.9).<br />

82 The initializer for a structure or union object that has automatic storage<br />

duration is neither an initializer list nor a single expression that<br />

has compatible structure or union type (6.7.9).<br />

83 The initializer for an aggregate or union, other than an array initialized<br />

by a string literal, is not a brace-enclosed list of initializers for its<br />

elements or members (6.7.9).<br />

84 An identifier with external linkage is used, but in the program there<br />

does not exist exactly one external definition for the identifier, or the<br />

identifier is not used and there exist multiple external definitions for<br />

the identifier (6.9).<br />

85 A function definition includes an identifier list, but the types of the<br />

parameters are not declared in a following declaration list (6.9.1).<br />

ARR32-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 515<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

86 An adjusted parameter type in a function definition is not an object<br />

type (6.9.1).<br />

87 A function that accepts a variable number of arguments is defined<br />

without a parameter type list that ends with the ellipsis notation<br />

(6.9.1).<br />

88 The } that terminates a function is reached, and the value of the function<br />

call is used by the caller (6.9.1).<br />

89 An identifier for an object with internal linkage and an incomplete<br />

type is declared with a tentative definition (6.9.2).<br />

90 The token defined is generated during the expansion of a #if or<br />

#elif preprocessing directive, or the use of the defined unary operator<br />

does not match one of the two specified forms prior to macro replacement<br />

(6.10.1).<br />

91 The #include preprocessing directive that results after expansion<br />

does not match one of the two header name forms (6.10.2).<br />

92 The character sequence in an #include preprocessing directive does<br />

not start with a letter (6.10.2).<br />

93 There are sequences of preprocessing tokens within the list of macro<br />

arguments that would otherwise act as preprocessing directives<br />

(6.10.3).<br />

94 The result of the preprocessing operator # is not a valid character<br />

string literal (6.10.3.2).<br />

95 The result of the preprocessing operator ## is not a valid preprocessing<br />

token (6.10.3.3).<br />

96 The #line preprocessing directive that results after expansion does<br />

not match one of the two well-defined forms, or its digit sequence<br />

specifies zero or a number greater than 2147483647 (6.10.4).<br />

97 A non-STDC#pragma preprocessing directive that is documented as<br />

causing translation failure or some other form of undefined behavior<br />

is encountered (6.10.6).<br />

98 A #pragma STDC preprocessing directive does not match one of the<br />

well-defined forms (6.10.6).<br />

99 The name of a predefined macro, or the identifier defined, is the subject<br />

of a #define or #undef preprocessing directive (6.10.8).<br />

100 An attempt is made to copy an object to an overlapping object by use<br />

of a library function, other than as explicitly allowed (e.g., memmove)<br />

(clause 7).<br />

MSC37-C<br />

PRE32-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 516<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

101 A file with the same name as one of the standard headers, not provided<br />

as part of the implementation, is placed in any of the standard<br />

places that are searched for included source files (7.1.2).<br />

102 A header is included within an external declaration or definition<br />

(7.1.2).<br />

103 A function, object, type, or macro that is specified as being declared<br />

or defined by some standard header is used before any header that declares<br />

or defines it is included (7.1.2).<br />

104 A standard header is included while a macro is defined with the same<br />

name as a keyword (7.1.2).<br />

105 The program attempts to declare a library function itself, rather than<br />

via a standard header, but the declaration does not have external linkage<br />

(7.1.2).<br />

106 The program declares or defines a reserved identifier, other than as<br />

allowed by 7.1.4 (7.1.3).<br />

107 The program removes the definition of a macro whose name begins<br />

with an underscore and either an uppercase letter or another underscore<br />

(7.1.3).<br />

108 An argument to a library function has an invalid value or a type not<br />

expected by a function with a variable number of arguments (7.1.4).<br />

109 The pointer passed to a library function array parameter does not<br />

have a value such that all address computations and object accesses<br />

are valid (7.1.4).<br />

110 The macro definition of assert is suppressed in order to access an<br />

actual function (7.2).<br />

111 The argument to the assert macro does not have a scalar type (7.2).<br />

112 The CX_LIMITED_RANGE, FENV_ACCESS, or FP_CONTRACT pragma<br />

is used in any context other than outside all external declarations or<br />

preceding all explicit declarations and statements inside a compound<br />

statement (7.3.4, 7.6.1, 7.12.2).<br />

113 The value of an argument to a character handling function is neither<br />

equal to the value of EOF nor representable as an unsigned char<br />

(7.4).<br />

114 A macro definition of errno is suppressed in order to access an actual<br />

object, or the program defines an identifier with the name errno<br />

(7.5).<br />

115 Part of the program tests floating-point status flags, sets floatingpoint<br />

control modes, or runs under non-default mode settings, but<br />

DCL37-C<br />

ARR30-C,<br />

ARR38-C<br />

MSC38-C<br />

STR37-C<br />

DCL37-C,<br />

MSC38-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 517<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

was translated with the state for the FENV_ACCESS pragma "off"<br />

(7.6.1).<br />

116 The exception-mask argument for one of the functions that provide<br />

access to the floating-point status flags has a nonzero value not obtained<br />

by bitwise OR of the floating-point exception macros (7.6.2).<br />

117 The fesetexceptflag function is used to set floating-point status<br />

flags that were not specified in the call to the fegetexceptflag<br />

function that provided the value of the corresponding fexcept_t object<br />

(7.6.2.4).<br />

118 The argument to fesetenv or feupdateenv is neither an object set<br />

by a call to fegetenv or feholdexcept, nor is it an environment<br />

macro (7.6.4.3, 7.6.4.4).<br />

119 The value of the result of an integer arithmetic or conversion function<br />

cannot be represented (7.8.2.1, 7.8.2.2, 7.8.2.3, 7.8.2.4, 7.22.6.1,<br />

7.22.6.2, 7.22.1).<br />

120 The program modifies the string pointed to by the value returned by<br />

the setlocale function (7.11.1.1).<br />

121 The program modifies the structure pointed to by the value returned<br />

by the localeconv function (7.11.2.1).<br />

122 A macro definition of math_errhandling is suppressed or the program<br />

defines an identifier with the name math_errhandling<br />

(7.12).<br />

123 An argument to a floating-point classification or comparison macro is<br />

not of real floating type (7.12.3, 7.12.14).<br />

124 A macro definition of setjmp is suppressed in order to access an actual<br />

function, or the program defines an external identifier with the<br />

name setjmp (7.13).<br />

125 An invocation of the setjmp macro occurs other than in an allowed<br />

context (7.13.2.1).<br />

126 The longjmp function is invoked to restore a nonexistent environment<br />

(7.13.2.1).<br />

127 After a longjmp, there is an attempt to access the value of an object<br />

of automatic storage class with non-volatile-qualified type, local<br />

to the function containing the invocation of the corresponding setjmp<br />

macro, that was changed between the setjmp invocation and<br />

longjmp call (7.13.2.1).<br />

128 The program specifies an invalid pointer to a signal handler function<br />

(7.14.1.1).<br />

ERR07-C<br />

ENV30-C<br />

ENV30-C<br />

MSC38-C<br />

MSC38-C<br />

MSC22-C<br />

MSC22-C<br />

MSC22-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 518<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

129 A signal handler returns when the signal corresponded to a computational<br />

exception (7.14.1.1).<br />

130 A signal handler called in response to SIGFPE, SIGILL, SIGSEGV, or<br />

any other implementation-defined value corresponding to a computational<br />

exception returns (7.14.1.1).<br />

131 A signal occurs as the result of calling the abort or raise function,<br />

and the signal handler calls the raise function (7.14.1.1).<br />

SIG31-C<br />

SIG35-C<br />

SIG30-C,<br />

SIG31-C<br />

132 A signal occurs other than as the result of calling the abort or raise<br />

function, and the signal handler refers to an object with static or<br />

thread storage duration that is not a lock-free atomic object other than<br />

by assigning a value to an object declared as volatile sig_atomic_t, or<br />

calls any function in the standard library other than the abort function,<br />

the _Exit function, the quick_exit function, or the signal function<br />

(for the same signal number) (7.14.1.1).<br />

133 The value of errno is referred to after a signal occurred other than as<br />

the result of calling the abort or raise function and the corresponding<br />

signal handler obtained a SIG_ERR return from a call to the signal<br />

function (7.14.1.1).<br />

134 A signal is generated by an asynchronous signal handler (7.14.1.1).<br />

135 The signal function is used in a multi-threaded program (7.14.1.1).<br />

136 A function with a variable number of arguments attempts to access its<br />

varying arguments other than through a properly declared and initialized<br />

va_list object, or before the va_start macro is invoked<br />

(7.16, 7.16.1.1, 7.16.1.4).<br />

137 The macro va_arg is invoked using the parameter ap that was<br />

passed to a function that invoked the macro va_arg with the same<br />

parameter (7.16).<br />

138 A macro definition of va_start, va_arg, va_copy, or va_end is<br />

suppressed in order to access an actual function, or the program defines<br />

an external identifier with the name va_copy or va_end<br />

(7.16.1).<br />

139 The va_start or va_copy macro is invoked without a corresponding<br />

invocation of the va_end macro in the same function, or vice<br />

versa (7.16.1, 7.16.1.2, 7.16.1.3, 7.16.1.4).<br />

140 The type parameter to the va_arg macro is not such that a pointer to<br />

an object of that type can be obtained simply by postfixing a *<br />

(7.16.1.1).<br />

SIG31-C<br />

ERR32-C<br />

CON37-C<br />

MSC38-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 519<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

141 The va_arg macro is invoked when there is no actual next argument,<br />

or with a specified type that is not compatible with the promoted type<br />

of the actual next argument, with certain exceptions (7.16.1.1).<br />

142 The va_copy or va_start macro is called to initialize a va_list<br />

that was previously initialized by either macro without an intervening<br />

invocation of the va_end macro for the same va_list (7.16.1.2,<br />

7.16.1.4).<br />

143 The parameter parmN of a va_start macro is declared with the register<br />

storage class, with a function or array type, or with a type that is<br />

not compatible with the type that results after application of the default<br />

argument promotions (7.16.1.4).<br />

144 The member designator parameter of an offsetof macro is an invalid<br />

right operand of the . operator for the type parameter, or designates<br />

a bit-field (7.19).<br />

145 The argument in an instance of one of the integer-constant macros is<br />

not a decimal, octal, or hexadecimal constant, or it has a value that<br />

exceeds the limits for the corresponding type (7.20.4).<br />

146 A byte input/output function is applied to a wide-oriented stream, or a<br />

wide character input/output function is applied to a byte-oriented<br />

stream (7.21.2).<br />

147 Use is made of any portion of a file beyond the most recent wide<br />

character written to a wide-oriented stream (7.21.2).<br />

148 The value of a pointer to a FILE object is used after the associated<br />

file is closed (7.21.3).<br />

149 The stream for the fflush function points to an input stream or to an<br />

update stream in which the most recent operation was input<br />

(7.21.5.2).<br />

150 The string pointed to by the mode argument in a call to the fopen<br />

function does not exactly match one of the specified character sequences<br />

(7.21.5.3).<br />

151 An output operation on an update stream is followed by an input operation<br />

without an intervening call to the fflush function or a file<br />

positioning function, or an input operation on an update stream is followed<br />

by an output operation with an intervening call to a file positioning<br />

function (7.21.5.3).<br />

152 An attempt is made to use the contents of the array that was supplied<br />

in a call to the setvbuf function (7.21.5.6).<br />

153 There are insufficient arguments for the format in a call to one of the<br />

formatted input/output functions, or an argument does not have an appropriate<br />

type (7.21.6.1, 7.21.6.2, 7.29.2.1, 7.29.2.2).<br />

DCL10-C<br />

FIO42-C,<br />

FIO46-C<br />

FIO39-C<br />

FIO47-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 520<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

154 The format in a call to one of the formatted input/output functions or<br />

to the strftime or wcsftime function is not a valid multibyte character<br />

sequence that begins and ends in its initial shift state (7.21.6.1,<br />

7.121.6.2, 7.27.3.5, 7.229.2.1, 7.29.2.2, 7.29.5.1).<br />

155 In a call to one of the formatted output functions, a precision appears<br />

with a conversion specifier other than those described (7.21.6.1,<br />

7.29.2.1).<br />

156 A conversion specification for a formatted output function uses an asterisk<br />

to denote an argument-supplied field width or precision, but the<br />

corresponding argument is not provided (7.21.6.1, 7.29.2.1).<br />

157 A conversion specification for a formatted output function uses a # or<br />

0 flag with a conversion specifier other than those described<br />

(7.21.6.1, 7.29.2.1).<br />

158 A conversion specification for one of the formatted input/output functions<br />

uses a length modifier with a conversion specifier other than<br />

those described (7.21.6.1, 7.21.6.2, 7.29.2.1, 7.29.2.2).<br />

159 An s conversion specifier is encountered by one of the formatted output<br />

functions, and the argument is missing the null terminator (unless<br />

a precision is specified that does not require null termination)<br />

(7.21.6.1, 7.29.2.1).<br />

160 An n conversion specification for one of the formatted input/output<br />

functions includes any flags, an assignment-suppressing character, a<br />

field width, or a precision (7.21.6.1, 7.21.6.2, 7.29.2.1, 7.29.2.2).<br />

161 A % conversion specifier is encountered by one of the formatted input/output<br />

functions, but the complete conversion specification is not<br />

exactly %% (7.21.6.1, 7.21.6.2, 7.29.2.1, 7.29.2.2).<br />

162 An invalid conversion specification is found in the format for one of<br />

the formatted input/output functions, or the strftime or wcsftime<br />

function (7.21.6.1, 7.21.6.2, 7.27.3.5, 7.29.2.1, 7.29.2.2, 7.29.5.1).<br />

163 The number of characters or wide characters transmitted by a formatted<br />

output function (or written to an array, or that would have been<br />

written to an array) is greater than INT_MAX (7.21.6.1, 7.29.2.1).<br />

164 The number of input items assigned by a formatted input function is<br />

greater than INT_MAX (7.21.6.2, 7.29.2.2).<br />

165 The result of a conversion by one of the formatted input functions<br />

cannot be represented in the corresponding object, or the receiving<br />

object does not have an appropriate type (7.21.6.2, 7.29.2.2).<br />

FIO47-C<br />

FIO47-C<br />

FIO47-C<br />

FIO47-C<br />

FIO47-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 521<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

166 A c, s, or [ conversion specifier is encountered by one of the formatted<br />

input functions, and the array pointed to by the corresponding argument<br />

is not large enough to accept the input sequence (and a null<br />

terminator if the conversion specifier is s or [) (7.21.6.2, 7.29.2.2).<br />

167 A c, s, or [ conversion specifier with an l qualifier is encountered by<br />

one of the formatted input functions, but the input is not a valid<br />

multibyte character sequence that begins in the initial shift state<br />

(7.21.6.2, 7.29.2.2).<br />

168 The input item for a %p conversion by one of the formatted input<br />

functions is not a value converted earlier during the same program<br />

execution (7.21.6.2, 7.29.2.2).<br />

169 The vfprintf, vfscanf, vprintf, vscanf, vsnprintf,<br />

vsprintf, vsscanf, vfwprintf, vfwscanf, vswprintf, vswscanf,<br />

vwprintf, or vwscanf function is called with an improperly<br />

initialized va_list argument, or the argument is used (other than in<br />

an invocation of va_end) after the function returns (7.21.6.8,<br />

7.21.6.9, 7.21.6.10, 7.21.6.11, 7.21.6.12, 7.21.6.13, 7.21.6.14,<br />

7.29.2.5, 7.29.2.6, 7.29.2.7, 7.29.2.8, 7.29.2.9, 7.29.2.10).<br />

170 The contents of the array supplied in a call to the fgets, gets, or<br />

fgetws function are used after a read error occurred (7.21.7.2,<br />

7.21.7.7, 7.293.2).<br />

171 The file position indicator for a binary stream is used after a call to<br />

the ungetc function where its value was zero before the call<br />

(7.21.7.11).<br />

172 The file position indicator for a stream is used after an error occurred<br />

during a call to the fread or fwrite function (7.21.8.1, 7.21.8.2).<br />

173 A partial element read by a call to the fread function is used<br />

(7.21.8.1).<br />

174 The fseek function is called for a text stream with a nonzero offset<br />

and either the offset was not returned by a previous successful call to<br />

the ftell function on a stream associated with the same file or<br />

whence is not SEEK_SET (7.21.9.2).<br />

175 The fsetpos function is called to set a position that was not returned<br />

by a previous successful call to the fgetpos function on a stream associated<br />

with the same file (7.21.9.3).<br />

176 A non-null pointer returned by a call to the calloc, malloc, or realloc<br />

function with a zero requested size is used to access an object<br />

(7.22.3).<br />

177 The value of a pointer that refers to space deallocated by a call to the<br />

free or realloc function is used (7.22.3).<br />

FIO40-C<br />

MEM04-C<br />

MEM30-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 522<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

178 The alignment requested of the aligned_alloc function is not<br />

valid or not supported by the implementation, or the size requested is<br />

not an integral multiple of the alignment (7.22.3.1).<br />

179 The pointer argument to the free or realloc function does not<br />

match a pointer earlier returned by calloc, malloc, or realloc, or<br />

the space has been deallocated by a call to free or realloc<br />

(7.22.3.3, 7.22.3.5).<br />

180 The value of the object allocated by the malloc function is used<br />

(7.22.3.4).<br />

181 The values of any bytes in a new object allocated by the realloc<br />

function beyond the size of the old object are used (7.22.3.5).<br />

182 The program calls the exit or quick_exit function more than once, or<br />

calls both functions (7.22.4.4, 7.22.4.7).<br />

183 During the call to a function registered with the atexit or<br />

at_quick_exit function, a call is made to the longjmp function that<br />

would terminate the call to the registered function (7.22.4.4,<br />

7.22.4.7).<br />

184 The string set up by the getenv or strerror function is modified<br />

by the program (7.22.4.6, 7.24.6.2).<br />

185 A signal is raised while the quick_exit function is executing<br />

(7.22.4.7).<br />

186 A command is executed through the system function in a way that is<br />

documented as causing termination or some other form of undefined<br />

behavior (7.22.4.8).<br />

187 A searching or sorting utility function is called with an invalid pointer<br />

argument, even if the number of elements is zero (7.22.5).<br />

188 The comparison function called by a searching or sorting utility function<br />

alters the contents of the array being searched or sorted, or returns<br />

ordering values inconsistently (7.22.5).<br />

189 The array being searched by the bsearch function does not have its<br />

elements in proper order (7.22.5.1).<br />

190 The current conversion state is used by a multibyte/wide character<br />

conversion function after changing the LC_CTYPE category (7.22.7).<br />

191 A string or wide string utility function is instructed to access an array<br />

beyond the end of an object (7.24.1, 7.29.4).<br />

192 A string or wide string utility function is called with an invalid<br />

pointer argument, even if the length is zero (7.24.1, 7.29.4).<br />

193 The contents of the destination array are used after a call to the<br />

strxfrm, strftime, wcsxfrm, or wcsftime function in which the<br />

MEM34-C<br />

EXP33-C<br />

ENV32-<br />

C,ERR04-C<br />

ENV32-C<br />

ENV30-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 523<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


UB Description Guideline<br />

specified length was too small to hold the entire null-terminated result<br />

(7.24.4.5, 7.27.3.5, 7.29.4.4.4, 7.29.5.1).<br />

194 The first argument in the very first call to the strtok or wcstok is a<br />

null pointer (7.24.5.8, 7.29.4.5.7).<br />

195 The type of an argument to a type-generic macro is not compatible<br />

with the type of the corresponding parameter of the selected function<br />

(7.25).<br />

196 A complex argument is supplied for a generic parameter of a type-generic<br />

macro that has no corresponding complex function (7.25).<br />

197 At least one member of the broken-down time passed to asctime contains<br />

a value outside its normal range, or the calculated year exceeds<br />

four digits or is less than the year 1000 (7.27.3.1).<br />

198 The argument corresponding to an s specifier without an l qualifier<br />

in a call to the fwprintf function does not point to a valid multibyte<br />

character sequence that begins in the initial shift state (7.29.2.11).<br />

199 In a call to the wcstok function, the object pointed to by ptr does<br />

not have the value stored by the previous call for the same wide string<br />

(7.29.4.5.7).<br />

200 An mbstate_t object is used inappropriately (7.29.6). EXP33-C<br />

201 The value of an argument of type wint_t to a wide character classification<br />

or case mapping function is neither equal to the value of<br />

WEOF nor representable as a wchar_t (7.30.1).<br />

202 The iswctype function is called using a different LC_CTYPE category<br />

from the one in effect for the call to the wctype function that<br />

returned the description (7.30.2.2.1).<br />

203 The towctrans function is called using a different LC_CTYPE category<br />

from the one in effect for the call to the wctrans function that<br />

returned the description (7.30.3.2.1).<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 524<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


Appendix D: Unspecified Behavior<br />

According to the C <strong>Standard</strong>, Annex J, J.1 [ISO/IEC 9899:2011], the behavior of a program is unspecified<br />

in the circumstances outlined the following table. The descriptions of unspecified behaviors<br />

in the “Description” column are direct quotes from the standard. The parenthesized numbers<br />

refer to the subclause of the C <strong>Standard</strong> (C11) that identifies the unspecified behavior. The<br />

“Guideline” column in the table identifies the coding practices that address the specific case of<br />

unspecified behavior (USB).<br />

USB Description Guideline<br />

1 The manner and timing of static initialization (5.1.2).<br />

2 The termination status returned to the hosted environment if the return<br />

type of main is not compatible with int (5.1.2.2.3).<br />

3 The values of objects that are neither lock-free atomic objects nor of<br />

type volatile sig_atomic_t and the state of the floating-point<br />

environment when the processing of the abstract machine is interrupted<br />

by receipt of a signal (5.1.2.3).<br />

4 The behavior of the display device if a printing character is written<br />

when the active position is at the final position of a line (5.2.2).<br />

5 The behavior of the display device if a backspace character is written<br />

when the active position is at the initial position of a line 5.2.2).<br />

6 The behavior of the display device if a horizontal tab character is<br />

written when the active position is at or past the last defined horizontal<br />

tabulation position (5.2.2).<br />

7 The behavior of the display device if a vertical tab character is written<br />

when the active position is at or past the last defined vertical tabulation<br />

position (5.2.2).<br />

8 How an extended source character that does not correspond to a universal<br />

character name counts toward the significant initial characters<br />

in an external identifier (5.2.4.1).<br />

9 Many aspects of the representations of types (6.2.6).<br />

10 The value of padding bytes when storing values in structures or unions<br />

(6.2.6.1).<br />

11 The values of bytes that correspond to union members other than the<br />

one last stored into (6.2.6.1).<br />

12 The representation used when storing a value in an object that has<br />

more than one object representation for that value (6.2.6.1).<br />

13 The values of any padding bits in integer representations (6.2.6.2).<br />

EXP39-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 525<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


USB Description Guideline<br />

14 Whether certain operators can generate negative zeros and whether a<br />

negative zero becomes a normal zero when stored in an object<br />

(6.2.6.2).<br />

15 Whether two string literals result in distinct arrays (6.4.5).<br />

16 The order in which subexpressions are evaluated and the order in<br />

which side effects take place, except as specified for the function-call<br />

(), &&, ||, ?:, and comma operators (6.5).<br />

17 The order in which the function designator, arguments, and subexpressions<br />

within the arguments are evaluated in a function call<br />

(6.5.2.2).<br />

18 The order of side effects among compound literal initialization list<br />

expressions (6.5.2.5).<br />

19 The order in which the operands of an assignment operator are evaluated<br />

(6.5.16).<br />

20 The alignment of the addressable storage unit allocated to hold a bitfield<br />

(6.7.2.1).<br />

21 Whether a call to an inline function uses the inline definition or the<br />

external definition of the function (6.7.4).<br />

22 Whether or not a size expression is evaluated when it is part of the<br />

operand of a sizeof operator and changing the value of the size expression<br />

would not affect the result of the operator (6.7.6.2).<br />

23 The order in which any side effects occur among the initialization list<br />

expressions in an initializer (6.7.9).<br />

24 The layout of storage for function parameters (6.9.1).<br />

25 When a fully expanded macro replacement list contains a functionlike<br />

macro name as its last preprocessing token and the next preprocessing<br />

token from the source file is a (, and the fully expanded replacement<br />

of that macro ends with the name of the first macro and the<br />

next preprocessing token from the source file is again a (, whether<br />

that is considered a nested replacement (6.10.3).<br />

26 The order in which # and ## operations are evaluated during macro<br />

substitution (6.10.3.2, 6.10.3.3).<br />

27 The state of the floating-point status flags when execution passes<br />

from a part of the program translated with FENV_ACCESS "off" to a<br />

part translated with FENV_ACCESS "on" (7.6.1).<br />

28 The order in which feraiseexcept raises floating-point exceptions,<br />

except as stated in F.8.6 (7.6.2.3).<br />

29 Whether math_errhandling is a macro or an identifier with external<br />

linkage (7.12).<br />

EXP30-C<br />

EXP44-C<br />

DCL37-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 526<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


USB Description Guideline<br />

30 The results of the frexp functions when the specified value is not a<br />

floating-point number (7.12.6.4).<br />

31 The numeric result of the ilogb functions when the correct value is<br />

outside the range of the return type (7.12.6.5, F.10.3.5).<br />

32 The result of rounding when the value is out of range (7.12.9.5,<br />

7.12.9.7, F.10.6.5).<br />

33 The value stored by the remquo functions in the object pointed to by<br />

quo when y is zero (7.12.10.3).<br />

34 Whether a comparison macro argument that is represented in a format<br />

wider than its semantic type is converted to the semantic type<br />

(7.12.14).<br />

35 Whether setjmp is a macro or an identifier with external linkage<br />

(7.13).<br />

36 Whether va_copy and va_end are macros or identifiers with external<br />

linkage (7.16.1).<br />

37 The hexadecimal digit before the decimal point when a non-normalized<br />

floating-point number is printed with an a or A conversion specifier<br />

(7.21.6.1, 7.29.2.1).<br />

38 The value of the file position indicator after a successful call to the<br />

ungetc function for a text stream, or the ungetwc function for any<br />

stream, until all pushed-back characters are read or discarded<br />

(7.21.7.10, 7.29.3.10).<br />

39 The details of the value stored by the fgetpos function (7.21.9.1).<br />

40 The details of the value returned by the ftell function for a text<br />

stream (7.21.9.4).<br />

41 Whether the strtod, strtof, strtold, wcstod, wcstof, and<br />

wcstold functions convert a minus-signed sequence to a negative<br />

number directly or by negating the value resulting from converting<br />

the corresponding unsigned sequence (7.22.1.3, 7.29.4.1.1).<br />

42 The order and contiguity of storage allocated by successive calls to<br />

the calloc, malloc, and realloc functions (7.22.3).<br />

43 The amount of storage allocated by a successful call to the calloc,<br />

malloc, and realloc function when 0 bytes was requested (7.22.3).<br />

44 Whether a call to the atexit function that does not happen before<br />

the exit function is called will succeed (7.22.4.2).<br />

45 Whether a call to the at_quick_exit function that does not happen<br />

before the quick_exit function is called will succeed (7.22.4.3).<br />

46 Which of two elements that compare as equal is matched by the<br />

bsearch function (7.22.5.1).<br />

DCL37-C<br />

DCL37-C<br />

MEM04-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 527<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.


USB Description Guideline<br />

47 The order of two elements that compare as equal in an array sorted by<br />

the qsort function (7.22.5.2).<br />

48 The encoding of the calendar time returned by the time function<br />

(7.27.2.4).<br />

49 The characters stored by the strftime or wcsftime function if any<br />

of the time values being converted is outside the normal range<br />

(7.27.3.5, 7.29.5.1).<br />

50 Whether an encoding error occurs if a wchar_t value that does not<br />

correspond to a member of the extended character set appears in the<br />

format string for a function in 7.29.2 or 7.29.5 and the specified semantics<br />

do not require that value to be processed by wcrtomb<br />

(7.29.1).<br />

51 The conversion state after an encoding error occurs (7.28.1.1,<br />

7.28.1.2, 7.28.1.3, 7.28.1.4, 7.29.6.3.2, 7.29.6.3.3, 7.29.6.4.1,<br />

7.29.6.4.2).<br />

52 The resulting value when the “invalid” floating-point exception is<br />

raised during IEC 60559 floating to integer conversion (F.4).<br />

53 Whether conversion of non-integer IEC 60559 floating values to integer<br />

raises the “inexact” floating-point exception (F.4).<br />

54 Whether or when library functions in raise the “inexact”<br />

floating-point exception in an IEC 60559 conformant implementation<br />

(F.10).<br />

55 Whether or when library functions in raise an undeserved<br />

“underflow” floating-point exception in an IEC 60559 conformant<br />

implementation (F.10).<br />

56 The exponent value stored by frexp for a NaN or infinity (F.10.3.4).<br />

57 The numeric result returned by the lrint, llrint, lround, and<br />

llround functions if the rounded value is outside the range of the return<br />

type (F.10.6.5, F.10.6.7).<br />

58 The sign of one part of the complex result of several math functions<br />

for certain exceptional values in IEC 60559 compatible implementations<br />

(G.6.1.1, G.6.2.2, G.6.2.3, G.6.2.4, G.6.2.5, G.6.2.6, G.6.3.1,<br />

G.6.4.2).<br />

MSC05-C<br />

<strong>SEI</strong> <strong>CERT</strong> C <strong>Coding</strong> <strong>Standard</strong>: Rules for Developing Safe, Reliable, and Secure Systems 528<br />

Software Engineering Institute | Carnegie Mellon University<br />

[DISTRIBUTION STATEMENT A] Approved for public release and unlimited distribution.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!