SlideShare a Scribd company logo
1 of 21
Download to read offline
Handling False Positives in PVS-Studio and 
CppCat 
Author: Andrey Karpov 
Date: 20.06.2014 
It occurred to me recently to reanalyze the Newton Game Dynamics physics engine. The project's code 
is very high-quality, so there were almost no genuine bugs detected, but I did get a few dozens of false 
positives. Seems like there's nothing to write about, doesn't it? Well, I thought I should write about how 
to handle false positives and how to avoid them. I found the Newton Game Dynamics project a good 
example to demonstrate that on. 
Project analysis 
The number of diagnostic messages the PVS-Studio analyzer generated on this project is as follows: 
• 48 first-level messages; 
• 79 second-level messages; 
• 261 third-level messages (off by default). 
All of these refer to the general analysis set of diagnostic rules (GA). 
So, it makes total 127 warnings that need to be examined. The CppCat analyzer generates just as many 
messages. Further in the article, I won't distinguish between PVS-Studio and CppCat. In general, both 
provide identical false positive suppression mechanisms. PVS-Studio does have a bit more of them, but 
it doesn't affect the whole picture much. 
Note. To learn about the differences between the functional capabilities of PVS-Studio and CppCat, 
follow this link. 
It took me three hours odd to write down all the necessary samples for the article and get rid of all the 
warnings. I think it would have taken me not more than an hour if I had not had to write down the 
examples. It suggests that the difficulty of fighting against false positives is exaggerated. It's true that 
they hinder and distract you; it's true that large projects contain piles of false positives. But 
nevertheless, it's not difficult at all to get rid of them. 
The result is: CppCat generates 0 warnings; so does PVS-Studio. Well, we could turn on the third-level or 
64-bit diagnostics of course, but they are not as interesting. First of all, you need to eliminate those 
warnings the analyzer draws your attention to as most crucial ones. And that is already a large step 
toward higher quality of your code. It is what you should start with. If you turn on all the diagnostics at
once, you won't feel strong and patient enough to go through all of them. By the way, it's a main 
mistake of novice programmers. Remember that "more" doesn't mean "better". 
Analysis report review 
The PVS-Studio and CppCat analyzers don't group diagnostic messages and don't sort them. You don't 
need this when you use them regularly: if a tool detects 2 or 3 bugs in new code, there is nothing to 
group and sort there, while implementing this feature would only complicate the interface. 
When using the tool for the first time, you can sort messages by diagnostic number. It is done by clicking 
on the header of the column with diagnostic code. We decided not to implement it as an automatic 
feature. Warnings are displayed in the same order as files are being analyzed, which allows you to start 
viewing messages without having to wait for the analysis to finish. If we chose to automatically sort 
messages while the analysis is running, they would "jump" all over the table and you won't be able to 
handle them until the analysis is over. 
Thus, sorting by message type (diagnostic number) is most useful at the first stages. And this is what I 
will do. It will allow me to quickly find false positives of one type and eliminate them, thus significantly 
simplifying the work and reducing the time of initial setting up. 
Handling diagnostic messages 
If any of the false positive suppression methods don't seem clear enough, see the corresponding section 
in the documentation: 
• For PVS-Studio - Suppression of false alarms. 
• For CppCat - the documentation coming with the distribution package. 
Warnings No. 1, No. 2 
void 
dgWorldDynamicUpdate::CalculateJointsVelocParallelKernel (....) 
{ 
.... 
dgVector velocStep2 (velocStep.DotProduct4(velocStep)); 
dgVector omegaStep2 (omegaStep.DotProduct4(omegaStep)); 
dgVector test ((velocStep2 > speedFreeze2) | 
(omegaStep2 > omegaStep2)); 
.... 
} 
Diagnostic message: V501 There are identical sub-expressions to the left and to the right of the '>' 
operator: omegaStep2 > omegaStep2 dgworlddynamicsparallelsolver.cpp 546 
The "omegaStep2 > omegaStep2" expression looks suspicious. I cannot say for sure if there is a genuine 
error here or not. Because this comparison can also be found in another file, I guess it's not a bug but 
the programmer's conscious intention. 
Let's assume it's not an error. I have marked these two fragments with a special comment: 
dgVector test ((velocStep2 > speedFreeze2) |
(omegaStep2 > omegaStep2)); //-V501 
From now on, the V501 warning will not be generated for these fragments. 
Warning No. 3 
dgInt32 
dgWorld::CalculatePolySoupToHullContactsDescrete(....) const 
{ 
.... 
dgAssert (dgAbsf(polygon.m_normal % polygon.m_normal - 
dgFloat32 (1.0f)) < dgFloat32 (1.0e-4f)); 
.... 
} 
Diagnostic message: V501 There are identical sub-expressions to the left and to the right of the '%' 
operator: polygon.m_normal % polygon.m_normal dgnarrowphasecollision.cpp 1921 
The analyzer is both right and wrong about this code fragment. On the one hand, the 
"polygon.m_normal % polygon.m_normal" expression is very suspicious indeed. On the other hand, the 
analyzer just can't figure out that this is a test to check the '%' operator implemented in a class. So the 
code is actually correct. Let's help the analyzer by adding a comment: 
dgAssert (dgAbsf(polygon.m_normal % polygon.m_normal - //-V501 
dgFloat32 (1.0f)) < dgFloat32 (1.0e-4f)); 
Warning No. 4 
static void PopupateTextureCacheNode (dScene* const scene) 
{ 
.... 
if (!(info->IsType(dSceneCacheInfo::GetRttiType()) || 
info->IsType(dSceneCacheInfo::GetRttiType()))) { 
.... 
} 
Diagnostic message: V501 There are identical sub-expressions 'info- 
>IsType(dSceneCacheInfo::GetRttiType())' to the left and to the right of the '||' operator. dscene.cpp 
125 
One and the same condition is checked twice. Suppose the second check is redundant. To get rid of the 
false warning, I fixed the code in the following way: 
if (!(info->IsType(dSceneCacheInfo::GetRttiType()))) { 
Warning No. 5 
dFloat dScene::RayCast (....) const 
{
.... 
dFloat den = 1.0f / 
((globalP1 - globalP0) % (globalP1 - globalP0)); //-V501 
.... 
} 
Diagnostic message: V501 There are identical sub-expressions '(globalP1 - globalP0)' to the left and to 
the right of the '%' operator. dscene.cpp 1280 
The variables globalP0 and globalP1 are instances of the 'dVector' class. Because of that, this code 
makes sense and the analyzer's worry is all for nothing. Let's mark the code with the comment: 
dFloat den = 1.0f / 
((globalP1 - globalP0) % (globalP1 - globalP0)); //-V501 
Although the analyzer is wrong, this code still can't be called neat. I suggest implementing special 
functions or something else for such cases. 
Warnings No. 6 - No. 15 
dgInt32 dgCollisionCompound::CalculateContactsToCompound ( 
...., dgCollisionParamProxy& proxy) const 
{ 
.... 
dgCollisionInstance childInstance 
(*subShape, subShape->GetChildShape()); 
.... 
proxy.m_referenceCollision = &childInstance; 
.... 
m_world->CalculateConvexToConvexContacts(proxy); 
.... 
} 
Diagnostic message: V506 Pointer to local variable 'childInstance' is stored outside the scope of this 
variable. Such a pointer will become invalid. dgcollisioncompound.cpp 1815 
The function receives a reference to an object of the 'dgCollisionParamProxy' type. A pointer to a local 
variable is written into this object, and the analyzer warns that it is potentially dangerous. After leaving 
the function, this pointer can't be used because the local variable it points to will be destroyed by then. 
There is no error in this particular case. The pointer is used only while the variable exists. 
I don't feel like using comments to suppress such warnings. You see, there are 9 more of them, all of the 
same kind. 
So let's do it another way. All the lines these false positives are generated on contain a variable named 
'proxy'. We can write one single comment to suppress all these warnings at once:
//-V:proxy:506 
It should be added into some file that gets included into all the other files. In our case, the file 
"dgPhysicsStdafx.h" will do best. 
From now on, the V506 warning won't be displayed for any lines containing the word 'proxy'. This 
mechanism was initially implemented to suppress warnings in macros. But it doesn't actually matter if a 
word serves as a name for a macro or some other entity (a variable, function, class, etc.). The principle 
behind it is simple: if a string contains a specified substring, the corresponding warning is not displayed. 
Warning No. 16 
The following sample is a lengthy one. There's nothing of much interest about it, so you may skip it. 
We have a vector class: 
class dgVector 
{ 
.... 
union { 
__m128 m_type; 
__m128i m_typeInt; 
dgFloat32 m_f[4]; 
struct { 
dgFloat32 m_x; 
dgFloat32 m_y; 
dgFloat32 m_z; 
dgFloat32 m_w; 
}; 
struct { 
dgInt32 m_ix; 
dgInt32 m_iy; 
dgInt32 m_iz; 
dgInt32 m_iw; 
}; 
}; 
.... 
}; 
And we have the following piece of code where vector members are filled with values by the memcpy() 
function: 
DG_INLINE dgMatrix::dgMatrix (const dgFloat32* const array)
{ 
memcpy (&m_front.m_x, array, sizeof (dgMatrix)) ; 
} 
Diagnostic message: V512 A call of the 'memcpy' function will lead to overflow of the buffer '& 
m_front.m_x'. dgmatrix.h 118 
The analyzer doesn't like that more bytes are written into the variable of the 'dgFloat32' type than it 
actually occupies. Far from neat, this practice, however, works well and is widely used. The function is 
actually filling with values the variables m_x, m_y, m_z, and so on. 
I was not attentive enough for the first time and just fixed the code in the following way: 
memcpy(m_front.m_f, array, sizeof(dgMatrix)); 
I thought that only one vector was copied, while the size of the 'm_f' array is just the same as that of the 
vector. 
But at the next launch, the analyzer drew my attention to the code once again. There were actually 4 
vectors to be copied, not one. And it is 4 vectors that the 'dgMatrix' class contains: 
class dgMatrix 
{ 
.... 
dgVector m_front; 
dgVector m_up; 
dgVector m_right; 
dgVector m_posit; 
.... 
} 
I don't know how to make this code neat and short, so I decided to leave it all as it had been before and 
just added the comment: 
memcpy (&m_front.m_x, array, sizeof (dgMatrix)) ; //-V512 
Warnings No. 17, No. 18 
void dgWorldDynamicUpdate::UpdateDynamics(dgFloat32 timestep) 
{ 
dgWorld* const world = (dgWorld*) this; 
dgUnsigned32 updateTime = world->m_getPerformanceCount(); 
m_bodies = 0; 
m_joints = 0; 
m_islands = 0;
m_markLru = 0; 
world->m_dynamicsLru = world->m_dynamicsLru + DG_BODY_LRU_STEP; 
m_markLru = world->m_dynamicsLru; 
.... 
} 
Diagnostic message: V519 The 'm_markLru' variable is assigned values twice successively. Perhaps this is 
a mistake. Check lines: 91, 94. dgworlddynamicupdate.cpp 94 
The 'm_markLru' variable is first initialized by 0 and then 'world->m_dynamicsLru' is written into it. 
There is no error here. To get rid of the warning, I removed the variable initialization by zero. 
Just in the same way I fixed one more code fragment. The corresponding diagnostic message: 
V519 The 'm_posit' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 
1310, 1313. customvehiclecontrollermanager.cpp 1313 
Warnings No. 19, No. 20 
dgFloat32 dgCollisionConvexPolygon::GetBoxMinRadius () const 
{ 
return m_faceClipSize; 
} 
dgFloat32 dgCollisionConvexPolygon::GetBoxMaxRadius () const 
{ 
return m_faceClipSize; 
} 
Diagnostic message: V524 It is odd that the body of 'GetBoxMaxRadius' function is fully equivalent to 
the body of 'GetBoxMinRadius' function. dgcollisionconvexpolygon.cpp 88 
Two functions whose names contain the words 'Min' and 'Max' are implemented in the same way. The 
analyzer finds it suspicious. But everything is OK here. To eliminate the false positive, I implemented one 
function through the other: 
dgFloat32 dgCollisionConvexPolygon::GetBoxMaxRadius () const 
{ 
return GetBoxMinRadius(); 
} 
In the same way I handled the functions GetBoxMaxRadius/GetBoxMaxRadius implemented in the 
'dgCollisionScene' class. 
Warning No. 21
dgInt32 AddFilterFace (dgUnsigned32 count, dgInt32* const pool) 
{ 
.... 
for (dgUnsigned32 i = 0; i < count; i ++) { 
for (dgUnsigned32 j = i + 1; j < count; j ++) { 
if (pool[j] == pool[i]) 
{ 
for (i = j; i < count - 1; i ++) { 
pool[i] = pool[i + 1]; 
} 
count --; 
i = count; 
reduction = true; 
break; 
} 
} 
} 
.... 
} 
Diagnostic message: V535 The variable 'i' is being used for this loop and for the outer loop. Check lines: 
105, 108. dgpolygonsoupbuilder.cpp 108 
We have two loops here. One of them uses the variable 'i' as a counter; the other, the variable 'j'. Inside 
these loops, one more loop is sometimes run. It uses the variable 'i' as a counter, too. The analyzer 
doesn't like it, though there is no error here. 
When an internal loop is executed, external loops are stopped: 
• the loop organized by the 'j' variable is stopped by the 'break' operator; 
• the loop organized by the 'i' variable is stopped through the assignment "i = count". 
The analyzer failed to figure out these nuances. The fragment above is a fine example of code that 
works but smells. 
I used commenting to eliminate the false positive: 
for (i = j; i < count - 1; i ++) { //-V535 
Warnings No. 22 - No. 25 
DG_INLINE dgMatrix::dgMatrix (const dgVector& front) 
{ 
....
m_right = m_right.Scale3 (dgRsqrt (m_right % m_right)); 
m_up = m_right * m_front; 
.... 
} 
Diagnostic message: V537 Consider reviewing the correctness of 'm_right' item's usage. dgmatrix.h 143 
The analyzer generates the V537 warning when it comes across a suspicious mixture of variables whose 
names contain the words "right", "left", "front", and the like. This diagnostic proved unsuccessful for this 
project as the analyzer generated 4 warnings on absolutely safe code. 
In that case, we can completely turn this diagnostic off in PVS-Studio's settings. 
In CppCat, you can't turn off single diagnostics, so we have to use an alternative method. All the lines 
that triggered the false positives contain the word "right". I added the following comment into the file 
"dgStdafx.h": 
//-V:right:537 
Warning No. 26 
Notice the comment. 
int pthread_delay_np (struct timespec *interval) 
{ 
.... 
/* 
* Most compilers will issue a warning 'comparison always 0' 
* because the variable type is unsigned, 
* but we need to keep this 
* for some reason I can't recall now. 
*/ 
if (0 > (wait_time = secs_in_millisecs + millisecs)) 
{ 
return EINVAL; 
} 
.... 
} 
Diagnostic message: V547 Expression is always false. Unsigned type value is never < 0. 
pthread_delay_np.c 119 
The comment tells us that it's not a bug, but the programmer's conscious intention. Well, in that case 
we only have to suppress the warning by a comment: 
if (0 > (wait_time = secs_in_millisecs + millisecs)) //-V547
Warning No. 27 
typedef unsigned long long dgUnsigned64; 
dgUnsigned64 m_mantissa[DG_GOOGOL_SIZE]; 
dgGoogol::dgGoogol(dgFloat64 value) 
:m_sign(0) 
,m_exponent(0) 
{ 
.... 
m_mantissa[0] = (dgInt64 (dgFloat64 ( 
dgUnsigned64(1)<<62) * mantissa)); 
// it looks like GCC have problems with this 
dgAssert (m_mantissa[0] >= 0); 
.... 
} 
Diagnostic message: V547 Expression 'm_mantissa[0] >= 0' is always true. Unsigned type value is always 
>= 0. dggoogol.cpp 55 
The analyzer shares GCC's opinion that something is wrong with this code (see the comment in the 
code). 
The check "dgAssert(m_mantissa[0] >= 0)" makes no sense: an unsigned variable is always equal to or 
larger than zero. 'dgAssert' doesn't actually check anything. 
Programmers tend to be lazy. They would rather write a comment than spend some time to investigate 
an issue and fix a mistake. 
I fixed the code so that 'dgAssert' executed a correct check. For this purpose, I had to add a temporary 
signed variable: 
dgInt64 integerMantissa = (dgInt64(dgFloat64( 
dgUnsigned64(1) << 62) * mantissa)); 
dgAssert(integerMantissa >= 0); 
m_mantissa[0] = integerMantissa; 
Warnings No. 28 - No. 31 
void dgRedBackNode::RemoveFixup (....) 
{
.... 
if (!ptr) { 
return; 
} 
.... 
ptr->SetColor(RED) ; 
ptr->RotateLeft (head); 
tmp = ptr->m_right; 
if (!ptr || !tmp) { 
return; 
} 
.... 
} 
Diagnostic message: V560 A part of conditional expression is always false: !ptr. dgtree.cpp 215 
The '!ptr' expression is always false. The reason is that the 'ptr' pointer has already been checked for 
being null before. If it was found to be null, the function would be left. 
The second check looks even sillier because of the pointer being dereferenced before it: "tmp = ptr- 
>m_right;". 
I eliminated the false positive by removing the second meaningless check. The code now looks like this: 
if (!ptr) { 
return; 
} 
.... 
tmp = ptr->m_right; 
if (!tmp) { 
return; 
} 
.... 
In the same way I fixed 3 other code fragments. 
By the way, this code could additionally trigger the V595 warning. I felt too lazy to check it for sure, but 
if we miss a couple of warnings in the end of the article, be aware that it will be just because of that. 
Warnings No. 32, No. 33 
DG_INLINE bool dgBody::IsCollidable() const;
void dgBroadPhase::AddPair (dgBody* const body0, dgBody* const body1, 
const dgVector& timestep2, dgInt32 threadID) 
{ 
.... 
bool kinematicBodyEquilibrium = 
(((body0->IsRTTIType(dgBody::m_kinematicBodyRTTI) ? 
true : false) & body0->IsCollidable()) | 
((body1->IsRTTIType(dgBody::m_kinematicBodyRTTI) ? 
true : false) & body1->IsCollidable())) ? false : true; 
.... 
} 
Diagnostic message: V564 The '&' operator is applied to bool type value. You've probably forgotten to 
include parentheses or intended to use the '&&' operator. dgbroadphase.cpp 921 
This code smells. I don't think I understand why the programmer would need such a complicated and 
obscure check. I rewrote it, and the code became a bit shorter and more readable. Besides, I got rid of 
the false warning. 
bool kinematicBodyEquilibrium = 
!((body0->IsRTTIType(dgBody::m_kinematicBodyRTTI) && 
body0->IsCollidable()) || 
(body1->IsRTTIType(dgBody::m_kinematicBodyRTTI) && 
body1->IsCollidable())); 
There was one more V564 warning, and I simplified the corresponding code fragment too: 
V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or 
intended to use the '&&' operator. dgbroadphase.cpp 922 
Warnings No. 34 - No. 37 
class dgAIWorld: public dgAIAgentGraph { .... }; 
typedef struct NewtonAIWorld{} NewtonAIWorld; 
NewtonAIWorld* NewtonAICreate () 
{ 
TRACE_FUNCTION(__FUNCTION__); 
dgMemoryAllocator* const allocator = new dgMemoryAllocator(); 
NewtonAIWorld* const ai = (NewtonAIWorld*) 
new (allocator) dgAIWorld (allocator);
return ai; 
} 
Diagnostic message: V572 It is odd that the object which was created using 'new' operator is 
immediately casted to another type. newtonai.cpp 40 
That's a pretty strange way to store objects: creating an object of the 'dgAIWorld' class and casting it 
explicitly to the ' NewtonAIWorld' type. I didn't feel like figuring out why it had been done - there must 
have been some reason; I simply suppressed this warning by a comment in this and 3 other functions. 
Warning No. 38 
void dgCollisionCompound::EndAddRemove () 
{ 
.... 
if (node->m_type == m_node) { 
list.Append(node); 
} 
if (node->m_type == m_node) { 
stack.Append(node->m_right); 
stack.Append(node->m_left); 
} 
.... 
} 
Diagnostic message: V581 The conditional expressions of the 'if' operators situated alongside each other 
are identical. Check lines: 952, 956. dgcollisioncompound.cpp 956 
The analyzer doesn't like one and the same condition being checked twice on end. Perhaps there is 
some typo here. What if this code was meant to look like this: 
if (node->m_type == m_node) { 
.... 
} 
if (node->m_type == m_FOO) { 
.... 
} 
However, that code sample is alright. To get rid of the false positive, we should fix the code. I don't think 
I will violate the program execution logic by leaving only one check: 
if (node->m_type == m_node) { 
list.Append(node); 
stack.Append(node->m_right);
stack.Append(node->m_left); 
} 
Warning No. 39 
void dSceneGraph::AddEdge (....) 
{ 
.... 
if ((!parentLink && !childLink)) { 
.... 
} 
Diagnostic message: V592 The expression was enclosed by parentheses twice: '((!parentLink 
&&!childLink))'. One pair of parentheses is unnecessary or misprint is present. dscenegraph.cpp 209 
It's OK, just redundant parentheses. I removed them: 
if (!parentLink && !childLink) { 
Warnings No. 40 - No. 44 
dgVector dgCollisionCylinder::SupportVertex (....) const 
{ 
dgAssert (dgAbsf ((dir % dir - dgFloat32 (1.0f))) < 
dgFloat32 (1.0e-3f)); 
.... 
} 
Diagnostic message: V592 The expression was enclosed by parentheses twice: '((dir % dir - 
dgFloat32(1.0f)))'. One pair of parentheses is unnecessary or misprint is present. dgcollisioncylinder.cpp 
202 
It's alright, just redundant parentheses. I removed them so that the analyzer didn't worry: 
dgAssert (dgAbsf (dir % dir - dgFloat32 (1.0f)) < 
dgFloat32 (1.0e-3f)); 
This line was replicated to 4 other code fragments through the Copy-Paste method. I fixed those too. 
Warnings No. 45 - No. 65 
void 
ptw32_throw (DWORD exception) 
{ 
.... 
ptw32_thread_t * sp = 
(ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);
sp->state = PThreadStateExiting; 
if (exception != PTW32_EPS_CANCEL && 
exception != PTW32_EPS_EXIT) 
{ 
exit (1); 
} 
.... 
if (NULL == sp || sp->implicit) 
.... 
} 
Diagnostic message: V595 The 'sp' pointer was utilized before it was verified against nullptr. Check lines: 
77, 85. ptw32_throw.c 77 
The V595 diagnostic works in the following way. The analyzer considers the code suspicious if a pointer 
is first dereferenced and then checked for being null. There are certain nuances and exceptions for rule, 
but the general principle is just like I said. 
Here we have just such a case: the 'sp' variable is first dereferenced in the expression "sp->state" and 
then is checked for being null. 
The analyzer has detected 20 more fragments like that. In each particular case, we should act 
differently: in some fragments I placed the check before the dereferencing operation and in some other 
fragments I simply removed it. 
Note 
False V595 warnings are very often triggered by macros of the following pattern: 
#define FREE(p) { if (p) free(p); } 
In this particular case, the analyzer will figure out the programmer's intention and keep silent. But in 
general, the following code pattern may trigger false positives: 
p->foo(); 
FREE(p); 
In these cases, I recommend that you throw macros away completely. The FREE() macro shown above is 
absolutely meaningless and even harmful. 
Firstly, you don't have to check the pointer for being null. The free() function handles null pointers 
correctly. The same is true for the 'delete' operator. That's why the FREE() macro is not needed - at all. 
Secondly, it is dangerous. If we extract pointers from an array, it may cause an error. For example: 
FREE(ArrayOfPtr[i++]) - the first pointer will be checked, and the next one will be freed. 
Warning No. 66 
void dgCollidingPairCollector::Init ()
{ 
dgWorld* const world = (dgWorld*) this; 
// need to expand teh buffer is needed 
world->m_pairMemoryBuffer[0]; 
m_count = 0; 
} 
Diagnostic message: V607 Ownerless expression 'world->m_pairMemoryBuffer[0]'. dgcontact.cpp 342 
The comment tells us that the "world->m_pairMemoryBuffer[0]" expression makes sense. The analyzer, 
however, doesn't know that and generates a false positive. I removed it by adding a comment: 
world->m_pairMemoryBuffer[0]; //-V607 
A nicer solution would be to add a special method expanding the buffer. Then the code would look 
something like this: 
void dgCollidingPairCollector::Init () 
{ 
dgWorld* const world = (dgWorld*) this; 
world->m_pairMemoryBuffer.ExpandBuffer(); 
m_count = 0; 
} 
We don't need the comment anymore - the code says it all by itself. The analyzer doesn't generate any 
warnings, and everything's fine. 
Warning No. 67 
dgGoogol dgGoogol::Floor () const 
{ 
.... 
dgUnsigned64 mask = (-1LL) << (64 - bits); 
.... 
} 
Diagnostic message: V610 Undefined behavior. Check the shift operator '<<. The left operand '(- 1LL)' is 
negative. dggoogol.cpp 249 
You cannot shift negative numbers to the left - it leads to undefined behavior. To learn more about that, 
see the article "Wade not in unknown waters. Part three". 
I fixed the code in the following way: 
dgUnsigned64 mask = (~0LLU) << (64 - bits); 
Warnings No. 68 - No. 79 
void dGeometryNodeSkinModifierInfo::RemoveUnusedVertices(
const int* const vertexMap) 
{ 
.... 
dVector* vertexWeights = new dVector[m_vertexCount]; 
dBoneWeightIndex* boneWeightIndex = 
new dBoneWeightIndex[m_vertexCount]; 
.... 
delete boneWeightIndex; 
delete vertexWeights; 
} 
Diagnostic messages: 
• V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' 
operator. Consider inspecting this code. It's probably better to use 'delete [] boneWeightIndex;'. 
dgeometrynodeskinmodifierinfo.cpp 97 
• V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' 
operator. Consider inspecting this code. It's probably better to use 'delete [] vertexWeights;'. 
dgeometrynodeskinmodifierinfo.cpp 98 
Square brackets are missing near the 'delete' operators. It is a mistake and it must be fixed. The correct 
code will look as follows: 
delete [] boneWeightIndex; 
delete [] vertexWeights; 
The analyzer found 10 more fragments like that, and I fixed them all. 
Warning No. 80 
#if defined(_MSC_VER) 
/* Disable MSVC 'anachronism used' warning */ 
#pragma warning( disable : 4229 ) 
#endif 
typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); 
#if defined(_MSC_VER) 
#pragma warning( default : 4229 ) 
#endif 
Diagnostic message: V665 Possibly, the usage of '#pragma warning(default: X)' is incorrect in this 
context. The '#pragma warning(push/pop)' should be used instead. Check lines: 733, 739. pthread.h 739
This is a bad way to suppress warnings, especially if this code refers to the library. To find out the reason 
why and how to fix this code, see the description of the V665 diagnostic. 
I fixed the code by using "warning(push)" and " warning(pop)": 
#if defined(_MSC_VER) 
/* Disable MSVC 'anachronism used' warning */ 
#pragma warning( push ) 
#pragma warning( disable : 4229 ) 
#endif 
typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); 
#if defined(_MSC_VER) 
#pragma warning( pop ) 
#endif 
Warnings No. 81 - No. 99 
dgAABBPointTree4d* dgConvexHull4d::BuildTree (....) const 
{ 
.... 
const dgBigVector& p = points[i]; 
.... 
varian = varian + p.CompProduct4(p); 
.... 
} 
Diagnostic message: V678 An object is used as an argument to its own method. Consider checking the 
first actual argument of the 'CompProduct4' function. dgconvexhull4d.cpp 536 
The analyzer doesn't like the calls of the X.Foo(X) pattern. Firstly, it may be a typo. Secondly, the class 
may not be ready for handling itself. 
In this particular case, the code is correct. The false positive should be suppressed. We could use the 
following comment, for example: 
varian = varian + p.CompProduct4(p); //-V678 
But that's a bad idea. The analyzer has generated 18 more warnings of this kind, and you don't want to 
add so many comments into the code. 
Fortunately, all the 19 warnings refer to calls of the functions CompProduct3() or CompProduct4. So you 
can write only one comment to suppress all the V678 warnings in lines containing the substring 
"CompProduct": 
//-V:CompProduct:678
I placed this comment in the file dgStdafx.h. 
Warnings No. 100 - No. 119 
The 'dgBaseNode' class contains pointers: 
class dgBaseNode: public dgRef 
{ 
.... 
dgBaseNode (const dgBaseNode &clone); 
.... 
private: 
.... 
dgBaseNode* parent; 
dgBaseNode* child; 
dgBaseNode* sibling; 
}; 
Because of that, it has a full-blown copy constructor: 
dgBaseNode::dgBaseNode (const dgBaseNode &clone) 
:dgRef (clone) 
{ 
Clear (); 
for (dgBaseNode* obj = clone.child; obj; obj = obj->sibling) { 
dgBaseNode* newObj = (dgBaseNode *)obj->CreateClone (); 
newObj->Attach (this); 
newObj->Release(); 
} 
} 
Diagnostic message: V690 The 'dgBaseNode' class implements a copy constructor, but lacks the the '=' 
operator. It is dangerous to use such a class. dgnode.h 35 
The "Law of the Big Two" is violated here: the copy constructor is present, but the copy assignment 
operator = is missing. It will result in the compiler simply copying pointers' values while executing 
assignment, which will in its turn give birth to hard-to-find bugs. Even if the = operator is not used 
currently, this code is potentially dangerous as you may very easily make a mistake. 
There is only one correct way to fix it all - implement the = operator. If this operator is not needed 
according to the code's logic, you can declare it private. 
The analyzer has found 18 more classes with the = operator missing (or not forbidden).
There is also one strange class whose meaning and purpose I failed to figure out: 
struct StringPool 
{ 
char buff[STRING_POOL_SIZE]; 
StringPool () 
{ 
} 
StringPool (const StringPool &arg) 
{ 
} 
}; 
I simply suppressed the false positive by a comment: 
struct StringPool //-V690 
{ 
.... 
}; 
Note 1. C++11 has new keywords to make it simpler to forbid the use of copy constructors and copy 
assignment operators; or to tell the compiler that the copy constructor or = operator created by the 
compiler by default are correct. What I mean are =default and =delete. To learn more about these, see 
C++FAQ. 
Note 2. In many programs, copy assignment operators or assignment operators are implemented, 
though they are not needed. I mean the situation when an object can be easily copied by the compiler. 
Here is a simple artificial example: 
struct Point { 
int x, y; 
Point &Point(const Point &p) { x = p.x; y = p.y; return *this; } 
}; 
This code contains a = operator that no one needs. The "Law of the Big Two" is violated here, and the 
analyzer generates the warning. To avoid writing one more unnecessary function (the copy constructor), 
we need to delete the = operator. 
Here is an excellent short and correct class: 
struct Point { 
int x, y; 
}; 
Warnings No. 120 - No. 125
We have 6 more warnings of different types left. I failed to cope with them as I am absolutely unfamiliar 
with the code. I can't figure out if I'm dealing with a genuine bug or a false positive. Besides, even if it is 
an error, I still don't see how to fix it. I didn't feel like worrying my head off about it and simply marked 
them as false positives. 
Warnings No. 126 - No. 127 
Two warnings have been "lost". It's OK. You see, one and the same suspicious code fragment may 
sometimes trigger 2 or even 3 warnings. Therefore, one fix can eliminate several warnings at once. For 
example, V595 warnings might have disappeared because of the fixes related to the V560 diagnostic 
(see warnings No. 28 - No. 31). 
Conclusions 
As you can see, there are pretty few false positives as such. Most warnings point out smelling code 
fragments. They work indeed, but they are still pretty strange, hard to read and maintain. What can 
confuse the analyzer is even more likely to confuse a human. 
Many of the code fragments the analyzer didn't like can be rewritten. It will not only help to eliminate a 
warning, but also make the code clearer. 
For those cases when the analyzer is obviously wrong, it provides you with a number of various methods 
of false positive suppression. They are described in detail in the documentation. 
I hope I have managed to demonstrate in this article that handling false positives is far not as difficult as 
it might seem at first. I wish you luck in mastering our static code analyzers.

More Related Content

What's hot

Analyzing ReactOS One More Time
Analyzing ReactOS One More TimeAnalyzing ReactOS One More Time
Analyzing ReactOS One More TimePVS-Studio
 
Java -Exception handlingunit-iv
Java -Exception handlingunit-ivJava -Exception handlingunit-iv
Java -Exception handlingunit-ivRubaNagarajan
 
Exception handling
Exception handlingException handling
Exception handlingIblesoft
 
Tesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareTesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareAndrey Karpov
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio
 
Linux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLiteLinux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLitePVS-Studio
 
exception handling in cpp
exception handling in cppexception handling in cpp
exception handling in cppgourav kottawar
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioAndrey Karpov
 
Dusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind projectDusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind projectPVS-Studio
 
Can We Trust the Libraries We Use?
Can We Trust the Libraries We Use?Can We Trust the Libraries We Use?
Can We Trust the Libraries We Use?Andrey Karpov
 
Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?PVS-Studio
 
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Ekaterina Milovidova
 
Monitor(karthika)
Monitor(karthika)Monitor(karthika)
Monitor(karthika)Nagarajan
 
CppCat Static Analyzer Review
CppCat Static Analyzer ReviewCppCat Static Analyzer Review
CppCat Static Analyzer ReviewAndrey Karpov
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++Deepak Tathe
 
Date Processing Attracts Bugs or 77 Defects in Qt 6
Date Processing Attracts Bugs or 77 Defects in Qt 6Date Processing Attracts Bugs or 77 Defects in Qt 6
Date Processing Attracts Bugs or 77 Defects in Qt 6Andrey Karpov
 
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerRechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerAndrey Karpov
 
Checking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerChecking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerPVS-Studio
 

What's hot (20)

Analyzing ReactOS One More Time
Analyzing ReactOS One More TimeAnalyzing ReactOS One More Time
Analyzing ReactOS One More Time
 
Java -Exception handlingunit-iv
Java -Exception handlingunit-ivJava -Exception handlingunit-iv
Java -Exception handlingunit-iv
 
Exception handling
Exception handlingException handling
Exception handling
 
Tesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareTesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition Software
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave
 
Linux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLiteLinux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLite
 
Comp102 lec 10
Comp102   lec 10Comp102   lec 10
Comp102 lec 10
 
exception handling in cpp
exception handling in cppexception handling in cpp
exception handling in cpp
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-Studio
 
Dusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind projectDusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind project
 
Can We Trust the Libraries We Use?
Can We Trust the Libraries We Use?Can We Trust the Libraries We Use?
Can We Trust the Libraries We Use?
 
Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?
 
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
 
Monitor(karthika)
Monitor(karthika)Monitor(karthika)
Monitor(karthika)
 
CppCat Static Analyzer Review
CppCat Static Analyzer ReviewCppCat Static Analyzer Review
CppCat Static Analyzer Review
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++
 
Date Processing Attracts Bugs or 77 Defects in Qt 6
Date Processing Attracts Bugs or 77 Defects in Qt 6Date Processing Attracts Bugs or 77 Defects in Qt 6
Date Processing Attracts Bugs or 77 Defects in Qt 6
 
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerRechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
 
Checking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerChecking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzer
 
Exception handling
Exception handlingException handling
Exception handling
 

Similar to Handling False Positives in PVS-Studio and CppCat

Checking PVS-Studio with Clang
Checking PVS-Studio with ClangChecking PVS-Studio with Clang
Checking PVS-Studio with ClangAndrey Karpov
 
An Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a ProjectAn Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a ProjectPVS-Studio
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckAndrey Karpov
 
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodeA Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodePVS-Studio
 
Analyzing the Blender project with PVS-Studio
Analyzing the Blender project with PVS-StudioAnalyzing the Blender project with PVS-Studio
Analyzing the Blender project with PVS-StudioPVS-Studio
 
How to find 56 potential vulnerabilities in FreeBSD code in one evening
How to find 56 potential vulnerabilities in FreeBSD code in one eveningHow to find 56 potential vulnerabilities in FreeBSD code in one evening
How to find 56 potential vulnerabilities in FreeBSD code in one eveningPVS-Studio
 
LibRaw, Coverity SCAN, PVS-Studio
LibRaw, Coverity SCAN, PVS-StudioLibRaw, Coverity SCAN, PVS-Studio
LibRaw, Coverity SCAN, PVS-StudioAndrey Karpov
 
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...PVS-Studio
 
Analyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectAnalyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectPVS-Studio
 
Checking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerChecking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerPVS-Studio
 
Heading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th CheckHeading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th CheckPVS-Studio
 
Checking the Qt 5 Framework
Checking the Qt 5 FrameworkChecking the Qt 5 Framework
Checking the Qt 5 FrameworkAndrey Karpov
 
Static and Dynamic Code Analysis
Static and Dynamic Code AnalysisStatic and Dynamic Code Analysis
Static and Dynamic Code AnalysisAndrey Karpov
 
A fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBoxA fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBoxPVS-Studio
 
How to make fewer errors at the stage of code writing. Part N1.
How to make fewer errors at the stage of code writing. Part N1.How to make fewer errors at the stage of code writing. Part N1.
How to make fewer errors at the stage of code writing. Part N1.PVS-Studio
 
How to Improve Visual C++ 2017 Libraries Using PVS-Studio
How to Improve Visual C++ 2017 Libraries Using PVS-StudioHow to Improve Visual C++ 2017 Libraries Using PVS-Studio
How to Improve Visual C++ 2017 Libraries Using PVS-StudioPVS-Studio
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggyPVS-Studio
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in DoxygenPVS-Studio
 
Copy-Paste and Muons
Copy-Paste and MuonsCopy-Paste and Muons
Copy-Paste and MuonsAndrey Karpov
 

Similar to Handling False Positives in PVS-Studio and CppCat (20)

Checking PVS-Studio with Clang
Checking PVS-Studio with ClangChecking PVS-Studio with Clang
Checking PVS-Studio with Clang
 
An Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a ProjectAn Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a Project
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after Cppcheck
 
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodeA Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
 
Analyzing the Blender project with PVS-Studio
Analyzing the Blender project with PVS-StudioAnalyzing the Blender project with PVS-Studio
Analyzing the Blender project with PVS-Studio
 
How to find 56 potential vulnerabilities in FreeBSD code in one evening
How to find 56 potential vulnerabilities in FreeBSD code in one eveningHow to find 56 potential vulnerabilities in FreeBSD code in one evening
How to find 56 potential vulnerabilities in FreeBSD code in one evening
 
LibRaw, Coverity SCAN, PVS-Studio
LibRaw, Coverity SCAN, PVS-StudioLibRaw, Coverity SCAN, PVS-Studio
LibRaw, Coverity SCAN, PVS-Studio
 
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
 
Analyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectAnalyzing the Dolphin-emu project
Analyzing the Dolphin-emu project
 
Checking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerChecking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzer
 
Heading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th CheckHeading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th Check
 
Checking the Qt 5 Framework
Checking the Qt 5 FrameworkChecking the Qt 5 Framework
Checking the Qt 5 Framework
 
Static and Dynamic Code Analysis
Static and Dynamic Code AnalysisStatic and Dynamic Code Analysis
Static and Dynamic Code Analysis
 
A fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBoxA fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBox
 
How to make fewer errors at the stage of code writing. Part N1.
How to make fewer errors at the stage of code writing. Part N1.How to make fewer errors at the stage of code writing. Part N1.
How to make fewer errors at the stage of code writing. Part N1.
 
How to Improve Visual C++ 2017 Libraries Using PVS-Studio
How to Improve Visual C++ 2017 Libraries Using PVS-StudioHow to Improve Visual C++ 2017 Libraries Using PVS-Studio
How to Improve Visual C++ 2017 Libraries Using PVS-Studio
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in Doxygen
 
Copy-Paste and Muons
Copy-Paste and MuonsCopy-Paste and Muons
Copy-Paste and Muons
 
Grounded Pointers
Grounded PointersGrounded Pointers
Grounded Pointers
 

More from Andrey Karpov

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программистаAndrey Karpov
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developerAndrey Karpov
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Andrey Karpov
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesAndrey Karpov
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewAndrey Karpov
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокAndrey Karpov
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Andrey Karpov
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesAndrey Karpov
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?Andrey Karpov
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaAndrey Karpov
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)Andrey Karpov
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Andrey Karpov
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerAndrey Karpov
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareAndrey Karpov
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineAndrey Karpov
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsAndrey Karpov
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++Andrey Karpov
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?Andrey Karpov
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youAndrey Karpov
 

More from Andrey Karpov (20)

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developer
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature Overview
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
PVS-Studio в 2021
PVS-Studio в 2021PVS-Studio в 2021
PVS-Studio в 2021
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and Java
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
 

Recently uploaded

Buds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in NoidaBuds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in Noidabntitsolutionsrishis
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfLivetecs LLC
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfIdiosysTechnologies1
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 

Recently uploaded (20)

Buds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in NoidaBuds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in Noida
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdf
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdf
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 

Handling False Positives in PVS-Studio and CppCat

  • 1. Handling False Positives in PVS-Studio and CppCat Author: Andrey Karpov Date: 20.06.2014 It occurred to me recently to reanalyze the Newton Game Dynamics physics engine. The project's code is very high-quality, so there were almost no genuine bugs detected, but I did get a few dozens of false positives. Seems like there's nothing to write about, doesn't it? Well, I thought I should write about how to handle false positives and how to avoid them. I found the Newton Game Dynamics project a good example to demonstrate that on. Project analysis The number of diagnostic messages the PVS-Studio analyzer generated on this project is as follows: • 48 first-level messages; • 79 second-level messages; • 261 third-level messages (off by default). All of these refer to the general analysis set of diagnostic rules (GA). So, it makes total 127 warnings that need to be examined. The CppCat analyzer generates just as many messages. Further in the article, I won't distinguish between PVS-Studio and CppCat. In general, both provide identical false positive suppression mechanisms. PVS-Studio does have a bit more of them, but it doesn't affect the whole picture much. Note. To learn about the differences between the functional capabilities of PVS-Studio and CppCat, follow this link. It took me three hours odd to write down all the necessary samples for the article and get rid of all the warnings. I think it would have taken me not more than an hour if I had not had to write down the examples. It suggests that the difficulty of fighting against false positives is exaggerated. It's true that they hinder and distract you; it's true that large projects contain piles of false positives. But nevertheless, it's not difficult at all to get rid of them. The result is: CppCat generates 0 warnings; so does PVS-Studio. Well, we could turn on the third-level or 64-bit diagnostics of course, but they are not as interesting. First of all, you need to eliminate those warnings the analyzer draws your attention to as most crucial ones. And that is already a large step toward higher quality of your code. It is what you should start with. If you turn on all the diagnostics at
  • 2. once, you won't feel strong and patient enough to go through all of them. By the way, it's a main mistake of novice programmers. Remember that "more" doesn't mean "better". Analysis report review The PVS-Studio and CppCat analyzers don't group diagnostic messages and don't sort them. You don't need this when you use them regularly: if a tool detects 2 or 3 bugs in new code, there is nothing to group and sort there, while implementing this feature would only complicate the interface. When using the tool for the first time, you can sort messages by diagnostic number. It is done by clicking on the header of the column with diagnostic code. We decided not to implement it as an automatic feature. Warnings are displayed in the same order as files are being analyzed, which allows you to start viewing messages without having to wait for the analysis to finish. If we chose to automatically sort messages while the analysis is running, they would "jump" all over the table and you won't be able to handle them until the analysis is over. Thus, sorting by message type (diagnostic number) is most useful at the first stages. And this is what I will do. It will allow me to quickly find false positives of one type and eliminate them, thus significantly simplifying the work and reducing the time of initial setting up. Handling diagnostic messages If any of the false positive suppression methods don't seem clear enough, see the corresponding section in the documentation: • For PVS-Studio - Suppression of false alarms. • For CppCat - the documentation coming with the distribution package. Warnings No. 1, No. 2 void dgWorldDynamicUpdate::CalculateJointsVelocParallelKernel (....) { .... dgVector velocStep2 (velocStep.DotProduct4(velocStep)); dgVector omegaStep2 (omegaStep.DotProduct4(omegaStep)); dgVector test ((velocStep2 > speedFreeze2) | (omegaStep2 > omegaStep2)); .... } Diagnostic message: V501 There are identical sub-expressions to the left and to the right of the '>' operator: omegaStep2 > omegaStep2 dgworlddynamicsparallelsolver.cpp 546 The "omegaStep2 > omegaStep2" expression looks suspicious. I cannot say for sure if there is a genuine error here or not. Because this comparison can also be found in another file, I guess it's not a bug but the programmer's conscious intention. Let's assume it's not an error. I have marked these two fragments with a special comment: dgVector test ((velocStep2 > speedFreeze2) |
  • 3. (omegaStep2 > omegaStep2)); //-V501 From now on, the V501 warning will not be generated for these fragments. Warning No. 3 dgInt32 dgWorld::CalculatePolySoupToHullContactsDescrete(....) const { .... dgAssert (dgAbsf(polygon.m_normal % polygon.m_normal - dgFloat32 (1.0f)) < dgFloat32 (1.0e-4f)); .... } Diagnostic message: V501 There are identical sub-expressions to the left and to the right of the '%' operator: polygon.m_normal % polygon.m_normal dgnarrowphasecollision.cpp 1921 The analyzer is both right and wrong about this code fragment. On the one hand, the "polygon.m_normal % polygon.m_normal" expression is very suspicious indeed. On the other hand, the analyzer just can't figure out that this is a test to check the '%' operator implemented in a class. So the code is actually correct. Let's help the analyzer by adding a comment: dgAssert (dgAbsf(polygon.m_normal % polygon.m_normal - //-V501 dgFloat32 (1.0f)) < dgFloat32 (1.0e-4f)); Warning No. 4 static void PopupateTextureCacheNode (dScene* const scene) { .... if (!(info->IsType(dSceneCacheInfo::GetRttiType()) || info->IsType(dSceneCacheInfo::GetRttiType()))) { .... } Diagnostic message: V501 There are identical sub-expressions 'info- >IsType(dSceneCacheInfo::GetRttiType())' to the left and to the right of the '||' operator. dscene.cpp 125 One and the same condition is checked twice. Suppose the second check is redundant. To get rid of the false warning, I fixed the code in the following way: if (!(info->IsType(dSceneCacheInfo::GetRttiType()))) { Warning No. 5 dFloat dScene::RayCast (....) const {
  • 4. .... dFloat den = 1.0f / ((globalP1 - globalP0) % (globalP1 - globalP0)); //-V501 .... } Diagnostic message: V501 There are identical sub-expressions '(globalP1 - globalP0)' to the left and to the right of the '%' operator. dscene.cpp 1280 The variables globalP0 and globalP1 are instances of the 'dVector' class. Because of that, this code makes sense and the analyzer's worry is all for nothing. Let's mark the code with the comment: dFloat den = 1.0f / ((globalP1 - globalP0) % (globalP1 - globalP0)); //-V501 Although the analyzer is wrong, this code still can't be called neat. I suggest implementing special functions or something else for such cases. Warnings No. 6 - No. 15 dgInt32 dgCollisionCompound::CalculateContactsToCompound ( ...., dgCollisionParamProxy& proxy) const { .... dgCollisionInstance childInstance (*subShape, subShape->GetChildShape()); .... proxy.m_referenceCollision = &childInstance; .... m_world->CalculateConvexToConvexContacts(proxy); .... } Diagnostic message: V506 Pointer to local variable 'childInstance' is stored outside the scope of this variable. Such a pointer will become invalid. dgcollisioncompound.cpp 1815 The function receives a reference to an object of the 'dgCollisionParamProxy' type. A pointer to a local variable is written into this object, and the analyzer warns that it is potentially dangerous. After leaving the function, this pointer can't be used because the local variable it points to will be destroyed by then. There is no error in this particular case. The pointer is used only while the variable exists. I don't feel like using comments to suppress such warnings. You see, there are 9 more of them, all of the same kind. So let's do it another way. All the lines these false positives are generated on contain a variable named 'proxy'. We can write one single comment to suppress all these warnings at once:
  • 5. //-V:proxy:506 It should be added into some file that gets included into all the other files. In our case, the file "dgPhysicsStdafx.h" will do best. From now on, the V506 warning won't be displayed for any lines containing the word 'proxy'. This mechanism was initially implemented to suppress warnings in macros. But it doesn't actually matter if a word serves as a name for a macro or some other entity (a variable, function, class, etc.). The principle behind it is simple: if a string contains a specified substring, the corresponding warning is not displayed. Warning No. 16 The following sample is a lengthy one. There's nothing of much interest about it, so you may skip it. We have a vector class: class dgVector { .... union { __m128 m_type; __m128i m_typeInt; dgFloat32 m_f[4]; struct { dgFloat32 m_x; dgFloat32 m_y; dgFloat32 m_z; dgFloat32 m_w; }; struct { dgInt32 m_ix; dgInt32 m_iy; dgInt32 m_iz; dgInt32 m_iw; }; }; .... }; And we have the following piece of code where vector members are filled with values by the memcpy() function: DG_INLINE dgMatrix::dgMatrix (const dgFloat32* const array)
  • 6. { memcpy (&m_front.m_x, array, sizeof (dgMatrix)) ; } Diagnostic message: V512 A call of the 'memcpy' function will lead to overflow of the buffer '& m_front.m_x'. dgmatrix.h 118 The analyzer doesn't like that more bytes are written into the variable of the 'dgFloat32' type than it actually occupies. Far from neat, this practice, however, works well and is widely used. The function is actually filling with values the variables m_x, m_y, m_z, and so on. I was not attentive enough for the first time and just fixed the code in the following way: memcpy(m_front.m_f, array, sizeof(dgMatrix)); I thought that only one vector was copied, while the size of the 'm_f' array is just the same as that of the vector. But at the next launch, the analyzer drew my attention to the code once again. There were actually 4 vectors to be copied, not one. And it is 4 vectors that the 'dgMatrix' class contains: class dgMatrix { .... dgVector m_front; dgVector m_up; dgVector m_right; dgVector m_posit; .... } I don't know how to make this code neat and short, so I decided to leave it all as it had been before and just added the comment: memcpy (&m_front.m_x, array, sizeof (dgMatrix)) ; //-V512 Warnings No. 17, No. 18 void dgWorldDynamicUpdate::UpdateDynamics(dgFloat32 timestep) { dgWorld* const world = (dgWorld*) this; dgUnsigned32 updateTime = world->m_getPerformanceCount(); m_bodies = 0; m_joints = 0; m_islands = 0;
  • 7. m_markLru = 0; world->m_dynamicsLru = world->m_dynamicsLru + DG_BODY_LRU_STEP; m_markLru = world->m_dynamicsLru; .... } Diagnostic message: V519 The 'm_markLru' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 91, 94. dgworlddynamicupdate.cpp 94 The 'm_markLru' variable is first initialized by 0 and then 'world->m_dynamicsLru' is written into it. There is no error here. To get rid of the warning, I removed the variable initialization by zero. Just in the same way I fixed one more code fragment. The corresponding diagnostic message: V519 The 'm_posit' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1310, 1313. customvehiclecontrollermanager.cpp 1313 Warnings No. 19, No. 20 dgFloat32 dgCollisionConvexPolygon::GetBoxMinRadius () const { return m_faceClipSize; } dgFloat32 dgCollisionConvexPolygon::GetBoxMaxRadius () const { return m_faceClipSize; } Diagnostic message: V524 It is odd that the body of 'GetBoxMaxRadius' function is fully equivalent to the body of 'GetBoxMinRadius' function. dgcollisionconvexpolygon.cpp 88 Two functions whose names contain the words 'Min' and 'Max' are implemented in the same way. The analyzer finds it suspicious. But everything is OK here. To eliminate the false positive, I implemented one function through the other: dgFloat32 dgCollisionConvexPolygon::GetBoxMaxRadius () const { return GetBoxMinRadius(); } In the same way I handled the functions GetBoxMaxRadius/GetBoxMaxRadius implemented in the 'dgCollisionScene' class. Warning No. 21
  • 8. dgInt32 AddFilterFace (dgUnsigned32 count, dgInt32* const pool) { .... for (dgUnsigned32 i = 0; i < count; i ++) { for (dgUnsigned32 j = i + 1; j < count; j ++) { if (pool[j] == pool[i]) { for (i = j; i < count - 1; i ++) { pool[i] = pool[i + 1]; } count --; i = count; reduction = true; break; } } } .... } Diagnostic message: V535 The variable 'i' is being used for this loop and for the outer loop. Check lines: 105, 108. dgpolygonsoupbuilder.cpp 108 We have two loops here. One of them uses the variable 'i' as a counter; the other, the variable 'j'. Inside these loops, one more loop is sometimes run. It uses the variable 'i' as a counter, too. The analyzer doesn't like it, though there is no error here. When an internal loop is executed, external loops are stopped: • the loop organized by the 'j' variable is stopped by the 'break' operator; • the loop organized by the 'i' variable is stopped through the assignment "i = count". The analyzer failed to figure out these nuances. The fragment above is a fine example of code that works but smells. I used commenting to eliminate the false positive: for (i = j; i < count - 1; i ++) { //-V535 Warnings No. 22 - No. 25 DG_INLINE dgMatrix::dgMatrix (const dgVector& front) { ....
  • 9. m_right = m_right.Scale3 (dgRsqrt (m_right % m_right)); m_up = m_right * m_front; .... } Diagnostic message: V537 Consider reviewing the correctness of 'm_right' item's usage. dgmatrix.h 143 The analyzer generates the V537 warning when it comes across a suspicious mixture of variables whose names contain the words "right", "left", "front", and the like. This diagnostic proved unsuccessful for this project as the analyzer generated 4 warnings on absolutely safe code. In that case, we can completely turn this diagnostic off in PVS-Studio's settings. In CppCat, you can't turn off single diagnostics, so we have to use an alternative method. All the lines that triggered the false positives contain the word "right". I added the following comment into the file "dgStdafx.h": //-V:right:537 Warning No. 26 Notice the comment. int pthread_delay_np (struct timespec *interval) { .... /* * Most compilers will issue a warning 'comparison always 0' * because the variable type is unsigned, * but we need to keep this * for some reason I can't recall now. */ if (0 > (wait_time = secs_in_millisecs + millisecs)) { return EINVAL; } .... } Diagnostic message: V547 Expression is always false. Unsigned type value is never < 0. pthread_delay_np.c 119 The comment tells us that it's not a bug, but the programmer's conscious intention. Well, in that case we only have to suppress the warning by a comment: if (0 > (wait_time = secs_in_millisecs + millisecs)) //-V547
  • 10. Warning No. 27 typedef unsigned long long dgUnsigned64; dgUnsigned64 m_mantissa[DG_GOOGOL_SIZE]; dgGoogol::dgGoogol(dgFloat64 value) :m_sign(0) ,m_exponent(0) { .... m_mantissa[0] = (dgInt64 (dgFloat64 ( dgUnsigned64(1)<<62) * mantissa)); // it looks like GCC have problems with this dgAssert (m_mantissa[0] >= 0); .... } Diagnostic message: V547 Expression 'm_mantissa[0] >= 0' is always true. Unsigned type value is always >= 0. dggoogol.cpp 55 The analyzer shares GCC's opinion that something is wrong with this code (see the comment in the code). The check "dgAssert(m_mantissa[0] >= 0)" makes no sense: an unsigned variable is always equal to or larger than zero. 'dgAssert' doesn't actually check anything. Programmers tend to be lazy. They would rather write a comment than spend some time to investigate an issue and fix a mistake. I fixed the code so that 'dgAssert' executed a correct check. For this purpose, I had to add a temporary signed variable: dgInt64 integerMantissa = (dgInt64(dgFloat64( dgUnsigned64(1) << 62) * mantissa)); dgAssert(integerMantissa >= 0); m_mantissa[0] = integerMantissa; Warnings No. 28 - No. 31 void dgRedBackNode::RemoveFixup (....) {
  • 11. .... if (!ptr) { return; } .... ptr->SetColor(RED) ; ptr->RotateLeft (head); tmp = ptr->m_right; if (!ptr || !tmp) { return; } .... } Diagnostic message: V560 A part of conditional expression is always false: !ptr. dgtree.cpp 215 The '!ptr' expression is always false. The reason is that the 'ptr' pointer has already been checked for being null before. If it was found to be null, the function would be left. The second check looks even sillier because of the pointer being dereferenced before it: "tmp = ptr- >m_right;". I eliminated the false positive by removing the second meaningless check. The code now looks like this: if (!ptr) { return; } .... tmp = ptr->m_right; if (!tmp) { return; } .... In the same way I fixed 3 other code fragments. By the way, this code could additionally trigger the V595 warning. I felt too lazy to check it for sure, but if we miss a couple of warnings in the end of the article, be aware that it will be just because of that. Warnings No. 32, No. 33 DG_INLINE bool dgBody::IsCollidable() const;
  • 12. void dgBroadPhase::AddPair (dgBody* const body0, dgBody* const body1, const dgVector& timestep2, dgInt32 threadID) { .... bool kinematicBodyEquilibrium = (((body0->IsRTTIType(dgBody::m_kinematicBodyRTTI) ? true : false) & body0->IsCollidable()) | ((body1->IsRTTIType(dgBody::m_kinematicBodyRTTI) ? true : false) & body1->IsCollidable())) ? false : true; .... } Diagnostic message: V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. dgbroadphase.cpp 921 This code smells. I don't think I understand why the programmer would need such a complicated and obscure check. I rewrote it, and the code became a bit shorter and more readable. Besides, I got rid of the false warning. bool kinematicBodyEquilibrium = !((body0->IsRTTIType(dgBody::m_kinematicBodyRTTI) && body0->IsCollidable()) || (body1->IsRTTIType(dgBody::m_kinematicBodyRTTI) && body1->IsCollidable())); There was one more V564 warning, and I simplified the corresponding code fragment too: V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. dgbroadphase.cpp 922 Warnings No. 34 - No. 37 class dgAIWorld: public dgAIAgentGraph { .... }; typedef struct NewtonAIWorld{} NewtonAIWorld; NewtonAIWorld* NewtonAICreate () { TRACE_FUNCTION(__FUNCTION__); dgMemoryAllocator* const allocator = new dgMemoryAllocator(); NewtonAIWorld* const ai = (NewtonAIWorld*) new (allocator) dgAIWorld (allocator);
  • 13. return ai; } Diagnostic message: V572 It is odd that the object which was created using 'new' operator is immediately casted to another type. newtonai.cpp 40 That's a pretty strange way to store objects: creating an object of the 'dgAIWorld' class and casting it explicitly to the ' NewtonAIWorld' type. I didn't feel like figuring out why it had been done - there must have been some reason; I simply suppressed this warning by a comment in this and 3 other functions. Warning No. 38 void dgCollisionCompound::EndAddRemove () { .... if (node->m_type == m_node) { list.Append(node); } if (node->m_type == m_node) { stack.Append(node->m_right); stack.Append(node->m_left); } .... } Diagnostic message: V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 952, 956. dgcollisioncompound.cpp 956 The analyzer doesn't like one and the same condition being checked twice on end. Perhaps there is some typo here. What if this code was meant to look like this: if (node->m_type == m_node) { .... } if (node->m_type == m_FOO) { .... } However, that code sample is alright. To get rid of the false positive, we should fix the code. I don't think I will violate the program execution logic by leaving only one check: if (node->m_type == m_node) { list.Append(node); stack.Append(node->m_right);
  • 14. stack.Append(node->m_left); } Warning No. 39 void dSceneGraph::AddEdge (....) { .... if ((!parentLink && !childLink)) { .... } Diagnostic message: V592 The expression was enclosed by parentheses twice: '((!parentLink &&!childLink))'. One pair of parentheses is unnecessary or misprint is present. dscenegraph.cpp 209 It's OK, just redundant parentheses. I removed them: if (!parentLink && !childLink) { Warnings No. 40 - No. 44 dgVector dgCollisionCylinder::SupportVertex (....) const { dgAssert (dgAbsf ((dir % dir - dgFloat32 (1.0f))) < dgFloat32 (1.0e-3f)); .... } Diagnostic message: V592 The expression was enclosed by parentheses twice: '((dir % dir - dgFloat32(1.0f)))'. One pair of parentheses is unnecessary or misprint is present. dgcollisioncylinder.cpp 202 It's alright, just redundant parentheses. I removed them so that the analyzer didn't worry: dgAssert (dgAbsf (dir % dir - dgFloat32 (1.0f)) < dgFloat32 (1.0e-3f)); This line was replicated to 4 other code fragments through the Copy-Paste method. I fixed those too. Warnings No. 45 - No. 65 void ptw32_throw (DWORD exception) { .... ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);
  • 15. sp->state = PThreadStateExiting; if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) { exit (1); } .... if (NULL == sp || sp->implicit) .... } Diagnostic message: V595 The 'sp' pointer was utilized before it was verified against nullptr. Check lines: 77, 85. ptw32_throw.c 77 The V595 diagnostic works in the following way. The analyzer considers the code suspicious if a pointer is first dereferenced and then checked for being null. There are certain nuances and exceptions for rule, but the general principle is just like I said. Here we have just such a case: the 'sp' variable is first dereferenced in the expression "sp->state" and then is checked for being null. The analyzer has detected 20 more fragments like that. In each particular case, we should act differently: in some fragments I placed the check before the dereferencing operation and in some other fragments I simply removed it. Note False V595 warnings are very often triggered by macros of the following pattern: #define FREE(p) { if (p) free(p); } In this particular case, the analyzer will figure out the programmer's intention and keep silent. But in general, the following code pattern may trigger false positives: p->foo(); FREE(p); In these cases, I recommend that you throw macros away completely. The FREE() macro shown above is absolutely meaningless and even harmful. Firstly, you don't have to check the pointer for being null. The free() function handles null pointers correctly. The same is true for the 'delete' operator. That's why the FREE() macro is not needed - at all. Secondly, it is dangerous. If we extract pointers from an array, it may cause an error. For example: FREE(ArrayOfPtr[i++]) - the first pointer will be checked, and the next one will be freed. Warning No. 66 void dgCollidingPairCollector::Init ()
  • 16. { dgWorld* const world = (dgWorld*) this; // need to expand teh buffer is needed world->m_pairMemoryBuffer[0]; m_count = 0; } Diagnostic message: V607 Ownerless expression 'world->m_pairMemoryBuffer[0]'. dgcontact.cpp 342 The comment tells us that the "world->m_pairMemoryBuffer[0]" expression makes sense. The analyzer, however, doesn't know that and generates a false positive. I removed it by adding a comment: world->m_pairMemoryBuffer[0]; //-V607 A nicer solution would be to add a special method expanding the buffer. Then the code would look something like this: void dgCollidingPairCollector::Init () { dgWorld* const world = (dgWorld*) this; world->m_pairMemoryBuffer.ExpandBuffer(); m_count = 0; } We don't need the comment anymore - the code says it all by itself. The analyzer doesn't generate any warnings, and everything's fine. Warning No. 67 dgGoogol dgGoogol::Floor () const { .... dgUnsigned64 mask = (-1LL) << (64 - bits); .... } Diagnostic message: V610 Undefined behavior. Check the shift operator '<<. The left operand '(- 1LL)' is negative. dggoogol.cpp 249 You cannot shift negative numbers to the left - it leads to undefined behavior. To learn more about that, see the article "Wade not in unknown waters. Part three". I fixed the code in the following way: dgUnsigned64 mask = (~0LLU) << (64 - bits); Warnings No. 68 - No. 79 void dGeometryNodeSkinModifierInfo::RemoveUnusedVertices(
  • 17. const int* const vertexMap) { .... dVector* vertexWeights = new dVector[m_vertexCount]; dBoneWeightIndex* boneWeightIndex = new dBoneWeightIndex[m_vertexCount]; .... delete boneWeightIndex; delete vertexWeights; } Diagnostic messages: • V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] boneWeightIndex;'. dgeometrynodeskinmodifierinfo.cpp 97 • V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] vertexWeights;'. dgeometrynodeskinmodifierinfo.cpp 98 Square brackets are missing near the 'delete' operators. It is a mistake and it must be fixed. The correct code will look as follows: delete [] boneWeightIndex; delete [] vertexWeights; The analyzer found 10 more fragments like that, and I fixed them all. Warning No. 80 #if defined(_MSC_VER) /* Disable MSVC 'anachronism used' warning */ #pragma warning( disable : 4229 ) #endif typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); #if defined(_MSC_VER) #pragma warning( default : 4229 ) #endif Diagnostic message: V665 Possibly, the usage of '#pragma warning(default: X)' is incorrect in this context. The '#pragma warning(push/pop)' should be used instead. Check lines: 733, 739. pthread.h 739
  • 18. This is a bad way to suppress warnings, especially if this code refers to the library. To find out the reason why and how to fix this code, see the description of the V665 diagnostic. I fixed the code by using "warning(push)" and " warning(pop)": #if defined(_MSC_VER) /* Disable MSVC 'anachronism used' warning */ #pragma warning( push ) #pragma warning( disable : 4229 ) #endif typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); #if defined(_MSC_VER) #pragma warning( pop ) #endif Warnings No. 81 - No. 99 dgAABBPointTree4d* dgConvexHull4d::BuildTree (....) const { .... const dgBigVector& p = points[i]; .... varian = varian + p.CompProduct4(p); .... } Diagnostic message: V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'CompProduct4' function. dgconvexhull4d.cpp 536 The analyzer doesn't like the calls of the X.Foo(X) pattern. Firstly, it may be a typo. Secondly, the class may not be ready for handling itself. In this particular case, the code is correct. The false positive should be suppressed. We could use the following comment, for example: varian = varian + p.CompProduct4(p); //-V678 But that's a bad idea. The analyzer has generated 18 more warnings of this kind, and you don't want to add so many comments into the code. Fortunately, all the 19 warnings refer to calls of the functions CompProduct3() or CompProduct4. So you can write only one comment to suppress all the V678 warnings in lines containing the substring "CompProduct": //-V:CompProduct:678
  • 19. I placed this comment in the file dgStdafx.h. Warnings No. 100 - No. 119 The 'dgBaseNode' class contains pointers: class dgBaseNode: public dgRef { .... dgBaseNode (const dgBaseNode &clone); .... private: .... dgBaseNode* parent; dgBaseNode* child; dgBaseNode* sibling; }; Because of that, it has a full-blown copy constructor: dgBaseNode::dgBaseNode (const dgBaseNode &clone) :dgRef (clone) { Clear (); for (dgBaseNode* obj = clone.child; obj; obj = obj->sibling) { dgBaseNode* newObj = (dgBaseNode *)obj->CreateClone (); newObj->Attach (this); newObj->Release(); } } Diagnostic message: V690 The 'dgBaseNode' class implements a copy constructor, but lacks the the '=' operator. It is dangerous to use such a class. dgnode.h 35 The "Law of the Big Two" is violated here: the copy constructor is present, but the copy assignment operator = is missing. It will result in the compiler simply copying pointers' values while executing assignment, which will in its turn give birth to hard-to-find bugs. Even if the = operator is not used currently, this code is potentially dangerous as you may very easily make a mistake. There is only one correct way to fix it all - implement the = operator. If this operator is not needed according to the code's logic, you can declare it private. The analyzer has found 18 more classes with the = operator missing (or not forbidden).
  • 20. There is also one strange class whose meaning and purpose I failed to figure out: struct StringPool { char buff[STRING_POOL_SIZE]; StringPool () { } StringPool (const StringPool &arg) { } }; I simply suppressed the false positive by a comment: struct StringPool //-V690 { .... }; Note 1. C++11 has new keywords to make it simpler to forbid the use of copy constructors and copy assignment operators; or to tell the compiler that the copy constructor or = operator created by the compiler by default are correct. What I mean are =default and =delete. To learn more about these, see C++FAQ. Note 2. In many programs, copy assignment operators or assignment operators are implemented, though they are not needed. I mean the situation when an object can be easily copied by the compiler. Here is a simple artificial example: struct Point { int x, y; Point &Point(const Point &p) { x = p.x; y = p.y; return *this; } }; This code contains a = operator that no one needs. The "Law of the Big Two" is violated here, and the analyzer generates the warning. To avoid writing one more unnecessary function (the copy constructor), we need to delete the = operator. Here is an excellent short and correct class: struct Point { int x, y; }; Warnings No. 120 - No. 125
  • 21. We have 6 more warnings of different types left. I failed to cope with them as I am absolutely unfamiliar with the code. I can't figure out if I'm dealing with a genuine bug or a false positive. Besides, even if it is an error, I still don't see how to fix it. I didn't feel like worrying my head off about it and simply marked them as false positives. Warnings No. 126 - No. 127 Two warnings have been "lost". It's OK. You see, one and the same suspicious code fragment may sometimes trigger 2 or even 3 warnings. Therefore, one fix can eliminate several warnings at once. For example, V595 warnings might have disappeared because of the fixes related to the V560 diagnostic (see warnings No. 28 - No. 31). Conclusions As you can see, there are pretty few false positives as such. Most warnings point out smelling code fragments. They work indeed, but they are still pretty strange, hard to read and maintain. What can confuse the analyzer is even more likely to confuse a human. Many of the code fragments the analyzer didn't like can be rewritten. It will not only help to eliminate a warning, but also make the code clearer. For those cases when the analyzer is obviously wrong, it provides you with a number of various methods of false positive suppression. They are described in detail in the documentation. I hope I have managed to demonstrate in this article that handling false positives is far not as difficult as it might seem at first. I wish you luck in mastering our static code analyzers.