RADE

C++ Source Checker

mkCheckSource Null Pointers Phase 2 Checks

Testing source code in the CAA V5 environment
Technical Article

Abstract

This article describes the checks relative to NULL Pointers Part 2. These checks are identified by LCDMMCBU, LCLVMCBU, LCAVMCBU, LCDMMCBU2, LCLVMCBU2, LCAVMCBU2.


Problematic

Managing pointers Lifecycle is not as easy as it seems to be[1]. How difficult can it be to debug an invalid pointer or an assert due to a NULL pointer.

To prevent these errors, two different types of checks are made by CSC:

This article deals only with NULL Pointers Part 2.
See [2] for NULL Pointers Part 1.

[Top]

Checks

Principle

LC*MCBU

In these checks, every variable (instance of class) of type pointer is followed. Each time a method (member function of the class) is called on the variable, CSC checks if the call is done in a safe branch of code against nullity of the pointer. If it is not, an error is reported. If CSC can not statically determine if the branch of code is safe, an error is reported.

Methods and functions in LifeCycle_SafeMethodsForMCBU cannot return a null pointer.

 

LC*MCBU2

These checks are a subpart of the LC*MCBU ones. In these checks, each time a method is called on a variable of type pointer, if the variable was previously assigned via a function declared in an external framework (not the current framework), and if the pointer may be null at this time, an error is reported. 
Pointers of type in LifeCycle_IgnoredClassesForMCBU2 are ignored.

These checks insure that the inter-framework interactions  won't generate any runtime abort.

If the LifeCycle_UntrustableForMCBU2 list is not empty, the function must:

The default LifeCycle_UntrustableForMCBU2 section is empty: all the calls to a function declared in an external framework are analyzed, except calls of "safe" methods.

 

[Top]

LCLVMCBU

LCLVMCBU stands for LifeCycle: Local Variable Missing Check Before Use.

An error of type LCLVMCBU is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, leading to the abort of the program.

Example LCLVCMBU-1

The local variable edgeCurve is not tested before use.

The following code will report a LCLVMCBU error:

...
CATEdgeCurve* edgeCurve = NULL;
vertices[vindex]->GetParamOnEdgeCurve(startEdge, edgeCurve, crvParam, side);
edgeCurve-> Eval(crvParam, CATCrvEvalCommand::EvalFirstDerivative, NULL, &edgeTgt);
...

The correct code is:

...
CATEdgeCurve* edgeCurve = NULL;
vertices[vindex]->GetParamOnEdgeCurve(startEdge, edgeCurve, crvParam, side);
if( edgeCurve ) 
{
  edgeCurve-> Eval(crvParam, CATCrvEvalCommand::EvalFirstDerivative, NULL, &edgeTgt);
  ...
}
...

LCDMMCBU

LCDMMCBU2 stands for LifeCycle: Data Member Missing Check Before Use.

An error of type LCDMMCBU is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, implying the abort of the program.

Example LCDMMCBU-1

The data member _pHole is not tested before use.

Let's take the following class:

class CATPrtCreateHoleCom
{
  ...
  CATINewHole* _pHole;
  HRESULT CreateHole(void*);
  ...;
};

The following code will report a LCDMMCBU error:

...
HRESULT CATPrtCreateHoleCom::CreateHole (void *)
{
  ...
  CATISpecObject_var hSpecLimit;
  _pHole-> GetLimit(hSpecLimit);
  _pHole->Release();
  _pHole= NULL;
  ... // Use hSpecLimit
}
...

The correct code is:

...
HRESULT CATPrtCreateHoleCom::CreateHole (void *)
{
  ...
  CATISpecObject_var hHole= ...; // Retrieve hHole
  CATISpecObject_var hSpecLimit;
  if( _pHole )
  {
    _pHole-> GetLimit(hSpecLimit);
    _pHole->Release();
    _pHole= NULL;
  }
  ... // Use hSpecLimit
}
...

LCAVMCBU

LCAVMCBU stands for LifeCycle: Argument Variable Missing Check Before Use.

An error of type LCAVMCBU is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, implying the abort of the program.

Example LCAVCMBU-1

The argument variable iEdgeList is not tested before use.

The following code will report a LCAVMCBU error:

long CATTopBasicTools::GetTangentDirection(..., CATLISTP(CATEdge) *iEdgeList ...)
{
  if ( iEdgeList-> Size() == 1) 
  { 
     ...
  }
  ...
}

The correct code is:

long CATTopBasicTools::GetTangentDirection(..., CATLISTP(CATEdge) *iEdgeList ...)
{
  if (! iEdgeList) return 0; // for example
  if ( iEdgeList-> Size() == 1) 
  { 
     ...
  }
  ...
}

[Top]

LCLVMCBU2

LCLVMCBU2 stands for LifeCycle: Local Variable Missing Check Before Use type 2.

An error of type LCLVMCBU2 is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, leading to the abort of the program.

Example LCLVCMBU2-1

The local variable is not tested.

The following code will report a LCLVMCBU2 Error:

...
CATFcaElementIParamsExt* element= ...; // Retrieve element
if( element ) 
{
  CATIParmPublisher * ipDescendants = NULL;
  element->QueryInterface( CATIParmPublisher::ClassId(), (void**) &ipDescendants );
  CATListValCATISpecObject_var ihSpec_parameters;
  ipDescendants-> GetAllChildren(CATIAParameter::ClassName(), ihSpec_parameters);
  ipDescendants-> Release();
  ipDescendants= NULL;
  ...
}
...

The correct code is:

...
CATFcaElementIParamsExt* element= ...; // Retrieve element
if( element ) 
{
  CATIParmPublisher * ipDescendants = NULL;
  HRESULT hr= element->QueryInterface( CATIParmPublisher::ClassId(), (void**) &ipDescendants );
  if( SUCCEEDED( hr ) ) 
  {
    CATListValCATISpecObject_var ihSpec_parameters;
    ipDescendants-> GetAllChildren(CATIAParameter::ClassName(), ihSpec_parameters);
    ipDescendants-> Release();
    ipDescendants= NULL;
  }
  ...
}
...

LCDMMCBU2

LCDMMCBU2 stands for LifeCycle: Data Member Missing Check Before Use type 2.

An error of type LCDMMCBU2 is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, implying the abort of the program.

Example LCDMMCBU2-1

The data member is not tested.

Let's take the following class:

class CATPrtCreateHoleCom
{
  ...
  CATINewHole* _pHole;
  HRESULT CreateHole(void*);
  ...;
};

The following code will report a LCDMMCBU2 Error:

...
HRESULT CATPrtCreateHoleCom::CreateHole (void *)
{
  ...
  CATISpecObject_var hHole= ...; // Retrieve hHole
  hHole-> QueryInterface(CATINewHole::ClassId(), (void **)&_pHole);
  CATISpecObject_var hSpecLimit;
  _pHole-> GetLimit(hSpecLimit);
  _pHole->Release();
  _pHole= NULL;
  ... // Use hSpecLimit
}
...

The correct code is:

...
HRESULT CATPrtCreateHoleCom::CreateHole (void *)
{
  ...
  CATISpecObject_var hHole= ...; // Retrieve hHole
  HRESULT hr= hHole-> QueryInterface(CATINewHole::ClassId(), (void **)&_pHole);
  CATISpecObject_var hSpecLimit;
  if( SUCCEEDED( hr ) )
  {
    _pHole-> GetLimit(hSpecLimit);
    _pHole->Release();
    _pHole= NULL;
  }
  ... // Use hSpecLimit
}
...

LCAVMCBU2

LCAVMCBU2 stands for LifeCycle: Argument Variable Missing Check Before Use type 2.

An error of type LCAVMCBU2 is reported when:

If the assigning method returned a null pointer, a null pointer read will occur at runtime, implying the abort of the program.

Example LCAVCMBU2-1

The argument variable is not tested.

The following code will report a LCAVMCBU2 Error:

...
HRESULT CATSPPPhysicalActivityFlowMgt::AddControlInput(CATIPcsProductIO*& oCIO, const CATBaseUnknown_var & iItem)
{ 
  HRESULT rc= E_FAIL;
  CATISpecObject* pCISO =... ; // Retrieve pCISO
  if ( pCISO ) 
  { 
    rc = pCISO-> QueryInterface(IID_CATIPcsProductIO,(void**)&oCIO); 
    oCIO -> SetItem(iItem);
  } 
  return rc; 
}
...

The correct code is:

...
HRESULT CATSPPPhysicalActivityFlowMgt::AddControlInput(CATIPcsProductIO*& oCIO, const CATBaseUnknown_var & iItem)
{ 
  HRESULT rc= E_FAIL;
  CATISpecObject* pCISO =... ; // Retrieve pCISO
  if ( pCISO ) 
  { 
    rc = pCISO-> QueryInterface(IID_CATIPcsProductIO,(void**)&oCIO); 
    if( SUCCEEDED( rc ) ) 
    {
      oCIO -> SetItem(iItem);
    }
  } 
  return rc; 
}
....

[Top]

Relative sections in setting files

For a more complete description of Setting Files, see [3].

LifeCycle_IgnoredClassesForMCBU2

This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists

This section contains a list of ClassName. Every instance of class contained in this list will be excluded from all checks of type Null Pointers Part 2.

Be careful:

Example:

ClassName CATDialog

This means that no instance of class CATDialog (or any inherited class) will generate an error of type Null Pointers Part 2.

 

LifeCycle_UntrustableForMCBU2

This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists

This section contains a list of Call. Each Call describes a method or function which can return a null pointer:

ClassName
The name of the class (no ClassName means it is a function)
MethodOrFunctionSign
The signature of the function or method

Be careful:

Example 1:

ClassName            CATBaseUnknown
MethodOrFunctionSign QueryInterface

This means that the method QueryInterface of the class CATBaseUnknown can return a null pointer.

 

LifeCycle_SafeMethodsForMCBU

This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists

This section contains a list of CallDeclaration. Each Call describes a method or function which cannot return a null pointer:

FrameworkName
The name of the framework in which the method is declared
ClassName
The name of the class (no ClassName means it is a function)
MethodOrFunctionSign
The signature of the function or method

Example 1:

FrameworkName        System
ClassName            CATBaseUnknown
MethodOrFunctionSign GetImpl

This means that the method GetImpl of the class CATBaseUnknown defined in framework System never returns a null pointer.

[Top]


In Short

All checks included in Pointers Null Part 2 insure that no null pointer read will occur at runtime.

[Top]


References

[1] CAA V5 C++ Coding Rules
[2] Null Pointers Part 2 Checks
[3] Setting Files
[Top]

History

Version: 1 [May 2001] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.