SEI CERT C Coding Standard
tqcylJ
tqcylJ
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.