RADE |
C++ Source Checker |
mkCheckSource Null Pointers Phase 1 ChecksTesting source code in the CAA V5 environment |
Technical Article |
AbstractThis article describes the checks relative to NULL Pointers Part 1. These checks are identified by LCDMNI, LCLVNI, LCDMMN, LCLVMN, LCVMNA, LCLVMNAR, LCVMNAAR, LCLVMNAC, LCVMNAAC. |
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:
These checks must insure that:
(pointer is VALID) <=> (pointer is NOT NULL)
These checks must insure that every pointer is tested against NULL before use.
This article deals only with NULL Pointers Part 1.
See [2] for NULL Pointers Part 2.
[Top]
CSC has the knowledge of every data member of every class. For each Data member of type pointer, CSC checks:
CSC has the knowledge of every local variable. For each Local Variable of type pointer, CSC checks:
CSC has the knowledge of every argument variable of functions or methods. For each Argument Variable of type pointer, CSC checks:
[Top]
LCDMNI stands for LifeCycle: Data Member Not Initialized.
An error of type LCDMNI is reported when:
As the data member is not set, we can not test it against NULL to know if it is valid or not.
The Data Member is not initialized.
Let's take the following class:
class CATTest01 { CATBaseUnknown* _data; CATTest01(); ...; }; |
The following code will report a LCDMNI Error:
CATTest01::CATTest01() { } |
The correct code is:
CATTest01::CATTest01() : _data(NULL) {} |
or:
CATTest01::CATTest01() { _data= NULL; } |
The Data Member is not initialized before use.
Let's take the following class:
class CATTest02 { CATBaseUnknown* _data; CATTest02(); ...; }; |
The following code will report a LCDMNI Error:
CATTest02::CATTest02() { CATBaseUnknown* localVar= _data; ... } |
The correct code is:
CATTest02::CATTest02() { _data= ...; // Retrieve _data CATBaseUnknown* localVar= _data; } |
_data MUST be initialized before use.
The Data Member is not initialized before use.
Let's take the following class:
class CATTest03 { CATBaseUnknown* _data; CATTest01(); ...; }; |
The following code will report a LCDMNI Error:
CATTest03::CATTest03() { functionForUse( _data ); ... } |
The correct code is:
CATTest03::CATTest03() { _data= NULL; // Or retrieve _data: _data= ...; functionForUse( _data ); } |
_data MUST be initialized before use.
LCLVNI stands for LifeCycle: Local Variable Not Initialized.
An error of type LCLVNI is reported when:
As the variable is not set, we can not test it against NULL to know if it is valid or not.
The Local Variable is not initialized before use.
The following code will report a LCLVNI Error:
... CATI2DDitto *ditto; HRESULT hr = myDittoPtr-> QueryInterface(IID_CATI2DDitto, (void **)&ditto); ... |
The correct code is:
... CATI2DDitto *ditto= NULL; HRESULT hr = myDittoPtr-> QueryInterface(IID_CATI2DDitto, (void **)&ditto); ... |
The Local Variable is not initialized before use.
The following code will report a LCLVNI Error:
... CATDocument *aDocument; HRESULT hr = CATDocumentServices::Open (PathDoc, aDocument); ... |
The correct code is:
... CATDocument *aDocument= NULL; HRESULT hr = CATDocumentServices::Open (PathDoc, aDocument); ... |
[Top]
The aim of these checks is to ensure the assignment to NULL of a pointer after C++ specific calls which alter the validity of the pointer.
LCDMMN stands for LifeCycle: Data Member Missing NULL.
An error of type LCDMMN is reported when:
Every data member of type pointer must be set to NULL in destructor (after last use).
The Data Member is not reset in destructor.
Let's take the following class:
class CATTest04 { CATBaseUnknown* _data; CATTest04(); ~CATTest04(); ...; }; |
The following code will report a LCDMMN Error:
CATTest04::~CATTest04() { } |
The correct code is:
CATTest04::CATTest04() { _data= NULL; } |
The Data Member is not reset in destructor after last use.
Let's take the following class:
class CATTest05 { CATBaseUnknown* _data; void check(); CATTest05(); ~CATTest05(); ...; }; |
The following code will report a LCDMMN Error:
void CATTest05::check() { if( _data ) cout << "_data is not null " << endl; } CATTest05::~CATTest05() { _data= NULL; check(); } |
As the method check() uses the data member _data, CSC will see that data member _data is first set to NULL, then used in the destructor.
The correct code is:
void CATTest05::check() { if( _data ) cout << "_data is not null " << endl; } CATTest05::~CATTest05() { check(); _data= NULL; } |
LCLVMN stands for LifeCycle: Local Variable Missing NULL.
An error of type LCLVMN is reported when a local variable is:
If the variable is not set to NULL after delete, we got a non null pointer which is not valid !
The Local Variable is not reset after delete.
The following code will report a LCLVMN Error:
CATDbDriverCol *driverCol=0; ... // use driverCol delete driverCol; CATDbDriverDatabase *driverDB = CATDbDriverDatabase::Create(vendor); driverDB-> CreateCol(driverCol); |
The correct code is:
CATDbDriverCol *driverCol=0; ... // use driverCol delete driverCol; driverCol= NULL; CATDbDriverDatabase *driverDB = CATDbDriverDatabase::Create(vendor); driverDB-> CreateCol(driverCol); |
LCVMNA stands for LifeCycle: Variable Missing Null Assignment.
LCVMNA is for argument variables and data members the equivalent of LCLVMN for
local variables
An error of type LCVMNA is reported when an argument variable or a data member is:
If the variable is not set to NULL after delete, we got a non null pointer which is not valid !
The Data Member is not reset after delete.
Let's take the following class:
class CATTest06 { CATFont* _font; void clean(); ...; }; |
The following code will report a LCVMNA Error:
void CATTest06::clean() { if( _font ) delete _font; } |
The correct code is:
void CATTest06::clean() { if( _font ) { delete _font; _font= NULL; } } |
The argument variable is not reset after delete.
The following code will report a LCVMNA Error:
void delete_dimension(dimension*& dim) { delete(dim); } |
The correct code is:
void delete_dimension(dimension*& dim) { delete(dim); dim= NULL; } |
[Top]
The aim of these checks is to ensure the assignment to NULL of a pointer after CATIA specific calls which alter the validity of the pointer.
LCLVMNAR stands for LifeCycle: Local Variable Missing NULL Assignment after Release. It is a particular case of error LCLVMNAC.
An error of type LCLVMNAR is reported when a local variable is:
If the variable is not set to NULL after a call to Release, we got a non null pointer which is not valid !
The local variable is not reset after Release, the following code will report a LCLVMNAR error:
if (result) { AddScope(result); result->Release(); } |
The correct code is:
if (result) { AddScope(result); result->Release(); result = NULL; } |
The local variable is reused after Release and before assignement to NULL, the following code will report a LCLVMNAR error:
if (_Parent) { _Parent-> Release(); hr = _Parent-> QueryInterface( IID_CATISketchingElement, (void **) &geom ); _Parent = NULL; } |
The correct code is:
if (_Parent) { hr = _Parent-> QueryInterface( IID_CATISketchingElement, (void **) &geom ); _Parent-> Release(); _Parent = NULL; } |
[Top]
LCVMNAAR stands for LifeCycle: Variable Missing Null Assignment After
Release.
LCVMNAAR is for argument variables and data members the equivalent of LCLVMNAR
for local variables, and is a particular case of error LCVMNAAC.
An error of type LCVMNAAR is reported when an argument variable or a data member is:
If the variable is not set to NULL after Release, we got a non null pointer which is not valid !
The data member is not reset after Release.
Let's take the following class:
class CATTest07 { CATBaseUnknown* _data; void clean(); ...; }; |
The following code will report a LCVMNAAR error:
void CATTest07::clean() { if( _data ) _data->Release(); } |
The correct code is:
void CATTest07::clean() { if( _data ) { _data->Release(); _data = NULL; } } |
The argument variable is not reset after delete, the following code will report a LCVMNAAR error:
void delete_sphere(CATSphere*& sphere) { sphere->Release(); } |
The correct code is:
void delete_sphere(CATSphere*& sphere) { sphere->Release; sphere = NULL; } |
[Top]
LCLVMNAC stands for LifeCycle: Local Variable Missing NULL Assignment after Call to delete method.
Some classes must not be deleted via delete or Release but have a specific destruction method. A pointer to an instance of one of these classes (or of an inherited class) have to call the delete method corresponding to its class to be deleted. After the call, the pointer must be set to NULL or to a valid data, in order to preserve equivalence between validity of the pointer and a value not NULL.
The list of each class concerned and its associated delete methods is provided in the setting files, see LifeCycle_DeleteMethods section.
An error of type LCLVMNAC is reported when a local variable:
If the variable is not set to NULL after a call to a delete method, we got a non null pointer which is not valid !
Let's assume that a pointer on a CATRep instance must be deleted using the method Destroy().
The local variable is not reset after call to delete method Destroy() and before use, the following code will report a LCLVMNAC Error:
CATRep * rep = new CATRep(); ... // use of rep rep->Destroy(); CATManipulator* manip = rep->GetManipulator(); |
The correct code is:
CATRep * rep = new CATRep(); ... // use of rep CATManipulator* manip = rep->GetManipulator(); rep->Destroy(); rep = NULL; |
[Top]
LCVMNAAC stands for LifeCycle: Variable Missing Null Assignment After Call to delete method.
LCVMNAAC is for argument variables and data members the equivalent of
LCLVMNAC for local variables.
The list of each class concerned and its associated delete methods is provided
in the setting files, see LifeCycle_DeleteMethods
section.
An error of type LCVMNAAC is reported when an argument variable or a data member:
If the variable is not set to NULL after a call to a delete method, we got a non null pointer which is not valid !
Let's assume that a pointer on a CATRep instance must be deleted using the Destroy method.
Let's take the following class:
class CATTest08 { CATRep* _rep; void clean(); ...; }; |
The data member is not reset after call to delete method Destroy(), the following code will report a LCVMNAAC error:
void CATTest08::clean() { if( _rep ) _rep->Destroy(); } |
The correct code is:
void CATTest08::clean() { if( _rep ) { _rep->Destroy(); _rep = NULL; } } |
The argument variable is not reset after call to delete method Destroy(), the following code will report a LCVMNAAR error:
void delete_rep(CATRep*& rep) { rep->Destroy(); } |
The correct code is:
void delete_rep(CATRep*& rep) { rep->Destroy(); rep = NULL; } |
[Top]
For a more complete description of Setting Files, see [3].
This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists
This section contains a list of Macro like:
#define DELETEMACRO(ptr) if (ptr) {delete(ptr); ptr=NULL;} |
This list is used in particular when a macro of this type is used to reset a Data Member in a destructor. This prevent from generating an invalid LCDMMN error.
[Top]
This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists
This section contains a list of Macro like:
#define NEWMACRO(ptr) ptr= new CL(); |
This list is used in particular when a macro of this type is used to initialize a Data Member in a constructor. This prevent from generating an invalid LCDMNI error.
[Top]
This section is located in: SettingsSet > OptionLists > LifeCycle_OptionLists
This section contains a list of Call. Each Call describes the delete method of a class:
Example 1:
ClassName CATRep MethodOrFunctionSign Destroy
This means that the method Destroy deletes CATRep instances. Thus each CATRep instance must be set to null (or to a valid data) after a call to Destroy.
[Top]
All checks included in Pointers Null Part 1 insure that no dangling pointer will be present at runtime.
[Top]
[1] | CAA V5 C++ Coding Rules |
[2] | Null Pointers Part 2 Checks |
[3] | Setting Files |
[Top] |
Version: 1 [May 2001] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.