Gimpel Software
  Order        Patches        Discussion Forum        Blog 
Contact      Site Map       
   Home
   Bug of the Month
   Products
   Order
   Support
   Company
   Links
   Interactive Demo

Possibly Uninitialized

This discussion deals with messages 644, 645 ("may not have been initialized"), 771, 772 ("conceivably not initialized"), 530 ("not initialized"), and 1401 - 1403 ("member ... not initialized"). These messages refer to auto variables and data members while in constructors.

For example, given the code

         if( a ) b = 6;
         else c = b;
         a = c;

assume that neither b nor c were previously initialized. PC-lint/FlexeLint reports that b is not initialized (when its value is assigned to c) and that c may not have been initialized (when its value is assigned to a).

In earlier versions (and in conventional lint's) a single unintelligent sweep is taken which would regard b and c as having been initialized prior to use.

while loops and for loops are not quite the same as if statements. Consider, for example, the following code:

          while ( n-- )
              {
              b = 6;
                .
                .
                .
              }
          c = b;

assuming that b had not been initialized earlier, we report that b is "conceivably not initialized" when assigned to c and give a lighter Informational message. The reason for distinguishing this case from the earlier one is that it could be that the programmer knows the body of the loop is always taken at least once. By contrast, in the earlier case involving if statements, the programmer would be hard-pressed to say that the if condition is always taken, for that would imply, at the least, some redundant code which could be eliminated.

The switch is more like an if than a while. For example,

         switch ( k )
              {
         case 1:  b = 2; break;
         case 2:  b = 3;
                  /* Fall Through */
         case 3:  a = 4; break;
         default:  error();
              }
         c = b;

Although b has been assigned a value in two different places, there are paths that might result in b not being initialized. Thus, when b is assigned to c a possibly-uninitialized message is obtained. To fix things up you could assign a default value to b before the switch. This quiets lint but then you lose the initialization detection in the event of subsequent modifications. A better approach may be to fix up the case's for which b has not been assigned a value. We will show this below.

If the invocation of error() is one of those instances which "can't occur but I'll report it anyway," then you should let PC-lint/FlexeLint know that this section of code is not reachable. If error() does not return, it should be marked as not returning by using the option

          -function(exit,error)

This transfers the special property of the exit function to error. Alternatively, you may mark the return point as unreachable as shown in the following fixed up example:

          switch ( k )
               {
          case 1:  b = 2; break;
          case 2:
          case 3:  b = 3; a = 4; break;
          default:  error();
                    /*lint -unreachable */
               }
          c = b;

Don't make the mistake of placing the -unreachable directive before the call to error() as this property is not transmitted across the call. If there is a break after the call, make sure the directive is placed before the break. Code after a break, is never considered reachable, so the directive placed after the break would have no effect.

Another way to get the "not initialized" message is to pass a pointer variable to free (or to some function like free -- see Function Mimicry. For example:

          if( n ) free( p );
              .
              .
              .
          p->value = 3;

will result in p being considered as possibly not initialized at the point of access.

Forward goto's are supported in the sense that the initialization state of the goto is merged with that of the label. Thus, if b is not yet initialized, the code:

          if ( a ) goto label;
          b = 0;
          label: c = b;

will receive a possibly-uninitialized message when b is assigned to c. However, backward goto's, since they do not reduce the initialization state, are ignored.

When the checking for possibly uninitialized variables is first applied to a large mature project, there will be a small number of false hits. Experience indicates that they usually involve code that is not especially well structured or may involve some variation of the following construct:

          if( x )  initialize y
             .
             .
             .
          if( x )  use y

For these cases simply add an initializer to the declaration for y or use the option -esym(644,y).

Data members are considered to be initially uninitialized in constructors. For example:

          class X
              {
              // Warnings 1401 and 1402
              X() { if(n) n = 3; }
              int  n;
              int m;
              };

results in the message 1402 that n is not initialized when it is accessed and message 1401 that m has not been initialized by the constructor. Calling a member function (that is not const) changes things:

          class X
              {
              // the call to f() inhibits initialization warnings
              X() { f(); if( n )  n = 3; }
              void f();
              int n;
              int m;
              };

If X::f() was const or if some non member function were called instead, no assumptions about initialization would be made:

          class X
              {
              // Warnings 1401 and 1402 are issued
              X() { g(); if( n ) n = 3; }
              void g() const;
              int n;
              int m;
              };

Home | Contact | Order

PC-lint and FlexeLint are trademarks of Gimpel Software LLC
Copyright © 2015, Gimpel Software LLC, All rights reserved.