RADE

C++ Source Checker

mkCheckSource C++ Checks

Testing source code in the CAA V5 environment
Technical Article

Abstract

This article describes the checks relative to C++ rules. This checks are identified by BDON, BDON2, EOLC, SCIS, NWD1, NWD2, UPVA.


Problematic

Some C++ errors are checked by CSC, like the allocation of memory with an API, and the de-allocation of this memory with another API, or allocation on the heap without de-allocation, or use of passage by value whereas passage by reference is more effective [1].

[Top]

Checks

Principle

BDON / BDON2:
CSC follows all pointers, noting for each of them every allocation via new or new[] and every de-allocation via delete or delete[]. When a bad allocation/de-allocation couple is detected, CSC reports an error.

EOLC:
A class declared in a LocalInterfaces directory of a module can not be used outside of this module, so it is useless to declare it as "__dllspec(dllexport)". Don't forget that this will generate a (little) bigger object file. When CSC detects an exported class in a header file located in a LocalInterfaces directory of a module, an error is reported.

SCIS:
A "if(...)" expression not followed by an instruction is, most of the time, an error.

NWD1 / NWD2:
An object is allocated on the heap directly with a new, or via an allocation method and is never deleted.

UPVA:
An object of complex type is passed by value in method or function argument, that gives bad performances (use of the copy constructor ...). Passage by constant reference is far more effective.

IOS1 / IOS2:
CSC checks that ofstream objects are not opened in input mode (IOS1 error) or ifstream objects in output mode (IOS2 error). Inconsistency can lead to errors with some operating systems.

BVSS:
For each call to strcpy function, which copy a source string into a destination string, CSC checks that the destination string is longer than the source. An error causes an overflow and thus memory corruption whose origin can be difficult to recognize.

UINC:
When a source file includes a header file whereas there is no use of any declaration contained in it.

MINC:
Indirect header modification without common build level can cause build error. Indeed, when a source uses resources without including the header file where the declaration of the resources is located, a build error occurs. Unless if the inclusion is indirect, i.e. there is an inclusion path starting from the source file to the header file needed.  If the inclusion path is broken, i.e. one of the files in the path stops including the following file of the path, build process fails.

For example, let’s assume following inclusion path:

If code #include “2.h” is deleted in 1.h file, development A still compiles, whereas compilation error occurs in file B.cpp in Development B.

 If the modification happens in a different workspace, the error can appear only in an upper level, possibly only in the highest one. A build error in those levels leads to a useless loss of time in release and development process.

The objective of this check is to provide a mean to anticipate these problems of indirect inclusion of header file, and then to react earlier, at developer level.

[Top]

BDON

BDON stands for Bad Delete On New.

An error of type BDON is reported when :

Forgetting to delete the pointer as an array will prevent from calling the destructors of every element of the array, thus probably leading to memory leaks.

Example BDON-1

The following code will report a BDON error:

...
CATNode * nodes = NULL;
int nbnodes= ...;
nodes = new CATNode [nbnodes];
...
if( nodes ) delete nodes;
...

To correct the error, use the correct de-allocation routine:

...
CATNode * nodes = NULL;
int nbnodes= ...;
nodes = new CATNode [nbnodes];
...
if( nodes ) delete [] nodes;
...

[Top]

BDON2

BDON2 stands for Bad Delete On New type 2.

An error of type BDON2 is reported when:

Example BDON2-1

The following code will report a BDON2 error:

...
CATNode * nodes = NULL;
int nbnodes= ...;
nodes = new CATNode();

if( nodes ) delete [] nodes;
...

To correct the error, use the correct de-allocation routine:

...
CATNode * nodes = NULL;
int nbnodes= ...;
nodes = new CATNode();

if( nodes ) delete nodes;
...

[Top]

EOLC

EOLC stands for Export Of Local Class.

An error of type EOLC is reported when:

Example EOLC-1

Let's assume that CATSpecCheckCmd.h is located in the directory LocalInterfaces of the module CATCheckServices.m (MyFramework/CATCheckServices.m/LocalInterfaces/CATSpecCheckCmd.h). If the declaration of the class is as the following, a EOLC error will be reported:

class ExportedByCATCheckServices CATSpecCheckCmd : public CATCommand 
{ 
  ...
};

To correct the error, don't use the keyword ExportedByxxx (it is useless here since the class is local):

class CATSpecCheckCmd : public CATCommand 
{ 
  ...
};

[Top]

SCIS

SCIS stands for SuspiCious If in Source.

An error of type SCIS is reported when :

Example SCIS-1

The following code will report a SCIS error:

...
HRESULT hr= product-> QueryInterface(iIID, (void **)&path);
if (SUCCEEDED(hr)); 
{ 
  ...
}
...

To correct the error, remove the semicolon which is a bad programming pattern in this case.

...
HRESULT hr= product-> QueryInterface(iIID, (void **)&path);
if (SUCCEEDED(hr))
{ 
  ...
}
...

Example SCIS-2

Invalids SCIS are generated when an "if (..)" expression is preceded by a macro not ended by a semicolon.

The following code will report an invalid SCIS error. The parser will not understand correctly the macro.

...
MACRO_USE("Hello")
if (elem1 == NULL_var) 
{
  ...
}
...

To correct the error, add a semicolon after the use of the macro (this as not effect for the code, and will correct the error):

...
...
MACRO_USE("Hello");
if (elem1 == NULL_var) 
{
  ...
}
...

[Top]

NWD1

NWD1 stands for New Without Delete 1.

An error of type NWD1 is reported when :

Example NWD1-1

The variable myCATBase is allocated with new and it is never deleted, the following code will report a NWD1 error:

{
  CATBaseUnnown* myCATBase = new CATBaseUnknown();
  ... // use of myCATBase
}

The correct code is:

{
  CATBaseUnnown* myCATBase = new CATBaseUnknown();
  ... // use of myCATBase
  delete myCATBase;
}

[Top]

NWD2

NWD2 stands for New without Delete 2.

An error of type NWD2 is reported when:

An allocation method (or function) is a method (or a function) returning a pointer (directly or as out/in-out argument) which will have to be deleted after last use. The list of the allocation methods and functions is provided in the setting files, see MemoryManagement_NewMethods section.

Example NWD2-1

Let's take the following function CATCreateTopLayDown and assume that it is referenced as an allocation function:

CATLayDownOperator* CATCreateTopLayDown(
       CATGeoFactory* iFactory, CATTopData* iData, CATBody* iBodyToLayDown, CATBody* iBodySupport){
  CATLayDownOperator * volatile iLayDownOp = NULL;
  ...
  iLayDownOp = new CATLayDownOperator(iFactory,iData,iBodyToLayDown,iBodySupport); 
  ...
  return iLayDownOp ;
}

The following code will report a NWD2 error, as the variable TestLay is allocated via CATCreateTopLayDown and never deleted:

{ 
  CATLayDownOperator * TestLay = NULL;
  TestLay = CATCreateTopLayDown (iFacto, CurData, iToTest, iSupport);
  if (TestLay != NULL){
    TestLay->Run(); 
  } 
}

The correct code is:

{ 
  CATLayDownOperator * volatile TestLay = NULL;
  TestLay = CATCreateTopLayDown (iFacto, CurData, iToTest, iSupport);
  if (TestLay != NULL){
    TestLay->Run(); 
    delete TestLay;
  } 
}

[Top]

UPVA

UPVA stands for ineffective Use of Passage by Value in method or function Argument.

Using passage by value can be really costly for object of complex type (or for object lists), particularly because of the calls to the copy constructor. Using passage by constant reference can then perform the same behavior with better performances.

A warning of type UPVA is reported when:

It is possible to indicate in the setting files classes for which passage by reference instead of passage by value is not required. Therefore no UPVA warning will be reported for an argument of this type passed by value. The section concerned of the setting files is the EffectiveCopyClass section.

Example UPVA-1

Let's assume that the method IsCurveReferencedByWire has the following signature:

void IsCurveReferencedByWire( CATCurve * Curve, const CATCrvParam iPrmOnECrv, CATEdge *& oEdgeSupport, 
  CATCrvParam & oPrmOnEdge, int i);

The argument iPrmOnECrv of complex type CATCrvParam, is passed by constant value, therefore the code will report an UPVA warning.
The correct signature is :

void IsCurveReferencedByWire( CATCurve * Curve, const CATCrvParam &  iPrmOnECrv, CATEdge *& oEdgeSupport, 
  CATCrvParam & oPrmOnEdge, int i);

[Top]

IOS1

IOS1 is set for Bad Use Of Input Stream.

An error of type IOS1 is reported when:

Example IOS1-1

The following code will report an IOS1 error:

ifstream dumpFile ; 
dumpFile.open(filePathString.CastToCharPtr(), ios::out);

The correct code is:

ofstream dumpFile ; 
dumpFile.open(filePathString.CastToCharPtr(), ios::out);

[Top]

IOS2

IOS2 is set for Bad Use Of Output Stream.

An error of type IOS2 is reported when:

Example IOS2-1

The following code will report an IOS2 error:

ofstream dumpFile ; 
dumpFile.open(filePathString.CastToCharPtr(), ios::in);

The correct code is:

ifstream dumpFile ; 
dumpFile.open(filePathString.CastToCharPtr(), ios::in);

[Top]

BVSS

BVSS stands for Bad Variable Size for strcpy

An error of type BVSS is reported when:

Example BVSS-1

The following code will report an BVSS error:

char hello [3];
strcpy(hello, "hello");

The correct code is:

char hello [6];
strcpy(hello, "hello");

[Top]

UINC

UINC stands for Useless INClude.

Including a header file is expensive in compilation time, as it implies to expand the included file but also all the files includes by this one, directly or not.

An error of type UINC is reported when:

[Top]

MINC

MINC stands for Missing INClude.

The check lists the type declarations needed in current source file, and reports those that are not included directly in the source file. At the moment, a type declaration is considered as needed in a source file if there is at least one local variable of this type (or a derived type) declared in one of the function or method implemented in the file.

However, as an implementation file must include the corresponding declaration file, and as the owners of the both file are usually the same, it is not demanded to include a header file needed in implementation file if the corresponding declaration file already includes it. This means that if the source file implements a class declared in another file – usually a header file, files included in the header file do not have to be included in the implementation source file.

Moreover, in a file declaring or implementing a class, no error is generated on parent class types.

To sum-up, an error of type MINC is reported when:

A particular case is set for types CATListOfInt, CATListOfFloat, CATListOfDouble, CATListOfCATString and CATListOfCATUnicodeString. These types are declared as typedefs in header file CATCollec.h. However, the files CATListOfInt.h, CATListOfFloat.h, CATListOfDouble.h, CATListOfCATString.h and CATListOfCATUnicodeString.h include CATCollec.h and are frequently included to have access to these types declarations. For readability reasons, and to limit useless error occurrences, including these files instead of CATCollec.h is not reported as an error.

Limitations

Invalid MINC errors reported in source file can be filtered. Then, the filtered error will no more be reported.

Mechanism of MINC checker implies that if a type declaration is not found or not understand by the tool, using this type will generate MINC errors.

Macro expansion can lead to such cases. Indeed, for performance reasons, macro expansion is not automatic in CSC tool (see [2]). Nevertheless, if needed, it is possible to declare in the settings file the macros which must be expanded. Then, the tool may generate different results whereas a macro is expanded or not by the tool. Here are two different cases:

First case
Type of a local variable declared in a macro body will be said as needed in each file containing this macro, if the macro is declared in CSC settings to be expanded.
Let’s assume the following code example:

Expected behavior would be that no error MINC be reported for file A.cpp. But if the macro THROW_ERROR is expanded by the tool, the variable declaration Error* e  = new Error(msg) is seen in file A.cpp and an error MINC is then reported for Error type. If the macro is not expanded, no error will be reported.
Furthermore, suppression of directive ‘#include “Error.h” ’ in file 1.h will not provoke the generation of a MINC error.

Second case
Let’s assume the following code example:

Expected behavior would be that an error MINC be reported: declaration of CATString type is not included in A.cpp, whereas it is used.
This will happen only if the tool expands MACRO. Otherwise, no error will be reported.

[Top]

Relative sections in setting files

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

MemoryManagement_NewMethods

This section is located in: SettingsSet > OptionLists > MemoryManagement_OptionLists

This section contains a list of CallWithSpecificArg. Each CallWithSpecificArg describes a method or a function returning a pointer (directly or as out/in-out argument) which will have to be deleted after last use:

ClassName
The name of the class (no ClassName means that it is a function)
MethodOrFunctionSign
The signature of the method or function
SpecificArg
The number of the argument which is allocated (0 refers to the method's result)

Be careful:

Example 1:

SpecificArg          1
ClassName            myClass
MethodOrFunctionSign myClassAllocationMethod(?)

This means that the method myClassAllocationMethod with 1 argument of the class myClass (or any inheriting class) makes an allocation by new on its first and only argument.

Example 2:

SpecificArg          0
ClassName            
MethodOrFunctionSign myClassAllocationFunction

This means that the the function myClassAllocationFunction (no matter the number of arguments) makes an allocation by new on its returned pointer.

[Top]

EffectiveCopyClass

This section is located in: SettingsSet > OptionLists > Various_OptionLists

This section contains a list of ClassName. Each ClassName describes a name of class for which UPVA warnings will not be reported.

Example:

ClassName  CATString

This means that arguments of type CATString can be passed by value without generating any UPVA warnings.

[Top]


In Short

C++ Source Checker can easily and quickly point some C++ simple rules, improving performance or preventing some memory leaks.

[Top]


References

[1] CAA V5 C++ Coding Rules
[2] Inside the Parser
[3] Setting Files
[Top]

History

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

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