01.07.2016 Views

SEI CERT C Coding Standard

tqcylJ

tqcylJ

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<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!