RADE |
C++ Source Checker |
mkCheckSource C++ ChecksTesting source code in the CAA V5 environment |
Technical Article |
AbstractThis article describes the checks relative to C++ rules. This checks are identified by BDON, BDON2, EOLC, SCIS, NWD1, NWD2, UPVA. |
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]
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 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.
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:
- an array pointer is allocated via new and de-allocated via delete [].
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:
- a class is declared in a LocalInterfaces directory (in a module).
- this class contains the keyword ExportedByxxx in its declaration.
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 :
- an expression if(...) is used.
- this expression is not followed by an instruction.
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))
{
...
}
...
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 :
- an object is allocated using new.
- this object is never deleted.
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 object is allocated on the heap via an allocation method or function.
- this object is never deleted.
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.
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:
- an object is passed by value as method or function argument.
- considering the type of the argument, it is estimated sufficiently
valuable (not a basic type, no envelope/letter mechanism, ...) to use a
passage by constant reference instead.
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.
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:
- an ifstream object is opened in output mode
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:
- an ofstream object is opened in input mode
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:
- a call to C function strcpy is make.
- destination and source are declared is the same scope.
- destination variable is a character array and is shorter than the source
string.
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:
- a header file is included in the source file.
- none of the declarations (types, structures, variables, functions, macros)
present in the header file is used.
[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:
- at least one local variable of type T is declared
- type T is not declared in any of the header files directly included in the
file analyzed or in the corresponding declaration file (if the analyzed
file is an implementation file)
- T is not a parent class of a class declared or implemented in the file
analyzed.
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:
- This section must not contain methods returning a list of pointers (or
handlers), each one being allocated (like CATListOfPtr). This is not
supported by the tool.
- Avoid describing the type of the arguments (just specify the number of
arguments with "?").
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.