CERT
Skip to end of metadata
Go to start of metadata

This guideline has not been reviewed recently and may be outdated. Please review it and comment to reflect any newly available information.

C++ does not require programmers to initialize local automatic variables before using them in functions or assignment statements. Local automatic variables can assume unexpected values if they are used before they are initialized.[ISO/IEC 14882-2003], Section 8.5, paragraph 9, says: "... if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value." Such variables are assigned a location on the stack and have a default value corresponding to the value stored at that stack location. Consequently, functions that use uninitialized variables can give rise to unpredictable behavior and provide an avenue of attack.

In most cases, compilers warn about uninitialized variables. Such warnings can be resolved by initializing the variables when possible.

Initializing local automatic variables on declaration helps capture common programming errors, minimizes violations of EXP53-CPP. Do not read uninitialized memory, and eases maintainability because uninitialized variables are easily spotted and caught before they propagate bugs down the program.

Adherence to this guideline will eliminate violations of EXP53-CPP. Do not read uninitialized memory. It will also reduce unnecessary member function calls for class variables.

In cases where it is not possible to comply, the rule EXP53-CPP. Do not read uninitialized memory takes precedence.

Noncompliant Code Example

In this noncompliant code example, var is not initialized to any value and it can potentially hold any value. This greatly increases the risk of using var before initialization and subsequent violations of EXP53-CPP. Do not read uninitialized memory. In code of greater complexity, such risk increases exponentially. Additionally, redundant member function calls are avoided. Consider, for instance, constructing the variable with the default constructor and then assigning a value with the assignment operator. Two member function calls are executed instead of one.

Implementation Details

GCC version 4.3.3 fails to diagnose this error.

Compliant Solution

In the compliant case, var is initialized to 1.

Additionally, programmers are able to limit the possible causes of any unexpected behavior to a narrower scope.

Noncompliant Code Example

In this noncompliant code example, foo1.a is not initialized to any value and it can potentially hold any value. This greatly increases the risk of using foo1.a before initialization and subsequently violating EXP53-CPP. Do not read uninitialized memory. In code of greater complexity, such risk increases exponentially.

Implementation Details

GCC version 4.3.3 fails to diagnose this error.

Compliant Solution

In the compliant case, foo1.a is initialized to 1 via the default constructor.

Exceptions

DCL19-CPP-EX1: It is not possible to initialize const qualified variables that are assigned a value in a try-catch block but are declared outside the try-catch block.

DCL19-CPP-EX2: Variables that must be passed to a function as a reference argument to be initialized do not have to be initialized at declaration.

Automated Detection

HP aC++ version A.06.20 can detect violations of this recommendation:
+Oinitcheck option to check for uninitialized variables
+check=uninit option to check for use of uninitialized variables

IBM XLC++ can initialize automatic variables to a specific value when the -qinitauto flag is used.

Sun C/C++ can initialize local variables when the -xcheck=init_local flag is used.

Klocwork Insight UNINIT.STACK checkers can detect violations of this recommendation with the UNINIT.STACK.MUST and UNINIT.STACK.MIGHT checkers.

 

Tool

Version

Checker

Description

Parasoft C/C++test9.5INIT-03, INIT-04 
Parasoft Insure++  Runtime detection

 PRQA QA-C++

 3.2

4101, 4102, 4206, 4207, 4218,

4219, 4265, 4269, 4270, 4271, 4272

 

Risk Assessment

Allowing uninitialized variables to exist in a program could lead to arbitrary code execution if sufficient precautions are not taken, such as a subsequent violation of EXP53-CPP. Do not read uninitialized memory.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL19-CPP

high

probable

medium

P12

L1

.

Bibliography

[ISO/IEC 14882-1998] Section 8.5 Initializers
[MISRA 2004] Rule 9.1
[MISRA 2008] Rule 8-5-1
[Lockheed Martin 2005] AV Rule 142 All variables shall be initialized before use.
[Henricson 1997] Industrial Strength C++, Chapter 5, rec 5.2 If possible, initialize variables at the point of declaration.


9 Comments

    • The reference to EXP33-CPP should be done in the introduction, rather than Risk Assessment.and Other Languages. (There should be no Other Languages section because this rule does not have a matching analog in C or Java.)
    • Your NCCE currently violates EXP33-CPP. In order for this rule to be considered worthwhile, you need the NCCE to violate this rule while abiding by EXP33-CPP. (I'm not sure you can make a vulnerable NCCE w/o violating EXP33-CPP, as unreferenced uninitialized memory does not constitute a security flaw.)
    • The rule should address comments in the email responses you get wrt this rule from myself and Martin Sebor.

    Additionally, memory allocated by functions such as malloc() or using the new operator, may provide an avenue for buffer overflow based attacks.

    • True but irrelevant, unless you plan on requiring heap data to be initialized in this rule (that seems overly ambitious)
  1. I agree with David that in order for a violation of this guideline to be a security flaw it must also violate some other guideline (such as EXP33-CPP).

    In addition, there are a number of errors in the code examples:

    1. The C++ keyword is throw, not throws. That said, the exception specification is unnecessary (and IMO distracting) for this guideline.
    2. The grammar for exception-specification is throw ( type-id-list opt ) (i.e., the optional type-id-list is enclosed in parentheses, not in curly braces).
    3. The NCCE attempts to assign a value to a const object.

    Finally, an example where observing this guideline would avoid violating EXP33-CPP might look something like this:

    However, a compliant solution doesn't require one to initialize all variables:

    In general, the preferable solution is to use the RAII idiom to avoid having to worry about resource management issues like those above. E.g., like so:

    or even better, like so:

  2. 1. The references at the bottom are all broken; you'll want to fix these.

    2. I think your "Implementation Details" should probably be an "Automated Detection" although it is interesting that you are mentioning tools that go behind detection. MSC07-CPP. Detect and remove dead code is an example of a guideline with an "Automated Detection". You probably want to have similar formatting and link them to the URLs that Martin provided.

    3. In the following sentences:

    This rule complements EXP33-CPP. Do not reference uninitialized memory.
    In cases where it is not possible to comply, the rule EXP33-CPP. Do not reference uninitialized memory takes precedence

    I would say "complements" is definitely the wrong term. I think you want to refer to this as a "recommendation" and not a "rule". I think you need to find a better way to describe how these guidelines are related. I suspect you may be able to say "conformance to this guideline will also eliminate violations of EXP33-CPP. Do not reference uninitialized memory. Then, as Martin states, you need to craft exceptions that prevent this rule from being rejected out of hand:

    I suspect a guideline that requires every auto variable to be initialized when it's declared isn't likely to be widely adopted on C or C++ projects unless exemptions are made that permit programs to avoid doing so unnecessarily.

    Specifying these exceptions is going to be non-trivial, but when done so as to minimize false positives, will likely yield a guideline that's quite close to EXP33-C.

  3. 1. The references at the bottom are all broken; you'll want to fix these.

    2. I think your "Implementation Details" should probably be an "Automated Detection" although it is interesting that you are mentioning tools that go behind detection. MSC07-CPP. Detect and remove dead code is an example of a guideline with an "Automated Detection". You probably want to have similar formatting and link them to the URLs that Martin provided.

    3. In the following sentences:

    This rule complements EXP33-CPP. Do not reference uninitialized memory.
    In cases where it is not possible to comply, the rule EXP33-CPP. Do not reference uninitialized memory takes precedence

    I would say "complements" is definitely the wrong term. I think you want to refer to this as a "recommendation" and not a "rule". I think you need to find a better way to describe how these guidelines are related. I suspect you may be able to say "conformance to this guideline will also eliminate violations of EXP33-CPP. Do not reference uninitialized memory. Then, as Martin states, you need to craft exceptions that prevent this rule from being rejected out of hand:

    I suspect a guideline that requires every auto variable to be initialized when it's declared isn't likely to be widely adopted on C or C++ projects unless exemptions are made that permit programs to avoid doing so unnecessarily.

    Specifying these exceptions is going to be non-trivial, but when done so as to minimize false positives, will likely yield a guideline that's quite close to EXP33-C.

  4. In addition to the above suggestions, I'll add:

    • The Imp. Details section should follow the NCCE, since it is about the NCCE.
    • I disagree with the Risk ASsessment section...please provide some arguments for the values there (or change them.)
  5. Looking at this rule now, it seems underspecified. The NCCE is rather vague, as Foo lacks an assignment operator or any fields. It currently does not exhibit undefined behavior, and does not leave values uninitialized. Leaving a class variable uninitialized always calls the default ctor. Constructors could leave data uninitialized; if the ctor has an initialization list, most compilers will holler if the init list leaves out a field. Also we have OOP37-CPP. Constructor initializers should be ordered correctly.

    The NCCE should be split into 2 NCCEs, one that uses an uninitialized local var that is not a class, and one that has a class whose ctor leaves some field uninitialized.

    1. One other problem...sometimes you have to initialize a variable with a function that may throw an exception. But the variable must be specified outside of the try block (for various reasons). EG:

      This may qualify as an exception to this rule.

      EDIT: I s/Object/int/g; in the code sample. Objects with no explicit initializer always invoke the default constructor, as Martin points out. Primitive types can remain uninitialized, however.

      1. The statement variable = get_object(); is not an initialization: it's an assignment. If Object has a default constructor the declaration of variable is also its initialization, so the guideline isn't violated and an exception is unnecessary.

        This, incidentally, is also why there is nothing wrong with the first non-compliant example. The object foo1 is initialized by the default ctor so there is no risk of causing a violation of EXP33-CPP (unless, of course, the default ctor fails to initialize some of its members; but that would be violation of a different guideline: Initialize data members in the constructor initializer list which might be worth adding).

        This guideline does not apply to objects of class types with user-defined constructors. The examples need to rewritten in terms of some other type (e.g., fundamental or aggregate). Something like:

        With a possible compliant solution being:

        or perhaps even better (n is const which is an improvement but the code is harder to read):

        1. I have (hopefully) addressed the issues raised here.