SlideShare a Scribd company logo
1 of 13
Download to read offline
Analyzing FreeCAD's Source Code and Its
"Sick" Dependencies
Author: Svyatoslav Razmyslov
Date: 30.04.2015
This article was initially meant as a review of bugs found in the FreeCAD open-source project but
eventually took a bit different direction. It happened because a considerable portion of the warnings
had been generated for the third-party libraries employed by the project. Extensive use of third-party
libraries in software development is highly beneficial, especially in the open-source software domain.
And bugs found in these libraries are no good reason to reject them. But we still should keep in mind
that third-party code we use in our projects may contain bugs, so we must be prepared to meet and, if
possible, fix them, thus improving the libraries.
Introduction
FreeCAD is a free and open-source general purpose parametric 3D CAD modeler allowing creating 3D
models and drawing their projections. FreeCAD's developer Juergen Riegel, working at DaimlerChrysler
corporation, positions his program as the first free mechanical engineering and design tool. There is a
well-known issue in a number of related areas that deals with the lack of a full-fledged open-source CAD
application, and the FreeCAD project is just aiming to become one. So let's check its source code with
PVS-Studio to help this open-source project become a bit better. I bet you encounter "glitches" in
various modelers every now and then when you can't hit a certain point or align a line which is
constantly shifting one pixel away from the desired position. All of that may be just a result of some
typos in the source code.
What's wrong with PVS-Studio?!
The FreeCAD project is cross-platform and there is a very good collection of documents on building it
available at their site. It wasn't difficult to get project files for Visual Studio Community 2013 for further
analysis by the PVS-Studio plugin installed on my computer. But for some reason, the check wouldn't go
well at first...
As I found out, the cause of the analyzer's internal error had been the presence of a binary sequence in
the preprocessed text *.i file. The analyzer can sort out issues like that but it was something unfamiliar
this time. The trouble was with one of the lines in the source-file compilation parameters.
/FI"Drawing.dir/Debug//Drawing_d.pch"
The /FI (Name Forced Include File) compilation switch, just like the #include directive, serves for
including text header files. But in this case, the programmers are trying to include a file with binary data.
It even manages to compile somehow - I guess Visual C++ simply ignores it.
But if we try to preprocess those files, instead of compiling them, Visual C++ will display an error
message. However, the Clang compiler, used in PVS-Studio by default, included the binary file into the
*.i file without much thinking. PVS-Studio never expected such a trap and went crazy.
To make it clearer, here's a fragment of the file preprocessed by Clang:
I carefully checked the project without that switch but the authors ought to know that they have an
error there.
FreeCAD
The first bug samples to be discussed result from a very well-known issue.
V501 There are identical sub-expressions 'surfaceTwo->IsVRational()' to the left and to the right of the
'!=' operator. modelrefine.cpp 780
bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne,
const TopoDS_Face &faceTwo) const
{
....
if (surfaceOne->IsURational() != surfaceTwo->IsURational())
return false;
if (surfaceTwo->IsVRational() != surfaceTwo->IsVRational())//<=
return false;
if (surfaceOne->IsUPeriodic() != surfaceTwo->IsUPeriodic())
return false;
if (surfaceOne->IsVPeriodic() != surfaceTwo->IsVPeriodic())
return false;
if (surfaceOne->IsUClosed() != surfaceTwo->IsUClosed())
return false;
if (surfaceOne->IsVClosed() != surfaceTwo->IsVClosed())
return false;
if (surfaceOne->UDegree() != surfaceTwo->UDegree())
return false;
if (surfaceOne->VDegree() != surfaceTwo->VDegree())
return false;
....
}
Because of a tiny typo, there is the wrong variable "surfaceTwo" instead of "surfaceOne" found to the
left of the inequality operator. I can just recommend to copy-paste larger text blocks next time, though
we will speak of such samples a bit later, too =).
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 162, 164. taskpanelview.cpp 162
/// @cond DOXERR
void TaskPanelView::OnChange(....)
{
std::string temp;
if (Reason.Type == SelectionChanges::AddSelection) {
}
else if (Reason.Type == SelectionChanges::ClrSelection) {
}
else if (Reason.Type == SelectionChanges::RmvSelection) {
}
else if (Reason.Type == SelectionChanges::RmvSelection) {
}
}
Why are we discussing an incomplete function? Because this code will most likely face the same
troubles as in the next two samples.
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 1465, 1467. application.cpp 1465
pair<string, string> customSyntax(const string& s)
{
#if defined(FC_OS_MACOSX)
if (s.find("-psn_") == 0)
return make_pair(string("psn"), s.substr(5));
#endif
if (s.find("-display") == 0)
return make_pair(string("display"), string("null"));
else if (s.find("-style") == 0)
return make_pair(string("style"), string("null"));
....
else if (s.find("-button") == 0) //<==
return make_pair(string("button"), string("null")); //<==
else if (s.find("-button") == 0) //<==
return make_pair(string("button"), string("null")); //<==
else if (s.find("-btn") == 0)
return make_pair(string("btn"), string("null"));
....
}
Hopefully, the author forgot to fix only one copy-pasted line but still managed to fully implement the
code searching for all the necessary lines.
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 191, 199. blendernavigationstyle.cpp 191
SbBool BlenderNavigationStyle::processSoEvent(....)
{
....
else if (!press &&
(this->currentmode == NavigationStyle::DRAGGING)) { //<==
SbTime tmp = (ev->getTime() - this->centerTime);
float dci = (float)QApplication::....;
if (tmp.getValue() < dci) {
newmode = NavigationStyle::ZOOMING;
}
processed = TRUE;
}
else if (!press &&
(this->currentmode == NavigationStyle::DRAGGING)) { //<==
this->setViewing(false);
processed = TRUE;
}
....
}
And now there is what I suppose to be quite a serious bug for such an application. In modeling, a large
bulk of work has to be done through mouse navigation, but we've got a problem with that: the source
code under the last condition never gets control because the first condition is the same and is executed
first.
V523 The 'then' statement is equivalent to the 'else' statement. viewproviderfemmesh.cpp 695
inline void insEdgeVec(std::map<int,std::set<int> > &map,
int n1, int n2)
{
if(n1<n2)
map[n2].insert(n1);
else
map[n2].insert(n1);
};
Regardless of the condition, there is always only one branch to be executed. I guess what the
programmer really intended was the following:
inline void insEdgeVec(std::map<int,std::set<int> > &map,
int n1, int n2)
{
if(n1<n2)
map[n2].insert(n1);
else
map[n1].insert(n2);
};
Why is it exactly the last line that I have fixed? Well, probably you will like the following article on this
subject: The Last Line Effect. But it is also possible that the first line should be fixed instead - I'm not sure
:).
V570 The 'this->quat[3]' variable is assigned to itself. rotation.cpp 260
Rotation & Rotation::invert(void)
{
this->quat[0] = -this->quat[0];
this->quat[1] = -this->quat[1];
this->quat[2] = -this->quat[2];
this->quat[3] = this->quat[3]; //<==
return *this;
}
A bit more of "the last line effect" errors. What the analyzer didn't like about this code is the missing
minus sign in the last line. But I can't say for sure if it is a bug or not in this particular case; it may be that
the programmer, when implementing this conversion, just wanted to specifically emphasize that the
fourth component doesn't get changed.
V576 Incorrect format. A different number of actual arguments is expected while calling 'fprintf'
function. Expected: 2. Present: 3. memdebug.cpp 222
int __cdecl MemDebug::sAllocHook(....)
{
....
if ( pvData != NULL )
fprintf( logFile, " at %pn", pvData );
else
fprintf( logFile, "n", pvData ); //<==
....
}
This code doesn't make sense. If the pointer is null, you can simply print the character of the new string
without passing unused parameters to the function.
V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw
Exception(FOO); waypointpyimp.cpp 231
void WaypointPy::setTool(Py::Int arg)
{
if((int)arg.operator long() > 0)
getWaypointPtr()->Tool = (int)arg.operator long();
else
Base::Exception("negativ tool not allowed!");
}
An exception-type object is created in this code but not used. I guess the keyword "throw" is missing
here:
void WaypointPy::setTool(Py::Int arg)
{
if((int)arg.operator long() > 0)
getWaypointPtr()->Tool = (int)arg.operator long();
else
throw Base::Exception("negativ tool not allowed!");
}
A few more issues of this kind:
 V596 The object was created but it is not being used. The 'throw' keyword could be missing:
throw Exception(FOO); application.cpp 274
 V596 The object was created but it is not being used. The 'throw' keyword could be missing:
throw Exception(FOO); fileinfo.cpp 519
 V596 The object was created but it is not being used. The 'throw' keyword could be missing:
throw Exception(FOO); waypointpyimp.cpp 244
 V596 The object was created but it is not being used. The 'throw' keyword could be missing:
throw Exception(FOO); sketch.cpp 185
V599 The virtual destructor is not present, although the 'Curve' class contains virtual functions.
constraints.cpp 1442
class Curve
{
//a base class for all curve-based
//objects (line, circle/arc, ellipse/arc) //<==
public:
virtual DeriVector2 CalculateNormal(....) = 0;
virtual int PushOwnParams(VEC_pD &pvec) = 0;
virtual void ReconstructOnNewPvec (....) = 0;
virtual Curve* Copy() = 0;
};
class Line: public Curve //<==
{
public:
Line(){}
Point p1;
Point p2;
DeriVector2 CalculateNormal(Point &p, double* derivparam = 0);
virtual int PushOwnParams(VEC_pD &pvec);
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
virtual Line* Copy();
};
The use:
class ConstraintAngleViaPoint : public Constraint
{
private:
inline double* angle() { return pvec[0]; };
Curve* crv1; //<==
Curve* crv2; //<==
....
};
ConstraintAngleViaPoint::~ConstraintAngleViaPoint()
{
delete crv1; crv1 = 0; //<==
delete crv2; crv2 = 0; //<==
}
In the base class "Curve", virtual functions are declared but the destructor to be created as default is
not. And of course, it won't be virtual! It means that all the objects derived from this class won't be fully
clear if used when a pointer to the child class is saved into a pointer to the base class. As the comment
suggests, the base class has a lot of child ones, for example the "Line" class in the example above.
V655 The strings were concatenated but are not utilized. Consider inspecting the expression.
propertyitem.cpp 1013
void
PropertyVectorDistanceItem::setValue(const QVariant& variant)
{
if (!variant.canConvert<Base::Vector3d>())
return;
const Base::Vector3d& value = variant.value<Base::Vector3d>();
Base::Quantity q = Base::Quantity(value.x, Base::Unit::Length);
QString unit = QString::fromLatin1("('%1 %2'").arg(....;
q = Base::Quantity(value.y, Base::Unit::Length);
unit + QString::fromLatin1("'%1 %2'").arg(....; //<==
setPropertyValue(unit);
}
The analyzer has detected a meaningless string summation. If you look close, you will notice that the
programmer probably wanted to use the '+=' operator instead of simple addition. If so, this code would
make sense.
V595 The 'root' pointer was utilized before it was verified against nullptr. Check lines: 293, 294.
view3dinventorexamples.cpp 293
void LightManip(SoSeparator * root)
{
SoInput in;
in.setBuffer((void *)scenegraph, std::strlen(scenegraph));
SoSeparator * _root = SoDB::readAll( &in );
root->addChild(_root); //<==
if ( root == NULL ) return; //<==
root->ref();
....
}
One example of a pointer check in a wrong place, and all the rest issues are found in the following files:
 V595 The 'cam' pointer was utilized before it was verified against nullptr. Check lines: 1049,
1056. viewprovider.cpp 1049
 V595 The 'viewProviderRoot' pointer was utilized before it was verified against nullptr. Check
lines: 187, 188. taskcheckgeometry.cpp 187
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 209, 210.
viewproviderrobotobject.cpp 209
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 222, 223.
viewproviderrobotobject.cpp 222
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 235, 236.
viewproviderrobotobject.cpp 235
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 248, 249.
viewproviderrobotobject.cpp 248
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 261, 262.
viewproviderrobotobject.cpp 261
 V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 274, 275.
viewproviderrobotobject.cpp 274
 V595 The 'owner' pointer was utilized before it was verified against nullptr. Check lines: 991,
995. propertysheet.cpp 991
Open CASCADE library
V519 The 'myIndex[1]' variable is assigned values twice successively. Perhaps this is a mistake. Check
lines: 60, 61. brepmesh_pairofindex.hxx 61
//! Prepends index to the pair.
inline void Prepend(const Standard_Integer theIndex)
{
if (myIndex[1] >= 0)
Standard_OutOfRange::Raise ("BRepMesh_PairOfIndex....");
myIndex[1] = myIndex[0];
myIndex[1] = theIndex;
}
In this sample, the programmer overwrites the value of the 'myIndex' array's item having index 1. I think
the code was actually meant to look like this:
myIndex[1] = myIndex[0];
myIndex[0] = theIndex;
SALOME Smesh Module
V501 There are identical sub-expressions '0 <= theParamsHint.Y()' to the left and to the right of the '&&'
operator. smesh_block.cpp 661
bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint,
gp_XYZ& theParams,
const int theShapeID,
const gp_XYZ& theParamsHint)
{
....
bool hasHint =
( 0 <= theParamsHint.X() && theParamsHint.X() <= 1 &&
0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 &&
0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 ); //<==
....
}
A check with .Z() is obviously missing here. And there is such a function in the class indeed: the class
itself is even named "gp_XYZ".
V503 This is a nonsensical comparison: pointer < 0. driverdat_r_smds_mesh.cpp 55
Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform()
{
....
FILE* aFileId = fopen(file2Read, "r");
if (aFileId < 0) {
fprintf(stderr, "....", file2Read);
return DRS_FAIL;
}
....
}
A pointer can't be less than zero. Even in the plainest examples with the fopen() function, that you can
find in books and on the Internet, operators == or != are used to compare a function value to NULL.
I was wondering at how code like that could have appeared at all but my co-worker Andrey Karpov told
me that such things often happen when refactoring code where the open() function was previously
used. This function returns -1 in this case, so the comparison <0 is quite legal. In the course of program
refactoring or porting, programmers replace this function with fopen() but forget to fix the check.
Another issue of this kind:
 V503 This is a nonsensical comparison: pointer < 0. driverdat_w_smds_mesh.cpp 41
V562 It's odd to compare a bool type value with a value of 12: !myType == SMESHDS_MoveNode.
smeshds_command.cpp 75
class SMESHDS_EXPORT SMESHDS_Command
{
....
private:
SMESHDS_CommandType myType;
....
};
enum SMESHDS_CommandType {
SMESHDS_AddNode,
SMESHDS_AddEdge,
SMESHDS_AddTriangle,
SMESHDS_AddQuadrangle,
....
};
void SMESHDS_Command::MoveNode(....)
{
if (!myType == SMESHDS_MoveNode) //<==
{
MESSAGE("SMESHDS_Command::MoveNode : Bad Type");
return;
}
....
}
Here we have an enumeration named "SMESHDS_CommandType" containing a lot of constants. The
analyzer has detected an incorrect check: a variable of this type is compared to a named constant, but
what for is the negation symbol?? I bet the check should actually look like this:
if (myType != SMESHDS_MoveNode) //<==
{
MESSAGE("SMESHDS_Command::MoveNode : Bad Type");
return;
}
Unfortunately, this check with message printing was copied to 20 other fragments. See the full list:
FreeCAD_V562.txt.
V567 Undefined behavior. The order of argument evaluation is not defined for 'splice' function. The
'outerBndPos' variable is modified while being used twice between sequence points. smesh_pattern.cpp
4260
void SMESH_Pattern::arrangeBoundaries (....)
{
....
if ( outerBndPos != boundaryList.begin() )
boundaryList.splice( boundaryList.begin(),
boundaryList,
outerBndPos, //<==
++outerBndPos ); //<==
}
The analyzer is actually not quite correct about this code. There's no undefined behavior here, but there
is an error, so the warning was displayed not in vain. The C++ standard doesn't put any restrictions on
the evaluation order of a function's actual arguments. So it is unknown which values will be passed into
the function.
Let me clarify on it by a simple example:
int a = 5;
printf("%i, %i", a, ++a);
This code may print both "5, 6" and "6, 6", which depends on the compiler and its settings.
V663 Infinite loop is possible. The 'cin.eof()' condition is insufficient to break from the loop. Consider
adding the 'cin.fail()' function call to the conditional expression. unv_utilities.hxx 63
inline bool beginning_of_dataset(....)
{
....
while( ((olds != "-1") || (news == "-1") ) && !in_file.eof() ){
olds = news;
in_file >> news;
}
....
}
When working with the 'std::istream' class, it's not enough to call the function 'eof()' to terminate the
loop. If a failure occurs when reading the data, calling the 'eof()' function will always return 'false'. To
terminate the loop in this case, we need an additional check for the value returned by the function
'fail()'.
V595 The 'anElem' pointer was utilized before it was verified against nullptr. Check lines: 1950, 1951.
smesh_controls.cpp 1950
bool ElemGeomType::IsSatisfy( long theId )
{
if (!myMesh) return false;
const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
const SMDSAbs_ElementType anElemType = anElem->GetType();
if (!anElem || (myType != SMDSAbs_All && anElemType != myType))
return false;
const int aNbNode = anElem->NbNodes();
....
}
The "anElem" pointer is dereferenced one line earlier than being checked for being valid.
Here are a few other similar issues in this project:
 V595 The 'elem' pointer was utilized before it was verified against nullptr. Check lines: 3989,
3990. smesh_mesheditor.cpp 3989
 V595 The 'anOldGrp' pointer was utilized before it was verified against nullptr. Check lines:
1488, 1489. smesh_mesh.cpp 1488
 V595 The 'aFaceSubmesh' pointer was utilized before it was verified against nullptr. Check lines:
496, 501. smesh_pattern.cpp 496
Boost C++ Libraries
V567 Undefined behavior. The 'this->n_' variable is modified while being used twice between sequence
points. regex_token_iterator.hpp 63
template<typename BidiIter>
struct regex_token_iterator_impl
: counted_base<regex_token_iterator_impl<BidiIter> >
{
....
if(0 != (++this->n_ %= (int)this->subs_.size()) || ....
{
....
}
....
}
It is unknown which of the operands of the %= operator will be evaluated first. Therefore, the
expression being correct or incorrect depends on pure chance.
Conclusion
Try and integrate static analyzers into the development process to run regular analysis of your projects
and third-party libraries they use. It will help you save plenty of time when writing new code and
maintaining old one.

More Related Content

What's hot

Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesPVS-Studio
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016PVS-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
 
Critical errors in CryEngine V code
Critical errors in CryEngine V codeCritical errors in CryEngine V code
Critical errors in CryEngine V codePVS-Studio
 
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
 
The First C# Project Analyzed
The First C# Project AnalyzedThe First C# Project Analyzed
The First C# Project AnalyzedPVS-Studio
 
A Spin-off: CryEngine 3 SDK Checked with CppCat
A Spin-off: CryEngine 3 SDK Checked with CppCatA Spin-off: CryEngine 3 SDK Checked with CppCat
A Spin-off: CryEngine 3 SDK Checked with CppCatAndrey Karpov
 
Checking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xChecking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xAndrey Karpov
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckAndrey Karpov
 
CppCat Static Analyzer Review
CppCat Static Analyzer ReviewCppCat Static Analyzer Review
CppCat Static Analyzer ReviewAndrey Karpov
 
Sony C#/.NET component set analysis
Sony C#/.NET component set analysisSony C#/.NET component set analysis
Sony C#/.NET component set analysisPVS-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 projectPVS-Studio
 
Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor
Waiting for the Linux-version: Checking the Code of Inkscape Graphics EditorWaiting for the Linux-version: Checking the Code of Inkscape Graphics Editor
Waiting for the Linux-version: Checking the Code of Inkscape Graphics EditorPVS-Studio
 
.gradle 파일 정독해보기
.gradle 파일 정독해보기.gradle 파일 정독해보기
.gradle 파일 정독해보기경주 전
 
Checking Notepad++: five years later
Checking Notepad++: five years laterChecking Notepad++: five years later
Checking Notepad++: five years laterPVS-Studio
 
PVS-Studio vs Clang
PVS-Studio vs ClangPVS-Studio vs Clang
PVS-Studio vs ClangPVS-Studio
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioAndrey Karpov
 
Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016PVS-Studio
 
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
 

What's hot (20)

Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 libraries
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016
 
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
 
Critical errors in CryEngine V code
Critical errors in CryEngine V codeCritical errors in CryEngine V code
Critical errors in CryEngine V code
 
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
 
The First C# Project Analyzed
The First C# Project AnalyzedThe First C# Project Analyzed
The First C# Project Analyzed
 
C++ Core Guidelines
C++ Core GuidelinesC++ Core Guidelines
C++ Core Guidelines
 
A Spin-off: CryEngine 3 SDK Checked with CppCat
A Spin-off: CryEngine 3 SDK Checked with CppCatA Spin-off: CryEngine 3 SDK Checked with CppCat
A Spin-off: CryEngine 3 SDK Checked with CppCat
 
Checking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xChecking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-x
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after Cppcheck
 
CppCat Static Analyzer Review
CppCat Static Analyzer ReviewCppCat Static Analyzer Review
CppCat Static Analyzer Review
 
Sony C#/.NET component set analysis
Sony C#/.NET component set analysisSony C#/.NET component set analysis
Sony C#/.NET component set analysis
 
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
 
Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor
Waiting for the Linux-version: Checking the Code of Inkscape Graphics EditorWaiting for the Linux-version: Checking the Code of Inkscape Graphics Editor
Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor
 
.gradle 파일 정독해보기
.gradle 파일 정독해보기.gradle 파일 정독해보기
.gradle 파일 정독해보기
 
Checking Notepad++: five years later
Checking Notepad++: five years laterChecking Notepad++: five years later
Checking Notepad++: five years later
 
PVS-Studio vs Clang
PVS-Studio vs ClangPVS-Studio vs Clang
PVS-Studio vs Clang
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-Studio
 
Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016
 
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
 

Viewers also liked

Il nuovo ISEE "sotto scacco"
Il nuovo ISEE "sotto scacco"Il nuovo ISEE "sotto scacco"
Il nuovo ISEE "sotto scacco"Claudio Goatelli
 
Cv (xi' an fantasy)
Cv (xi' an fantasy)Cv (xi' an fantasy)
Cv (xi' an fantasy)dlf226
 
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowania
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowaniaPartnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowania
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowaniaFRSE
 
Su desarrollo está en peligro. Actúa
Su desarrollo está en peligro. ActúaSu desarrollo está en peligro. Actúa
Su desarrollo está en peligro. ActúaVictoriano Portela
 

Viewers also liked (7)

ICPAK Registration
ICPAK RegistrationICPAK Registration
ICPAK Registration
 
Il nuovo ISEE "sotto scacco"
Il nuovo ISEE "sotto scacco"Il nuovo ISEE "sotto scacco"
Il nuovo ISEE "sotto scacco"
 
d50e37_d25a958f90b241b5ac7f25c3e98f271b
d50e37_d25a958f90b241b5ac7f25c3e98f271bd50e37_d25a958f90b241b5ac7f25c3e98f271b
d50e37_d25a958f90b241b5ac7f25c3e98f271b
 
Cv (xi' an fantasy)
Cv (xi' an fantasy)Cv (xi' an fantasy)
Cv (xi' an fantasy)
 
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowania
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowaniaPartnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowania
Partnerstwa Strategiczne w szkolnictwie wyższym - zasady finansowania
 
Auditoria int
Auditoria intAuditoria int
Auditoria int
 
Su desarrollo está en peligro. Actúa
Su desarrollo está en peligro. ActúaSu desarrollo está en peligro. Actúa
Su desarrollo está en peligro. Actúa
 

Similar to Analyzing FreeCAD's Source Code and Its "Sick" Dependencies

Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...Andrey Karpov
 
Re-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportRe-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportPVS-Studio
 
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-Studio
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-StudioArcheology for Entertainment, or Checking Microsoft Word 1.1a with PVS-Studio
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-StudioAndrey Karpov
 
Firefox Easily Analyzed by PVS-Studio Standalone
Firefox Easily Analyzed by PVS-Studio StandaloneFirefox Easily Analyzed by PVS-Studio Standalone
Firefox Easily Analyzed by PVS-Studio StandaloneAndrey Karpov
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-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
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codeAndrey Karpov
 
PVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd CheckPVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd CheckAndrey Karpov
 
100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects 100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects Andrey Karpov
 
Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopPVS-Studio
 
Checking the Open-Source Multi Theft Auto Game
Checking the Open-Source Multi Theft Auto GameChecking the Open-Source Multi Theft Auto Game
Checking the Open-Source Multi Theft Auto GameAndrey Karpov
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in DoxygenPVS-Studio
 
Intel IPP Samples for Windows - error correction
Intel IPP Samples for Windows - error correctionIntel IPP Samples for Windows - error correction
Intel IPP Samples for Windows - error correctionPVS-Studio
 
Analysis of Godot Engine's Source Code
Analysis of Godot Engine's Source CodeAnalysis of Godot Engine's Source Code
Analysis of Godot Engine's Source CodePVS-Studio
 
A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)Andrey Karpov
 
Copy-Paste and Muons
Copy-Paste and MuonsCopy-Paste and Muons
Copy-Paste and MuonsAndrey Karpov
 
GDB - a tough nut to crack: only a few bugs found by PVS-Studio
GDB - a tough nut to crack: only a few bugs found by PVS-StudioGDB - a tough nut to crack: only a few bugs found by PVS-Studio
GDB - a tough nut to crack: only a few bugs found by PVS-StudioPVS-Studio
 
Discussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsDiscussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsPVS-Studio
 
The Ultimate Question of Programming, Refactoring, and Everything
The Ultimate Question of Programming, Refactoring, and EverythingThe Ultimate Question of Programming, Refactoring, and Everything
The Ultimate Question of Programming, Refactoring, and EverythingAndrey Karpov
 

Similar to Analyzing FreeCAD's Source Code and Its "Sick" Dependencies (20)

Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...
 
Re-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportRe-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large report
 
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-Studio
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-StudioArcheology for Entertainment, or Checking Microsoft Word 1.1a with PVS-Studio
Archeology for Entertainment, or Checking Microsoft Word 1.1a with PVS-Studio
 
Firefox Easily Analyzed by PVS-Studio Standalone
Firefox Easily Analyzed by PVS-Studio StandaloneFirefox Easily Analyzed by PVS-Studio Standalone
Firefox Easily Analyzed by PVS-Studio Standalone
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
PVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd CheckPVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd Check
 
100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects 100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects
 
Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelop
 
Checking the Open-Source Multi Theft Auto Game
Checking the Open-Source Multi Theft Auto GameChecking the Open-Source Multi Theft Auto Game
Checking the Open-Source Multi Theft Auto Game
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in Doxygen
 
Intel IPP Samples for Windows - error correction
Intel IPP Samples for Windows - error correctionIntel IPP Samples for Windows - error correction
Intel IPP Samples for Windows - error correction
 
Analysis of Godot Engine's Source Code
Analysis of Godot Engine's Source CodeAnalysis of Godot Engine's Source Code
Analysis of Godot Engine's Source Code
 
A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)
 
Copy-Paste and Muons
Copy-Paste and MuonsCopy-Paste and Muons
Copy-Paste and Muons
 
GDB - a tough nut to crack: only a few bugs found by PVS-Studio
GDB - a tough nut to crack: only a few bugs found by PVS-StudioGDB - a tough nut to crack: only a few bugs found by PVS-Studio
GDB - a tough nut to crack: only a few bugs found by PVS-Studio
 
Checking VirtualDub
Checking VirtualDubChecking VirtualDub
Checking VirtualDub
 
Discussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsDiscussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source Components
 
The Ultimate Question of Programming, Refactoring, and Everything
The Ultimate Question of Programming, Refactoring, and EverythingThe Ultimate Question of Programming, Refactoring, and Everything
The Ultimate Question of Programming, Refactoring, and Everything
 

Recently uploaded

ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
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
 
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
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
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
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
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
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
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
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
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
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
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
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 

Recently uploaded (20)

ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
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
 
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
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
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
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
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
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
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...
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
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)
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 

Analyzing FreeCAD's Source Code and Its "Sick" Dependencies

  • 1. Analyzing FreeCAD's Source Code and Its "Sick" Dependencies Author: Svyatoslav Razmyslov Date: 30.04.2015 This article was initially meant as a review of bugs found in the FreeCAD open-source project but eventually took a bit different direction. It happened because a considerable portion of the warnings had been generated for the third-party libraries employed by the project. Extensive use of third-party libraries in software development is highly beneficial, especially in the open-source software domain. And bugs found in these libraries are no good reason to reject them. But we still should keep in mind that third-party code we use in our projects may contain bugs, so we must be prepared to meet and, if possible, fix them, thus improving the libraries. Introduction FreeCAD is a free and open-source general purpose parametric 3D CAD modeler allowing creating 3D models and drawing their projections. FreeCAD's developer Juergen Riegel, working at DaimlerChrysler corporation, positions his program as the first free mechanical engineering and design tool. There is a
  • 2. well-known issue in a number of related areas that deals with the lack of a full-fledged open-source CAD application, and the FreeCAD project is just aiming to become one. So let's check its source code with PVS-Studio to help this open-source project become a bit better. I bet you encounter "glitches" in various modelers every now and then when you can't hit a certain point or align a line which is constantly shifting one pixel away from the desired position. All of that may be just a result of some typos in the source code. What's wrong with PVS-Studio?! The FreeCAD project is cross-platform and there is a very good collection of documents on building it available at their site. It wasn't difficult to get project files for Visual Studio Community 2013 for further analysis by the PVS-Studio plugin installed on my computer. But for some reason, the check wouldn't go well at first... As I found out, the cause of the analyzer's internal error had been the presence of a binary sequence in the preprocessed text *.i file. The analyzer can sort out issues like that but it was something unfamiliar this time. The trouble was with one of the lines in the source-file compilation parameters. /FI"Drawing.dir/Debug//Drawing_d.pch" The /FI (Name Forced Include File) compilation switch, just like the #include directive, serves for including text header files. But in this case, the programmers are trying to include a file with binary data. It even manages to compile somehow - I guess Visual C++ simply ignores it.
  • 3. But if we try to preprocess those files, instead of compiling them, Visual C++ will display an error message. However, the Clang compiler, used in PVS-Studio by default, included the binary file into the *.i file without much thinking. PVS-Studio never expected such a trap and went crazy. To make it clearer, here's a fragment of the file preprocessed by Clang: I carefully checked the project without that switch but the authors ought to know that they have an error there. FreeCAD The first bug samples to be discussed result from a very well-known issue. V501 There are identical sub-expressions 'surfaceTwo->IsVRational()' to the left and to the right of the '!=' operator. modelrefine.cpp 780 bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo) const { .... if (surfaceOne->IsURational() != surfaceTwo->IsURational()) return false; if (surfaceTwo->IsVRational() != surfaceTwo->IsVRational())//<= return false; if (surfaceOne->IsUPeriodic() != surfaceTwo->IsUPeriodic()) return false; if (surfaceOne->IsVPeriodic() != surfaceTwo->IsVPeriodic()) return false; if (surfaceOne->IsUClosed() != surfaceTwo->IsUClosed()) return false; if (surfaceOne->IsVClosed() != surfaceTwo->IsVClosed()) return false; if (surfaceOne->UDegree() != surfaceTwo->UDegree())
  • 4. return false; if (surfaceOne->VDegree() != surfaceTwo->VDegree()) return false; .... } Because of a tiny typo, there is the wrong variable "surfaceTwo" instead of "surfaceOne" found to the left of the inequality operator. I can just recommend to copy-paste larger text blocks next time, though we will speak of such samples a bit later, too =). V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 162, 164. taskpanelview.cpp 162 /// @cond DOXERR void TaskPanelView::OnChange(....) { std::string temp; if (Reason.Type == SelectionChanges::AddSelection) { } else if (Reason.Type == SelectionChanges::ClrSelection) { } else if (Reason.Type == SelectionChanges::RmvSelection) { } else if (Reason.Type == SelectionChanges::RmvSelection) { } } Why are we discussing an incomplete function? Because this code will most likely face the same troubles as in the next two samples. V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 1465, 1467. application.cpp 1465 pair<string, string> customSyntax(const string& s) { #if defined(FC_OS_MACOSX) if (s.find("-psn_") == 0) return make_pair(string("psn"), s.substr(5)); #endif if (s.find("-display") == 0) return make_pair(string("display"), string("null")); else if (s.find("-style") == 0) return make_pair(string("style"), string("null")); .... else if (s.find("-button") == 0) //<== return make_pair(string("button"), string("null")); //<== else if (s.find("-button") == 0) //<== return make_pair(string("button"), string("null")); //<== else if (s.find("-btn") == 0) return make_pair(string("btn"), string("null")); .... } Hopefully, the author forgot to fix only one copy-pasted line but still managed to fully implement the code searching for all the necessary lines.
  • 5. V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 191, 199. blendernavigationstyle.cpp 191 SbBool BlenderNavigationStyle::processSoEvent(....) { .... else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { //<== SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::....; if (tmp.getValue() < dci) { newmode = NavigationStyle::ZOOMING; } processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { //<== this->setViewing(false); processed = TRUE; } .... } And now there is what I suppose to be quite a serious bug for such an application. In modeling, a large bulk of work has to be done through mouse navigation, but we've got a problem with that: the source code under the last condition never gets control because the first condition is the same and is executed first. V523 The 'then' statement is equivalent to the 'else' statement. viewproviderfemmesh.cpp 695 inline void insEdgeVec(std::map<int,std::set<int> > &map, int n1, int n2) { if(n1<n2) map[n2].insert(n1); else map[n2].insert(n1); }; Regardless of the condition, there is always only one branch to be executed. I guess what the programmer really intended was the following: inline void insEdgeVec(std::map<int,std::set<int> > &map, int n1, int n2)
  • 6. { if(n1<n2) map[n2].insert(n1); else map[n1].insert(n2); }; Why is it exactly the last line that I have fixed? Well, probably you will like the following article on this subject: The Last Line Effect. But it is also possible that the first line should be fixed instead - I'm not sure :). V570 The 'this->quat[3]' variable is assigned to itself. rotation.cpp 260 Rotation & Rotation::invert(void) { this->quat[0] = -this->quat[0]; this->quat[1] = -this->quat[1]; this->quat[2] = -this->quat[2]; this->quat[3] = this->quat[3]; //<== return *this; } A bit more of "the last line effect" errors. What the analyzer didn't like about this code is the missing minus sign in the last line. But I can't say for sure if it is a bug or not in this particular case; it may be that the programmer, when implementing this conversion, just wanted to specifically emphasize that the fourth component doesn't get changed. V576 Incorrect format. A different number of actual arguments is expected while calling 'fprintf' function. Expected: 2. Present: 3. memdebug.cpp 222 int __cdecl MemDebug::sAllocHook(....) { .... if ( pvData != NULL ) fprintf( logFile, " at %pn", pvData ); else fprintf( logFile, "n", pvData ); //<== .... } This code doesn't make sense. If the pointer is null, you can simply print the character of the new string without passing unused parameters to the function. V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw Exception(FOO); waypointpyimp.cpp 231
  • 7. void WaypointPy::setTool(Py::Int arg) { if((int)arg.operator long() > 0) getWaypointPtr()->Tool = (int)arg.operator long(); else Base::Exception("negativ tool not allowed!"); } An exception-type object is created in this code but not used. I guess the keyword "throw" is missing here: void WaypointPy::setTool(Py::Int arg) { if((int)arg.operator long() > 0) getWaypointPtr()->Tool = (int)arg.operator long(); else throw Base::Exception("negativ tool not allowed!"); } A few more issues of this kind:  V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw Exception(FOO); application.cpp 274  V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw Exception(FOO); fileinfo.cpp 519  V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw Exception(FOO); waypointpyimp.cpp 244  V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw Exception(FOO); sketch.cpp 185 V599 The virtual destructor is not present, although the 'Curve' class contains virtual functions. constraints.cpp 1442 class Curve { //a base class for all curve-based //objects (line, circle/arc, ellipse/arc) //<== public: virtual DeriVector2 CalculateNormal(....) = 0;
  • 8. virtual int PushOwnParams(VEC_pD &pvec) = 0; virtual void ReconstructOnNewPvec (....) = 0; virtual Curve* Copy() = 0; }; class Line: public Curve //<== { public: Line(){} Point p1; Point p2; DeriVector2 CalculateNormal(Point &p, double* derivparam = 0); virtual int PushOwnParams(VEC_pD &pvec); virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt); virtual Line* Copy(); }; The use: class ConstraintAngleViaPoint : public Constraint { private: inline double* angle() { return pvec[0]; }; Curve* crv1; //<== Curve* crv2; //<== .... }; ConstraintAngleViaPoint::~ConstraintAngleViaPoint() { delete crv1; crv1 = 0; //<== delete crv2; crv2 = 0; //<== } In the base class "Curve", virtual functions are declared but the destructor to be created as default is not. And of course, it won't be virtual! It means that all the objects derived from this class won't be fully clear if used when a pointer to the child class is saved into a pointer to the base class. As the comment suggests, the base class has a lot of child ones, for example the "Line" class in the example above. V655 The strings were concatenated but are not utilized. Consider inspecting the expression. propertyitem.cpp 1013 void PropertyVectorDistanceItem::setValue(const QVariant& variant) { if (!variant.canConvert<Base::Vector3d>()) return; const Base::Vector3d& value = variant.value<Base::Vector3d>(); Base::Quantity q = Base::Quantity(value.x, Base::Unit::Length); QString unit = QString::fromLatin1("('%1 %2'").arg(....; q = Base::Quantity(value.y, Base::Unit::Length); unit + QString::fromLatin1("'%1 %2'").arg(....; //<==
  • 9. setPropertyValue(unit); } The analyzer has detected a meaningless string summation. If you look close, you will notice that the programmer probably wanted to use the '+=' operator instead of simple addition. If so, this code would make sense. V595 The 'root' pointer was utilized before it was verified against nullptr. Check lines: 293, 294. view3dinventorexamples.cpp 293 void LightManip(SoSeparator * root) { SoInput in; in.setBuffer((void *)scenegraph, std::strlen(scenegraph)); SoSeparator * _root = SoDB::readAll( &in ); root->addChild(_root); //<== if ( root == NULL ) return; //<== root->ref(); .... } One example of a pointer check in a wrong place, and all the rest issues are found in the following files:  V595 The 'cam' pointer was utilized before it was verified against nullptr. Check lines: 1049, 1056. viewprovider.cpp 1049  V595 The 'viewProviderRoot' pointer was utilized before it was verified against nullptr. Check lines: 187, 188. taskcheckgeometry.cpp 187  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 209, 210. viewproviderrobotobject.cpp 209  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 222, 223. viewproviderrobotobject.cpp 222  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 235, 236. viewproviderrobotobject.cpp 235  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 248, 249. viewproviderrobotobject.cpp 248  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 261, 262. viewproviderrobotobject.cpp 261  V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 274, 275. viewproviderrobotobject.cpp 274  V595 The 'owner' pointer was utilized before it was verified against nullptr. Check lines: 991, 995. propertysheet.cpp 991 Open CASCADE library V519 The 'myIndex[1]' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 60, 61. brepmesh_pairofindex.hxx 61 //! Prepends index to the pair. inline void Prepend(const Standard_Integer theIndex) { if (myIndex[1] >= 0) Standard_OutOfRange::Raise ("BRepMesh_PairOfIndex....");
  • 10. myIndex[1] = myIndex[0]; myIndex[1] = theIndex; } In this sample, the programmer overwrites the value of the 'myIndex' array's item having index 1. I think the code was actually meant to look like this: myIndex[1] = myIndex[0]; myIndex[0] = theIndex; SALOME Smesh Module V501 There are identical sub-expressions '0 <= theParamsHint.Y()' to the left and to the right of the '&&' operator. smesh_block.cpp 661 bool SMESH_Block::ComputeParameters(const gp_Pnt& thePoint, gp_XYZ& theParams, const int theShapeID, const gp_XYZ& theParamsHint) { .... bool hasHint = ( 0 <= theParamsHint.X() && theParamsHint.X() <= 1 && 0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 && 0 <= theParamsHint.Y() && theParamsHint.Y() <= 1 ); //<== .... } A check with .Z() is obviously missing here. And there is such a function in the class indeed: the class itself is even named "gp_XYZ". V503 This is a nonsensical comparison: pointer < 0. driverdat_r_smds_mesh.cpp 55 Driver_Mesh::Status DriverDAT_R_SMDS_Mesh::Perform() { .... FILE* aFileId = fopen(file2Read, "r"); if (aFileId < 0) { fprintf(stderr, "....", file2Read); return DRS_FAIL; } .... } A pointer can't be less than zero. Even in the plainest examples with the fopen() function, that you can find in books and on the Internet, operators == or != are used to compare a function value to NULL. I was wondering at how code like that could have appeared at all but my co-worker Andrey Karpov told me that such things often happen when refactoring code where the open() function was previously used. This function returns -1 in this case, so the comparison <0 is quite legal. In the course of program refactoring or porting, programmers replace this function with fopen() but forget to fix the check. Another issue of this kind:  V503 This is a nonsensical comparison: pointer < 0. driverdat_w_smds_mesh.cpp 41
  • 11. V562 It's odd to compare a bool type value with a value of 12: !myType == SMESHDS_MoveNode. smeshds_command.cpp 75 class SMESHDS_EXPORT SMESHDS_Command { .... private: SMESHDS_CommandType myType; .... }; enum SMESHDS_CommandType { SMESHDS_AddNode, SMESHDS_AddEdge, SMESHDS_AddTriangle, SMESHDS_AddQuadrangle, .... }; void SMESHDS_Command::MoveNode(....) { if (!myType == SMESHDS_MoveNode) //<== { MESSAGE("SMESHDS_Command::MoveNode : Bad Type"); return; } .... } Here we have an enumeration named "SMESHDS_CommandType" containing a lot of constants. The analyzer has detected an incorrect check: a variable of this type is compared to a named constant, but what for is the negation symbol?? I bet the check should actually look like this: if (myType != SMESHDS_MoveNode) //<== { MESSAGE("SMESHDS_Command::MoveNode : Bad Type"); return; } Unfortunately, this check with message printing was copied to 20 other fragments. See the full list: FreeCAD_V562.txt. V567 Undefined behavior. The order of argument evaluation is not defined for 'splice' function. The 'outerBndPos' variable is modified while being used twice between sequence points. smesh_pattern.cpp 4260 void SMESH_Pattern::arrangeBoundaries (....) { .... if ( outerBndPos != boundaryList.begin() ) boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, //<== ++outerBndPos ); //<== }
  • 12. The analyzer is actually not quite correct about this code. There's no undefined behavior here, but there is an error, so the warning was displayed not in vain. The C++ standard doesn't put any restrictions on the evaluation order of a function's actual arguments. So it is unknown which values will be passed into the function. Let me clarify on it by a simple example: int a = 5; printf("%i, %i", a, ++a); This code may print both "5, 6" and "6, 6", which depends on the compiler and its settings. V663 Infinite loop is possible. The 'cin.eof()' condition is insufficient to break from the loop. Consider adding the 'cin.fail()' function call to the conditional expression. unv_utilities.hxx 63 inline bool beginning_of_dataset(....) { .... while( ((olds != "-1") || (news == "-1") ) && !in_file.eof() ){ olds = news; in_file >> news; } .... } When working with the 'std::istream' class, it's not enough to call the function 'eof()' to terminate the loop. If a failure occurs when reading the data, calling the 'eof()' function will always return 'false'. To terminate the loop in this case, we need an additional check for the value returned by the function 'fail()'. V595 The 'anElem' pointer was utilized before it was verified against nullptr. Check lines: 1950, 1951. smesh_controls.cpp 1950 bool ElemGeomType::IsSatisfy( long theId ) { if (!myMesh) return false; const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); const SMDSAbs_ElementType anElemType = anElem->GetType(); if (!anElem || (myType != SMDSAbs_All && anElemType != myType)) return false; const int aNbNode = anElem->NbNodes(); .... } The "anElem" pointer is dereferenced one line earlier than being checked for being valid. Here are a few other similar issues in this project:  V595 The 'elem' pointer was utilized before it was verified against nullptr. Check lines: 3989, 3990. smesh_mesheditor.cpp 3989  V595 The 'anOldGrp' pointer was utilized before it was verified against nullptr. Check lines: 1488, 1489. smesh_mesh.cpp 1488  V595 The 'aFaceSubmesh' pointer was utilized before it was verified against nullptr. Check lines: 496, 501. smesh_pattern.cpp 496
  • 13. Boost C++ Libraries V567 Undefined behavior. The 'this->n_' variable is modified while being used twice between sequence points. regex_token_iterator.hpp 63 template<typename BidiIter> struct regex_token_iterator_impl : counted_base<regex_token_iterator_impl<BidiIter> > { .... if(0 != (++this->n_ %= (int)this->subs_.size()) || .... { .... } .... } It is unknown which of the operands of the %= operator will be evaluated first. Therefore, the expression being correct or incorrect depends on pure chance. Conclusion Try and integrate static analyzers into the development process to run regular analysis of your projects and third-party libraries they use. It will help you save plenty of time when writing new code and maintaining old one.