Finding Uninitialized variables

The compiler has the ability to find possible or actual uninitializedlocal variables. This feature uses the compiler optimizer data flow for accurateanalysis. Everything the compiler finds is technically uninitialized, from a pointof view, however related program logic may affect this.

Lets explain that last point with some examples. The examplesare in Modula-2 but are understandable to Ada and Pascal programmers.

PROCEDURE it(foo : BOOLEAN);

VAR

    test : CARDINAL;

BEGIN

    IF foo THEN

        test := 2;

    END;

 

    dummy := test + 2; (* test is uninitialized atthis point *)

END it;

In this example test is uninitialized at the assignment to dummy.If foo is always true the test is always initialized. The compiler will detect theabove example as uninitialized.

PROCEDURE it(foo : BOOLEAN);

VAR

    test : CARDINAL;

BEGIN

    IF foo THEN

        test := 2;

    END;

 

    IF foo THEN

        dummy := test + 2; (* test is uninitializedat this point? *)

    END;

END it;

    

In this modification of the first example, test is still technically uninitialized, because there are two paths that can be taken from the first IF statement and in one of those test was not initialized, therefore on exit from the IF, test is considered uninitialized, however you and I know that foo is a guard variable protecting access to test. The compiler currently does not analyze the relational logic expressions for invariance. This means that the compiler does not look at the two IF expressions and notice that they are the same expression and the IF expression is invariant (not altered) in between the first and second instance, and therefore the variable test is really not uninitialized at the assignment to dummy. We call this logically initialized. If the value of foo were altered between the two IF statements the variable would be uninitialized.

One more quick example.

PROCEDURE it(top : CARDINAL);

VAR

    i : CARDINAL;

    test : CARDINAL;

BEGIN

    i := 1;

    WHILE i <= top DO

        test := i;

        i := i + 1;

    END;

 

    test := test + 1; (* test is technically uninitializedhere *)

END it;

In this example the loop does not have compile time known bounds,therefore the loop will execute 0 or more times. The variable test is initializedin the middle of the loop, therefore one of the two possible flows through that loop,the one where it never executes, does not have test as initialized.

In summary, all variables marked as possibly uninitialized arejust that, possibly, and require you to take a closer look and see if the variableis logically initialized.

If you wish the compiler to not check a specific local variablefor initialization, when Uninitialized checking is turned on, then you can use thefollowing directives.

Modula-2

VAR

    <*/PUSH/NOCHECK:U*>

    dontCheck : CARDINAL;

    <*/POP*>

Ada95

    Pragma Directive("/PUSH/NOCHECK:U");

    dontCheck : Integer;

    Pragma Directive("/POP");

How is a variable considered initialized. There are three ways.

Modula-2

VAR

    i : CARDINAL = 23; (* 1 *)

BEGIN

    i := 23; (* 2 *)

    PassToVarParam(i); (* 3 *)

Ada95

    i : Integer := 23; (* 1 *)

Begin

    i := 23; (* 2 *)

    PassToInOutOrOutParam(i); (* 3 *)

Modula-2. Passing a variable to a VAR parameter is a way to initializea variable, but there is a possible ambiguity here. We assume the VAR parameter willoutput into our variable, but does it also expect initialized input. We do not know,and therefore the compiler assumes that a VAR parameter does not expect initializeddata in the variable when passed. This can put a bit of a damper on your dreams ofstamping out uninitialized variables. We have added some extended syntax to the Modula-2VAR parameter syntax, to inform the compiler exactly what the parameter expects.These are

PROCEDURE it(VAR INOUT index : CARDINAL);

 

PROCEDURE it(VAR OUT index : CARDINAL);

The qualifiers INOUT and OUT have no effect except to informthe compiler of behavior of the parameter for uninitialized variable checking. OUTis not necessary, as that is the assumed default for VAR but you may want to placeit there for documentation purposes.

Modula-2 Note: If you are concerned about ISO syntax compatibilityand do not want to use INOUT or OUT, well it would only take you about 30 minutesto write a program that stripped or commented out the INOUT and OUT from a sourcefile, if you absolutely had to have ISO syntax. The bottom line is that if you wantuninitialized checking to work to its fullest they are probably necessary to catchthem all.

Ada95 does not have the problem the Modula-2 VAR parameter hassince Ada95 has specific in out and out parameters.

All Modula-2 value, and Ada95 in, parameter types expect initializeddata to be passed.

What happens with pointers and assignments.

Modula-2

ptr^ := 23;

Ada95

ptr.all := 23;

In this example ptr is not being initialized, and the variableptr must have been initialized even though it is on the left hand side of an assignmentstatement. The pointed to memory location is what is being initialized in the abovestatement.

Modula-2

foo(ADR(SomeVariable));

Ada95

foo(SomeVariable'address);

In this case the compiler does not check SomeVariable for initialization.The reason is that the compiler does not know what the procedure is going to do withthe address, thus it assumes the safe option which eliminates an incorrect uninitializedreport.