SlideShare a Scribd company logo
Waiting for the Linux-version: Checking
the Code of Inkscape Graphics Editor
Author: Egor Bredikhin
Date: 15.08.2016
In this article, I talk about the analysis results for another popular open-source project, vector graphics
editor Inkscape 0.92. The project has been developing for over 12 years now and provides a large
number of features to work with various vector-image formats. Over this time, its code base has grown
up to 600 thousand lines of code, and now is the right time to check it with PVS-Studio static analyzer.
Introduction
Inkscape is a cross-platform open-source vector graphics editor. It is widely used both by amateur and
professional designers all over the world to create images, icons, logos, charts, maps, and web-graphics.
Inkscape has become one of the most popular tools in this field. The project was founded in 2003 as a
fork of Sodipodi project and is still developing. See the official website for more information about
Inkscape.
For this analysis, we used the latest version of Inkscape, 0.92, whose source codes can be downloaded
from the GitHub repository, and static analyzer PVS-Studio 6.07, which can be downloaded here. Note
that at the moment of writing this article, only the Windows-version of PVS-Studio is available. The
situation, however, will improve soon, and you can already apply for beta testing of the Linux-version.
For details see the article "PVS-Studio confesses its love for Linux".
Well, let's get back to errors. Note that I picked only the most interesting warnings to discuss in this
article. To do a more thorough analysis on their own, the project authors should contact us so that we
could send them a temporary PVS-Studio key and the analysis report. Since there is no public version of
PVS-Studio yet, they can use the PVS-Studio Standalone tool, which runs under Windows, to view the
report. True, it's inconvenient, but please be patient: the big day of the Linux-version's release is coming
soon.
Analysis results
Testing a pointer for null after new
PVS-Studio diagnostic message: V668 There is no sense in testing the 'outputBuf' pointer against null, as
the memory was allocated using the 'new' operator. The exception will be generated in the case of
memory allocation error. gzipstream.cpp 180
bool GzipInputStream::load()
{
....
outputBuf = new unsigned char [OUT_SIZE];
if ( !outputBuf ) { // <=
delete[] srcBuf;
srcBuf = NULL;
return false;
}
....
}
As specified by the modern C++ standard, when memory can't be allocated, the new operator throws a
std::bad_alloc() exception instead of returning nullptr. If the system fails to allocate storage, an
exception is thrown and the function stops executing. The program, therefore, will never enter the block
of code following the condition.
In this particular case, the error may result in a memory leak. The most obvious solution is to use the try
{....} catch(const std::bad_alloc &) {....} block, but a much better way is to use smart pointers instead of
releasing the storage explicitly.
Other similar pointer checks:
 V668 There is no sense in testing the 'destbuf' pointer against null, as the memory was allocated
using the 'new' operator. The exception will be generated in the case of memory allocation
error. gzipstream.cpp 397
 V668 There is no sense in testing the 'srcBuf' pointer against null, as the memory was allocated
using the 'new' operator. The exception will be generated in the case of memory allocation
error. gzipstream.cpp 175
 V668 There is no sense in testing the 'oldcurve' pointer against null, as the memory was
allocated using the 'new' operator. The exception will be generated in the case of memory
allocation error. sp-lpe-item.cpp 719
Comparing this with zero
PVS-Studio diagnostic message: V704 '!this' expression in conditional statements should be avoided -
this expression is always false on newer compilers, because 'this' pointer can never be NULL. sp-lpe-
item.cpp 213
bool SPLPEItem::performPathEffect(....) {
if (!this) {
return false;
}
....
}
As specified by the modern C++ standard, the this pointer can never be null. Comparing this with zero
often results in unexpected errors. For details see the description of diagnostic V704.
Another case of testing this for nullptr:
 V704 'this' expression in conditional statements should be avoided - this expression is always
true on newer compilers, because 'this' pointer can never be NULL. sp-paint-server.cpp 42
Dangerous parameter redefinition
PVS-Studio diagnostic message: V581 The conditional expressions of the 'if' operators situated
alongside each other are identical. Check lines: 1046, 1051. sp-mesh-array.cpp 1051
void SPMeshNodeArray::create( ...., Geom::OptRect bbox ) // <=
{
....
if( !bbox ) {
std::cout << "SPMeshNodeArray::create(): bbox empty"
<< std::endl;
Geom::OptRect bbox = item->geometricBounds(); // <=
}
if( !bbox ) { // <=
std::cout << "ERROR: No bounding box!"
<< std::endl;
return;
}
....
}
The programmer wants a new object of type Geom::OptRect to be created for the bbox parameter when
this parameter equals nullptr; if the object can't be created, method execution should terminate with an
error message.
However, this code behaves quite differently from what the author expected. When the bbox parameter
equals nullptr, a completely new bbox object is created inside the first if block and immediately
destroyed on leaving that block. As a result, the second condition executes every time the first one
executes, so each time the bbox parameter equals nullptr, the method terminates and an error message
is issued.
That code fragment should be rewritten in the following way:
void SPMeshNodeArray::create( ...., Geom::OptRect bbox )
{
....
if( !bbox ) {
std::cout << "SPMeshNodeArray::create(): bbox empty"
<< std::endl;
bbox = item->geometricBounds();
if( !bbox ) {
std::cout << "ERROR: No bounding box!"
<< std::endl;
return;
}
}
....
}
Incorrectly commented-out line
PVS-Studio diagnostic message: V628 It's possible that the line was commented out improperly, thus
altering the program's operation logics. FontFactory.cpp 705
font_instance *font_factory::Face(....)
{
....
if( features[0] != 0 ) // <=
// std::cout << " features: " << std::endl;
for( unsigned k = 0; features[k] != 0; ++k ) {
// dump_tag( &features[k], " feature: ");
++(res->openTypeTables[ extract_tag(&features[k])]);
}
....
}
The programmer forgot to comment out the line with the condition, which was used for debugging. The
mistake is fortunately harmless. It's just that the condition in the if statement simply replicates the
condition of the for loop at the first iteration, but it's surely an error that may become dangerous later.
"One-time" loop
PVS-Studio diagnostic message: V612 An unconditional 'break' within a loop. text_reassemble.c 417
int TR_kern_gap(....)
{
....
while(ptsp && tsp){
....
if(!text32){
....
if(!text32)break;
}
....
if(!ptxt32){
....
if(!ptxt32)break;
}
....
break; // <=
}
....
return(kern);
}
This loop will terminate after the first iteration in any case, as there is no condition before the break
statement. I'm not sure what the author really wanted this code to do. If there is no error here, it's still
better to rewrite the code and replace while with if.
Very odd method
PVS-Studio diagnostic message: V571 Recurring check. The 'back == false' condition was already verified
in line 388. Path.cpp 389
void
Path::SetBackData (bool nVal)
{
if (back == false) {
if (nVal == true && back == false) {
back = true;
ResetPoints();
} else if (nVal == false && back == true) {
back = false;
ResetPoints();
}
} else {
if (nVal == true && back == false) {
back = true;
ResetPoints();
} else if (nVal == false && back == true) {
back = false;
ResetPoints();
}
}
}
It's hard to say why this method is written in such a strange way: the if and else blocks are identical and
there are lots of unnecessary checks. Even if there is no logical error here, this method definitely should
be rewritten:
void
Path::SetBackData (bool nVal)
{
back = nVal;
ResetPoints();
}
Lost comma
PVS-Studio diagnostic message: V737 It is possible that ',' comma is missing at the end of the string.
drawing-text.cpp 272
void DrawingText::decorateStyle(....)
{
....
int dashes[16]={
8, 7, 6, 5,
4, 3, 2, 1,
-8, -7, -6, -5 // <=
-4, -3, -2, -1
};
....
}
A comma is missing, which results in initializing the dashes array to wrong values.
Expected values:
{ 8, 7, 6, 5,
4, 3, 2, 1,
-8, -7, -6, -5,
-4, -3, -2, -1 }
Actual values:
{ 8, 7, 6, 5,
4, 3, 2, 1,
-8, -7, -6, -9,
-3, -2, -1, 0 }
The 12-th element will be initialized to the value -5 - 4 == -9, while the last element (which has no
associated value in the array initialization list) will be initialized to zero, as specified by the C++ standard.
Wrong length in strncmp
PVS-Studio diagnostic message: V666 Consider inspecting third argument of the function 'strncmp'. It is
possible that the value does not correspond with the length of a string which was passed with the
second argument. blend.cpp 85
static Inkscape::Filters::FilterBlendMode
sp_feBlend_readmode(....) {
....
switch (value[0]) {
case 'n':
if (strncmp(value, "normal", 6) == 0)
return Inkscape::Filters::BLEND_NORMAL;
break;
case 'm':
....
case 's':
if (strncmp(value, "screen", 6) == 0)
return Inkscape::Filters::BLEND_SCREEN;
if (strncmp(value, "saturation", 6) == 0) // <=
return Inkscape::Filters::BLEND_SATURATION;
break;
case 'd':
....
case 'o':
if (strncmp(value, "overlay", 7) == 0)
return Inkscape::Filters::BLEND_OVERLAY;
break;
case 'c':
....
case 'h':
if (strncmp(value, "hard-light", 7) == 0) // <=
return Inkscape::Filters::BLEND_HARDLIGHT;
....
break;
....
}
}
The strncmp function receives wrong lengths of strings "saturation" and "hard-light". As a result, only
the first 6 and 7 characters, respectively, will be compared. This error must result from using the so
called Copy-Paste programming and will cause false positives when adding new elements to switch-case.
The code needs fixing:
....
if (strncmp(value, "saturation", 10) == 0)
....
if (strncmp(value, "hard-light", 10) == 0)
....
Potential division by zero
PVS-Studio diagnostic message: V609 Divide by zero. Denominator range [0..999]. lpe-fillet-chamfer.cpp
607
Geom::PathVector
LPEFilletChamfer::doEffect_path(....)
{
....
if(....){
....
} else if (type >= 3000 && type < 4000) {
unsigned int chamferSubs = type-3000;
....
double chamfer_stepsTime = 1.0/chamferSubs;
....
}
...
}
When the type variable equals 3000, the value of the chamferSubs variable will be 0. Therefore, the
value of chamfer_stepsTime will be 1.0/0 == inf, which is obviously not what the programmer expected.
To fix it, the condition in the if block should be changed:
...
else if (type > 3000 && type < 4000)
...
Another way is to separately handle the situation when chamferSubs == 0.
Another similar issue:
 V609 Divide by zero. Denominator range [0..999]. lpe-fillet-chamfer.cpp 623
Missing else?
PVS-Studio diagnostic message: V646 Consider inspecting the application's logic. It's possible that 'else'
keyword is missing. sp-item.cpp 204
void SPItem::resetEvaluated()
{
if ( StatusCalculated == _evaluated_status ) {
....
} if ( StatusSet == _evaluated_status ) { // <=
....
}
}
As the code formatting (the second if statement occupies the same line as the closing brace of the
previous if statement) and logic suggest, the else keyword is missing:
....
if ( StatusCalculated == _evaluated_status ) {
....
} else if ( StatusSet == _evaluated_status ) {
....
}
}
....
Using a null pointer
PVS-Studio diagnostic message: V595 The 'priv' pointer was utilized before it was verified against
nullptr. Check lines: 154, 160. document.cpp 154
SPDocument::~SPDocument()
{
priv->destroySignal.emit(); // <=
....
if (oldSignalsConnected) {
priv->selChangeConnection.disconnect(); // <=
priv->desktopActivatedConnection.disconnect(); // <=
} else {
....
}
if (priv) { // <=
....
}
....
}
In the lowermost if block, the priv pointer is tested for NULL as the programmer assumes that it can be
NULL. However, this pointer was already used without any checks a bit earlier. This error needs to be
fixed by checking the pointer before using it.
Other similar errors:
 V595 The 'parts' pointer was utilized before it was verified against nullptr. Check lines: 624, 641.
sp-offset.cpp 624
 V595 The '_effects_list' pointer was utilized before it was verified against nullptr. Check lines:
103, 113. effect.cpp 103
 V595 The 'num' pointer was utilized before it was verified against nullptr. Check lines: 1312,
1315. cr-tknzr.c 1312
 V595 The 'selector' pointer was utilized before it was verified against nullptr. Check lines: 3463,
3481. cr-parser.c 3463
 V595 The 'a_this' pointer was utilized before it was verified against nullptr. Check lines: 1552,
1562. cr-sel-eng.c 1552
 V595 The 'FillData' pointer was utilized before it was verified against nullptr. Check lines: 5898,
5901. upmf.c 5898
 V595 The 'event_context' pointer was utilized before it was verified against nullptr. Check lines:
1014, 1023. tool-base.cpp 1014
 V595 The 'event_context' pointer was utilized before it was verified against nullptr. Check lines:
959, 970. tool-base.cpp 959
 V595 The 'this->repr' pointer was utilized before it was verified against nullptr. Check lines: 662,
665. eraser-tool.cpp 662
 V595 The 'this->repr' pointer was utilized before it was verified against nullptr. Check lines: 662,
665. eraser-tool.cpp 662
 V595 The 'modified_connection' pointer was utilized before it was verified against nullptr. Check
lines: 1114, 1122. gradient-vector.cpp 1114
 V595 The 'c' pointer was utilized before it was verified against nullptr. Check lines: 762, 770.
freehand-base.cpp 762
 V595 The 'release_connection' pointer was utilized before it was verified against nullptr. Check
lines: 505, 511. gradient-toolbar.cpp 505
 V595 The 'modified_connection' pointer was utilized before it was verified against nullptr. Check
lines: 506, 514. gradient-toolbar.cpp 506
Missing semicolon
PVS-Studio diagnostic message: V504 It is highly probable that the semicolon ';' is missing after 'return'
keyword. svg-fonts-dialog.cpp 167
void GlyphComboBox::update(SPFont* spfont)
{
if (!spfont) return // <=
//TODO: figure out why do we need to append("")
// before clearing items properly...
//Gtk is refusing to clear the combobox
//when I comment out this line
this->append("");
this->remove_all();
}
A semicolon (";") is missing after return, which is actually the cause of the problem mentioned in the
comments. It happens because commenting out the line:
this->append("");
results in the following construct:
if (!spfont) return this->remove_all();
Therefore, the combobox will be cleared only when spfont == NULL.
Unused parameter
PVS-Studio diagnostic message: V763 Parameter 'new_value' is always rewritten in function body
before being used. sp-xmlview-tree.cpp 259
void element_attr_changed(.... const gchar * new_value, ....)
{
NodeData *data = static_cast<NodeData *>(ptr);
gchar *label;
if (data->tree->blocked) return;
if (0 != strcmp (key, "id") &&
0 != strcmp (key, "inkscape:label"))
return;
new_value = repr->attribute("id"); // <=
....
}
The value of the new_value parameter always changes before it is used. Perhaps this parameter should
be removed from the parameter list since having it there doesn't make sense for now.
Another similar issue:
 763 Parameter 'widget' is always rewritten in function body before being used. ruler.cpp 923
Pointer to a nonexistent array
PVS-Studio diagnostic message: V507 Pointer to local array 'n' is stored outside the scope of this array.
Such a pointer will become invalid. inkscape.cpp 582
void
Application::crash_handler (int /*signum*/)
{
....
if (doc->isModifiedSinceSave()) {
const gchar *docname;
....
if (docname) {
....
if (*d=='.' && d>docname && dots==2) {
char n[64];
size_t len = MIN (d - docname, 63);
memcpy (n, docname, len);
n[len] = '0';
docname = n;
}
}
if (!docname || !*docname) docname = "emergency";
....
}
The n array's lifetime is less than that of the docname pointer, which points to that array. This issue
results in working with invalid pointer docname. One of the possible solutions is to define the n array
near the docname pointer:
....
if (doc->isModifiedSinceSave()) {
const gchar *docname;
char n[64];
....
Other similar errors:
 V507 Pointer to local array 'in_buffer' is stored outside the scope of this array. Such a pointer
will become invalid. inkjar.cpp 371
 V507 Pointer to local array 'out_buffer' is stored outside the scope of this array. Such a pointer
will become invalid. inkjar.cpp 375
Incorrect object name in a condition
PVS-Studio diagnostic message: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is
a probability of logical error presence. Check lines: 640, 643. font-variants.cpp 640
void
FontVariants::fill_css( SPCSSAttr *css )
{
....
if( _caps_normal.get_active() ) {
css_string = "normal";
caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL;
} else if( _caps_small.get_active() ) {
....
} else if( _caps_all_small.get_active() ) {
....
} else if( _caps_all_petite.get_active() ) { // <=
css_string = "petite"; // <=
caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE;
} else if( _caps_all_petite.get_active() ) { // <=
css_string = "all-petite"; // <=
caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE;
}
....
}
In the condition preceding _caps_all_petite.get_active(), the _caps_petite object name should be used
instead of _caps_all_petite. This code looks like it was written using Copy-Paste.
Careless use of numeric constants
PVS-Studio diagnostic message: V624 The constant 0.707107 is being utilized. The resulting value could
be inaccurate. Consider using the M_SQRT1_2 constant from <math.h>. PathOutline.cpp 1198
void
Path::OutlineJoin (....)
{
....
if (fabs(c2) > 0.707107) {
....
}
....
}
This format is not quite correct and may result in loss of computational accuracy. It is better to use the
mathematical constant M_SQRT1_2 (the inverse of the square root of 2) declared in the file <math.h>. I
guess this code works well enough actually, but I thought I should mention it as an example of untidy
code.
Other similar defects:
 V624 The constant 1.414213562 is being utilized. The resulting value could be inaccurate.
Consider using the M_SQRT2 constant from <math.h>. verbs.cpp 1848
 V624 The constant 3.14159 is being utilized. The resulting value could be inaccurate. Consider
using the M_PI constant from <math.h>. odf.cpp 1568
 V624 The constant 1.414213562 is being utilized. The resulting value could be inaccurate.
Consider using the M_SQRT2 constant from <math.h>. inkscape-preferences.cpp 1334
Identical expressions
PVS-Studio diagnostic message: V501 There are identical sub-expressions 'Ar.maxExtent() < tol' to the
left and to the right of the '&&' operator. path-intersection.cpp 313
void mono_intersect(....)
{
if(depth > 12 || (Ar.maxExtent() < tol && Ar.maxExtent() < tol))
{
....
}
....
}
The check of the Ar.maxExtent() < tol condition executes twice, which seems to be a result of some
modifications made in the code. The authors need either to fix the expression or simply remove the
duplicate check.
Another similar check:
 V501 There are identical sub-expressions 'Ar.maxExtent() < 0.1' to the left and to the right of the
'&&' operator. path-intersection.cpp 364
Identical operations in if and else blocks
PVS-Studio diagnostic message: V523 The 'then' statement is equivalent to the 'else' statement.
ShapeRaster.cpp 1825
void Shape::AvanceEdge(....)
{
....
if ( swrData[no].sens ) {
if ( swrData[no].curX < swrData[no].lastX ) {
line->AddBord(swrData[no].curX,
swrData[no].lastX,
false);
} else if ( swrData[no].curX > swrData[no].lastX ) {
line->AddBord(swrData[no].lastX,
swrData[no].curX,
false);
}
} else {
if ( swrData[no].curX < swrData[no].lastX ) {
line->AddBord(swrData[no].curX,
swrData[no].lastX,
false);
} else if ( swrData[no].curX > swrData[no].lastX ) {
line->AddBord(swrData[no].lastX,
swrData[no].curX,
false);
}
}
}
The if and else blocks contain the same code, so the authors need to examine this fragment and either
fix the logic or remove the duplicate branch.
Other similar issues:
 V523 The 'then' statement is equivalent to the 'else' statement. ShapeRaster.cpp 1795
 V523 The 'then' statement is equivalent to the 'else' statement. PathCutting.cpp 1323
 V523 The 'then' statement is equivalent to the 'else' statement. ShapeSweep.cpp 2340
Conclusion
This analysis revealed a lot of programmer mistakes caused by lack of attention. PVS-Studio static
analyzer is very good at detecting such errors, which helps save programmers' time and nerves. The
most important thing about static analysis is that it should be done regularly, so that the tool can catch
typos and other defects as soon as they appear. One-time checks, like this one, are good for promoting
PVS-Studio but aren't really effective. Think of static analyzer warnings as extended compiler warnings,
and compiler warnings are something you want to deal with all the time, not just once before a release.
I hope any programmer who cares about their code's quality can relate to this analogy.
Welcome to download PVS-Studio and try it with your own projects.
P.S.
We decided to launch an Instagram account and give it a try. We don't know yet if we are going to get
far with it, but we encourage you to follow us at "pvsstudio".

More Related Content

What's hot

What's hot (20)

Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
 
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
 
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
 
PVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - Continuation
 
Checking VirtualDub
Checking VirtualDubChecking VirtualDub
Checking VirtualDub
 
Checking Notepad++: five years later
Checking Notepad++: five years laterChecking Notepad++: five years later
Checking Notepad++: five years later
 
CppCat Checks OpenMW: Not All is Fine in the Morrowind Universe
CppCat Checks OpenMW: Not All is Fine in the Morrowind UniverseCppCat Checks OpenMW: Not All is Fine in the Morrowind Universe
CppCat Checks OpenMW: Not All is Fine in the Morrowind Universe
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGit
 
Pre New Year Check of PostgreSQL
Pre New Year Check of PostgreSQLPre New Year Check of PostgreSQL
Pre New Year Check of PostgreSQL
 
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
 
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
 
Going On with the Check of Geant4
Going On with the Check of Geant4Going On with the Check of Geant4
Going On with the Check of Geant4
 
The Little Unicorn That Could
The Little Unicorn That CouldThe Little Unicorn That Could
The Little Unicorn That Could
 
PVS-Studio vs Clang
PVS-Studio vs ClangPVS-Studio vs Clang
PVS-Studio vs Clang
 
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)
 
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
 
Linux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-StudioLinux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-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 correction
 
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
 
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
 

Viewers also liked

правила проведения чемпионата по Sc ii 32
правила проведения чемпионата по Sc ii 32правила проведения чемпионата по Sc ii 32
правила проведения чемпионата по Sc ii 32
Alexander Martyushov
 
Правила проведения турнира NETCAFE SC2 #3
Правила проведения турнира NETCAFE SC2 #3Правила проведения турнира NETCAFE SC2 #3
Правила проведения турнира NETCAFE SC2 #3
Alexander Martyushov
 

Viewers also liked (15)

Bugs found in GCC with the help of PVS-Studio
Bugs found in GCC with the help of PVS-StudioBugs found in GCC with the help of PVS-Studio
Bugs found in GCC with the help of PVS-Studio
 
правила проведения чемпионата по Sc ii 32
правила проведения чемпионата по Sc ii 32правила проведения чемпионата по Sc ii 32
правила проведения чемпионата по Sc ii 32
 
How to avoid bugs using modern C++
How to avoid bugs using modern C++How to avoid bugs using modern C++
How to avoid bugs using modern C++
 
Checking the Code of LDAP-Server ReOpenLDAP on Our Readers' Request
Checking the Code of LDAP-Server ReOpenLDAP on Our Readers' RequestChecking the Code of LDAP-Server ReOpenLDAP on Our Readers' Request
Checking the Code of LDAP-Server ReOpenLDAP on Our Readers' Request
 
Developing Developer Communications Skills
Developing Developer Communications SkillsDeveloping Developer Communications Skills
Developing Developer Communications Skills
 
I just had to check ICQ project
I just had to check ICQ projectI just had to check ICQ project
I just had to check ICQ project
 
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
 
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
 
PVS-Studio confesses its love for Linux
PVS-Studio confesses its love for LinuxPVS-Studio confesses its love for Linux
PVS-Studio confesses its love for Linux
 
Finding bugs in the code of LLVM project with the help of PVS-Studio
Finding bugs in the code of LLVM project with the help of PVS-StudioFinding bugs in the code of LLVM project with the help of PVS-Studio
Finding bugs in the code of LLVM project with the help of PVS-Studio
 
Why using finalizers is a bad idea
Why using finalizers is a bad ideaWhy using finalizers is a bad idea
Why using finalizers is a bad idea
 
Searching for bugs in Mono: there are hundreds of them!
Searching for bugs in Mono: there are hundreds of them!Searching for bugs in Mono: there are hundreds of them!
Searching for bugs in Mono: there are hundreds of them!
 
Alternative Dispatcher Layer Overview
Alternative Dispatcher Layer OverviewAlternative Dispatcher Layer Overview
Alternative Dispatcher Layer Overview
 
Правила проведения турнира NETCAFE SC2 #3
Правила проведения турнира NETCAFE SC2 #3Правила проведения турнира NETCAFE SC2 #3
Правила проведения турнира NETCAFE SC2 #3
 
We continue checking Microsoft projects: analysis of PowerShell
We continue checking Microsoft projects: analysis of PowerShellWe continue checking Microsoft projects: analysis of PowerShell
We continue checking Microsoft projects: analysis of PowerShell
 

Similar to Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor

Similar to Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor (15)

Analyzing Firebird 3.0
Analyzing Firebird 3.0Analyzing Firebird 3.0
Analyzing Firebird 3.0
 
Analyzing Firebird 3.0
Analyzing Firebird 3.0Analyzing Firebird 3.0
Analyzing Firebird 3.0
 
PVS-Studio delved into the FreeBSD kernel
PVS-Studio delved into the FreeBSD kernelPVS-Studio delved into the FreeBSD kernel
PVS-Studio delved into the FreeBSD kernel
 
I want to sell a PVS-Studio license to the Intel company
I want to sell a PVS-Studio license to the Intel companyI want to sell a PVS-Studio license to the Intel company
I want to sell a PVS-Studio license to the Intel company
 
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
 
The Unicorn's Travel to the Microcosm
The Unicorn's Travel to the MicrocosmThe Unicorn's Travel to the Microcosm
The Unicorn's Travel to the Microcosm
 
Analysis of the Trans-Proteomic Pipeline (TPP) project
Analysis of the Trans-Proteomic Pipeline (TPP) projectAnalysis of the Trans-Proteomic Pipeline (TPP) project
Analysis of the Trans-Proteomic Pipeline (TPP) project
 
Checking the World of Warcraft CMaNGOS open source server
Checking the World of Warcraft CMaNGOS open source serverChecking the World of Warcraft CMaNGOS open source server
Checking the World of Warcraft CMaNGOS open source server
 
A Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-StudioA Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-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 Everything
 
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
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave
 
Re-analysis of Umbraco code
Re-analysis of Umbraco codeRe-analysis of Umbraco code
Re-analysis of Umbraco code
 
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ BuilderA Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
 
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
 

Recently uploaded

AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
Alluxio, Inc.
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
mbmh111980
 

Recently uploaded (20)

Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web Services
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Breaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfBreaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdf
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in Michelangelo
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdfA Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
 

Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor

  • 1. Waiting for the Linux-version: Checking the Code of Inkscape Graphics Editor Author: Egor Bredikhin Date: 15.08.2016 In this article, I talk about the analysis results for another popular open-source project, vector graphics editor Inkscape 0.92. The project has been developing for over 12 years now and provides a large number of features to work with various vector-image formats. Over this time, its code base has grown up to 600 thousand lines of code, and now is the right time to check it with PVS-Studio static analyzer. Introduction Inkscape is a cross-platform open-source vector graphics editor. It is widely used both by amateur and professional designers all over the world to create images, icons, logos, charts, maps, and web-graphics. Inkscape has become one of the most popular tools in this field. The project was founded in 2003 as a fork of Sodipodi project and is still developing. See the official website for more information about Inkscape. For this analysis, we used the latest version of Inkscape, 0.92, whose source codes can be downloaded from the GitHub repository, and static analyzer PVS-Studio 6.07, which can be downloaded here. Note that at the moment of writing this article, only the Windows-version of PVS-Studio is available. The situation, however, will improve soon, and you can already apply for beta testing of the Linux-version. For details see the article "PVS-Studio confesses its love for Linux".
  • 2. Well, let's get back to errors. Note that I picked only the most interesting warnings to discuss in this article. To do a more thorough analysis on their own, the project authors should contact us so that we could send them a temporary PVS-Studio key and the analysis report. Since there is no public version of PVS-Studio yet, they can use the PVS-Studio Standalone tool, which runs under Windows, to view the report. True, it's inconvenient, but please be patient: the big day of the Linux-version's release is coming soon. Analysis results Testing a pointer for null after new PVS-Studio diagnostic message: V668 There is no sense in testing the 'outputBuf' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. gzipstream.cpp 180 bool GzipInputStream::load() { .... outputBuf = new unsigned char [OUT_SIZE]; if ( !outputBuf ) { // <= delete[] srcBuf; srcBuf = NULL; return false; } .... } As specified by the modern C++ standard, when memory can't be allocated, the new operator throws a std::bad_alloc() exception instead of returning nullptr. If the system fails to allocate storage, an
  • 3. exception is thrown and the function stops executing. The program, therefore, will never enter the block of code following the condition. In this particular case, the error may result in a memory leak. The most obvious solution is to use the try {....} catch(const std::bad_alloc &) {....} block, but a much better way is to use smart pointers instead of releasing the storage explicitly. Other similar pointer checks:  V668 There is no sense in testing the 'destbuf' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. gzipstream.cpp 397  V668 There is no sense in testing the 'srcBuf' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. gzipstream.cpp 175  V668 There is no sense in testing the 'oldcurve' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. sp-lpe-item.cpp 719 Comparing this with zero PVS-Studio diagnostic message: V704 '!this' expression in conditional statements should be avoided - this expression is always false on newer compilers, because 'this' pointer can never be NULL. sp-lpe- item.cpp 213 bool SPLPEItem::performPathEffect(....) { if (!this) { return false; } .... } As specified by the modern C++ standard, the this pointer can never be null. Comparing this with zero often results in unexpected errors. For details see the description of diagnostic V704. Another case of testing this for nullptr:  V704 'this' expression in conditional statements should be avoided - this expression is always true on newer compilers, because 'this' pointer can never be NULL. sp-paint-server.cpp 42 Dangerous parameter redefinition PVS-Studio diagnostic message: V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 1046, 1051. sp-mesh-array.cpp 1051 void SPMeshNodeArray::create( ...., Geom::OptRect bbox ) // <= { .... if( !bbox ) { std::cout << "SPMeshNodeArray::create(): bbox empty" << std::endl; Geom::OptRect bbox = item->geometricBounds(); // <= } if( !bbox ) { // <= std::cout << "ERROR: No bounding box!" << std::endl; return;
  • 4. } .... } The programmer wants a new object of type Geom::OptRect to be created for the bbox parameter when this parameter equals nullptr; if the object can't be created, method execution should terminate with an error message. However, this code behaves quite differently from what the author expected. When the bbox parameter equals nullptr, a completely new bbox object is created inside the first if block and immediately destroyed on leaving that block. As a result, the second condition executes every time the first one executes, so each time the bbox parameter equals nullptr, the method terminates and an error message is issued. That code fragment should be rewritten in the following way: void SPMeshNodeArray::create( ...., Geom::OptRect bbox ) { .... if( !bbox ) { std::cout << "SPMeshNodeArray::create(): bbox empty" << std::endl; bbox = item->geometricBounds(); if( !bbox ) { std::cout << "ERROR: No bounding box!" << std::endl; return; } } .... } Incorrectly commented-out line PVS-Studio diagnostic message: V628 It's possible that the line was commented out improperly, thus altering the program's operation logics. FontFactory.cpp 705 font_instance *font_factory::Face(....) { .... if( features[0] != 0 ) // <= // std::cout << " features: " << std::endl; for( unsigned k = 0; features[k] != 0; ++k ) { // dump_tag( &features[k], " feature: "); ++(res->openTypeTables[ extract_tag(&features[k])]); } .... } The programmer forgot to comment out the line with the condition, which was used for debugging. The mistake is fortunately harmless. It's just that the condition in the if statement simply replicates the condition of the for loop at the first iteration, but it's surely an error that may become dangerous later. "One-time" loop PVS-Studio diagnostic message: V612 An unconditional 'break' within a loop. text_reassemble.c 417
  • 5. int TR_kern_gap(....) { .... while(ptsp && tsp){ .... if(!text32){ .... if(!text32)break; } .... if(!ptxt32){ .... if(!ptxt32)break; } .... break; // <= } .... return(kern); } This loop will terminate after the first iteration in any case, as there is no condition before the break statement. I'm not sure what the author really wanted this code to do. If there is no error here, it's still better to rewrite the code and replace while with if. Very odd method PVS-Studio diagnostic message: V571 Recurring check. The 'back == false' condition was already verified in line 388. Path.cpp 389 void Path::SetBackData (bool nVal) { if (back == false) { if (nVal == true && back == false) { back = true; ResetPoints(); } else if (nVal == false && back == true) { back = false; ResetPoints(); } } else { if (nVal == true && back == false) { back = true; ResetPoints(); } else if (nVal == false && back == true) { back = false; ResetPoints(); } } } It's hard to say why this method is written in such a strange way: the if and else blocks are identical and there are lots of unnecessary checks. Even if there is no logical error here, this method definitely should be rewritten: void Path::SetBackData (bool nVal) {
  • 6. back = nVal; ResetPoints(); } Lost comma PVS-Studio diagnostic message: V737 It is possible that ',' comma is missing at the end of the string. drawing-text.cpp 272 void DrawingText::decorateStyle(....) { .... int dashes[16]={ 8, 7, 6, 5, 4, 3, 2, 1, -8, -7, -6, -5 // <= -4, -3, -2, -1 }; .... } A comma is missing, which results in initializing the dashes array to wrong values. Expected values: { 8, 7, 6, 5, 4, 3, 2, 1, -8, -7, -6, -5, -4, -3, -2, -1 } Actual values: { 8, 7, 6, 5, 4, 3, 2, 1, -8, -7, -6, -9, -3, -2, -1, 0 } The 12-th element will be initialized to the value -5 - 4 == -9, while the last element (which has no associated value in the array initialization list) will be initialized to zero, as specified by the C++ standard. Wrong length in strncmp PVS-Studio diagnostic message: V666 Consider inspecting third argument of the function 'strncmp'. It is possible that the value does not correspond with the length of a string which was passed with the second argument. blend.cpp 85 static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(....) { .... switch (value[0]) { case 'n': if (strncmp(value, "normal", 6) == 0) return Inkscape::Filters::BLEND_NORMAL; break; case 'm': .... case 's':
  • 7. if (strncmp(value, "screen", 6) == 0) return Inkscape::Filters::BLEND_SCREEN; if (strncmp(value, "saturation", 6) == 0) // <= return Inkscape::Filters::BLEND_SATURATION; break; case 'd': .... case 'o': if (strncmp(value, "overlay", 7) == 0) return Inkscape::Filters::BLEND_OVERLAY; break; case 'c': .... case 'h': if (strncmp(value, "hard-light", 7) == 0) // <= return Inkscape::Filters::BLEND_HARDLIGHT; .... break; .... } } The strncmp function receives wrong lengths of strings "saturation" and "hard-light". As a result, only the first 6 and 7 characters, respectively, will be compared. This error must result from using the so called Copy-Paste programming and will cause false positives when adding new elements to switch-case. The code needs fixing: .... if (strncmp(value, "saturation", 10) == 0) .... if (strncmp(value, "hard-light", 10) == 0) .... Potential division by zero PVS-Studio diagnostic message: V609 Divide by zero. Denominator range [0..999]. lpe-fillet-chamfer.cpp 607 Geom::PathVector LPEFilletChamfer::doEffect_path(....) { .... if(....){ .... } else if (type >= 3000 && type < 4000) { unsigned int chamferSubs = type-3000; .... double chamfer_stepsTime = 1.0/chamferSubs; .... } ... }
  • 8. When the type variable equals 3000, the value of the chamferSubs variable will be 0. Therefore, the value of chamfer_stepsTime will be 1.0/0 == inf, which is obviously not what the programmer expected. To fix it, the condition in the if block should be changed: ... else if (type > 3000 && type < 4000) ... Another way is to separately handle the situation when chamferSubs == 0. Another similar issue:  V609 Divide by zero. Denominator range [0..999]. lpe-fillet-chamfer.cpp 623 Missing else? PVS-Studio diagnostic message: V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. sp-item.cpp 204 void SPItem::resetEvaluated() { if ( StatusCalculated == _evaluated_status ) { .... } if ( StatusSet == _evaluated_status ) { // <= .... } } As the code formatting (the second if statement occupies the same line as the closing brace of the previous if statement) and logic suggest, the else keyword is missing: .... if ( StatusCalculated == _evaluated_status ) { .... } else if ( StatusSet == _evaluated_status ) { .... } } .... Using a null pointer PVS-Studio diagnostic message: V595 The 'priv' pointer was utilized before it was verified against nullptr. Check lines: 154, 160. document.cpp 154 SPDocument::~SPDocument() { priv->destroySignal.emit(); // <= .... if (oldSignalsConnected) { priv->selChangeConnection.disconnect(); // <= priv->desktopActivatedConnection.disconnect(); // <= } else { .... } if (priv) { // <= .... } ....
  • 9. } In the lowermost if block, the priv pointer is tested for NULL as the programmer assumes that it can be NULL. However, this pointer was already used without any checks a bit earlier. This error needs to be fixed by checking the pointer before using it. Other similar errors:  V595 The 'parts' pointer was utilized before it was verified against nullptr. Check lines: 624, 641. sp-offset.cpp 624  V595 The '_effects_list' pointer was utilized before it was verified against nullptr. Check lines: 103, 113. effect.cpp 103  V595 The 'num' pointer was utilized before it was verified against nullptr. Check lines: 1312, 1315. cr-tknzr.c 1312  V595 The 'selector' pointer was utilized before it was verified against nullptr. Check lines: 3463, 3481. cr-parser.c 3463  V595 The 'a_this' pointer was utilized before it was verified against nullptr. Check lines: 1552, 1562. cr-sel-eng.c 1552  V595 The 'FillData' pointer was utilized before it was verified against nullptr. Check lines: 5898, 5901. upmf.c 5898  V595 The 'event_context' pointer was utilized before it was verified against nullptr. Check lines: 1014, 1023. tool-base.cpp 1014  V595 The 'event_context' pointer was utilized before it was verified against nullptr. Check lines: 959, 970. tool-base.cpp 959  V595 The 'this->repr' pointer was utilized before it was verified against nullptr. Check lines: 662, 665. eraser-tool.cpp 662  V595 The 'this->repr' pointer was utilized before it was verified against nullptr. Check lines: 662, 665. eraser-tool.cpp 662  V595 The 'modified_connection' pointer was utilized before it was verified against nullptr. Check lines: 1114, 1122. gradient-vector.cpp 1114  V595 The 'c' pointer was utilized before it was verified against nullptr. Check lines: 762, 770. freehand-base.cpp 762  V595 The 'release_connection' pointer was utilized before it was verified against nullptr. Check lines: 505, 511. gradient-toolbar.cpp 505  V595 The 'modified_connection' pointer was utilized before it was verified against nullptr. Check lines: 506, 514. gradient-toolbar.cpp 506 Missing semicolon PVS-Studio diagnostic message: V504 It is highly probable that the semicolon ';' is missing after 'return' keyword. svg-fonts-dialog.cpp 167 void GlyphComboBox::update(SPFont* spfont) { if (!spfont) return // <= //TODO: figure out why do we need to append("") // before clearing items properly... //Gtk is refusing to clear the combobox //when I comment out this line this->append(""); this->remove_all(); }
  • 10. A semicolon (";") is missing after return, which is actually the cause of the problem mentioned in the comments. It happens because commenting out the line: this->append(""); results in the following construct: if (!spfont) return this->remove_all(); Therefore, the combobox will be cleared only when spfont == NULL. Unused parameter PVS-Studio diagnostic message: V763 Parameter 'new_value' is always rewritten in function body before being used. sp-xmlview-tree.cpp 259 void element_attr_changed(.... const gchar * new_value, ....) { NodeData *data = static_cast<NodeData *>(ptr); gchar *label; if (data->tree->blocked) return; if (0 != strcmp (key, "id") && 0 != strcmp (key, "inkscape:label")) return; new_value = repr->attribute("id"); // <= .... } The value of the new_value parameter always changes before it is used. Perhaps this parameter should be removed from the parameter list since having it there doesn't make sense for now. Another similar issue:
  • 11.  763 Parameter 'widget' is always rewritten in function body before being used. ruler.cpp 923 Pointer to a nonexistent array PVS-Studio diagnostic message: V507 Pointer to local array 'n' is stored outside the scope of this array. Such a pointer will become invalid. inkscape.cpp 582 void Application::crash_handler (int /*signum*/) { .... if (doc->isModifiedSinceSave()) { const gchar *docname; .... if (docname) { .... if (*d=='.' && d>docname && dots==2) { char n[64]; size_t len = MIN (d - docname, 63); memcpy (n, docname, len); n[len] = '0'; docname = n; } } if (!docname || !*docname) docname = "emergency"; .... } The n array's lifetime is less than that of the docname pointer, which points to that array. This issue results in working with invalid pointer docname. One of the possible solutions is to define the n array near the docname pointer: .... if (doc->isModifiedSinceSave()) { const gchar *docname; char n[64]; .... Other similar errors:  V507 Pointer to local array 'in_buffer' is stored outside the scope of this array. Such a pointer will become invalid. inkjar.cpp 371  V507 Pointer to local array 'out_buffer' is stored outside the scope of this array. Such a pointer will become invalid. inkjar.cpp 375 Incorrect object name in a condition PVS-Studio diagnostic message: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 640, 643. font-variants.cpp 640 void FontVariants::fill_css( SPCSSAttr *css ) { .... if( _caps_normal.get_active() ) { css_string = "normal";
  • 12. caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL; } else if( _caps_small.get_active() ) { .... } else if( _caps_all_small.get_active() ) { .... } else if( _caps_all_petite.get_active() ) { // <= css_string = "petite"; // <= caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE; } else if( _caps_all_petite.get_active() ) { // <= css_string = "all-petite"; // <= caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE; } .... } In the condition preceding _caps_all_petite.get_active(), the _caps_petite object name should be used instead of _caps_all_petite. This code looks like it was written using Copy-Paste. Careless use of numeric constants PVS-Studio diagnostic message: V624 The constant 0.707107 is being utilized. The resulting value could be inaccurate. Consider using the M_SQRT1_2 constant from <math.h>. PathOutline.cpp 1198 void Path::OutlineJoin (....) { .... if (fabs(c2) > 0.707107) { .... } .... } This format is not quite correct and may result in loss of computational accuracy. It is better to use the mathematical constant M_SQRT1_2 (the inverse of the square root of 2) declared in the file <math.h>. I guess this code works well enough actually, but I thought I should mention it as an example of untidy code. Other similar defects:  V624 The constant 1.414213562 is being utilized. The resulting value could be inaccurate. Consider using the M_SQRT2 constant from <math.h>. verbs.cpp 1848  V624 The constant 3.14159 is being utilized. The resulting value could be inaccurate. Consider using the M_PI constant from <math.h>. odf.cpp 1568  V624 The constant 1.414213562 is being utilized. The resulting value could be inaccurate. Consider using the M_SQRT2 constant from <math.h>. inkscape-preferences.cpp 1334 Identical expressions PVS-Studio diagnostic message: V501 There are identical sub-expressions 'Ar.maxExtent() < tol' to the left and to the right of the '&&' operator. path-intersection.cpp 313 void mono_intersect(....) { if(depth > 12 || (Ar.maxExtent() < tol && Ar.maxExtent() < tol)) { .... }
  • 13. .... } The check of the Ar.maxExtent() < tol condition executes twice, which seems to be a result of some modifications made in the code. The authors need either to fix the expression or simply remove the duplicate check. Another similar check:  V501 There are identical sub-expressions 'Ar.maxExtent() < 0.1' to the left and to the right of the '&&' operator. path-intersection.cpp 364 Identical operations in if and else blocks PVS-Studio diagnostic message: V523 The 'then' statement is equivalent to the 'else' statement. ShapeRaster.cpp 1825 void Shape::AvanceEdge(....) { .... if ( swrData[no].sens ) { if ( swrData[no].curX < swrData[no].lastX ) { line->AddBord(swrData[no].curX, swrData[no].lastX, false); } else if ( swrData[no].curX > swrData[no].lastX ) { line->AddBord(swrData[no].lastX, swrData[no].curX, false); } } else { if ( swrData[no].curX < swrData[no].lastX ) { line->AddBord(swrData[no].curX, swrData[no].lastX, false); } else if ( swrData[no].curX > swrData[no].lastX ) { line->AddBord(swrData[no].lastX, swrData[no].curX, false); } } } The if and else blocks contain the same code, so the authors need to examine this fragment and either fix the logic or remove the duplicate branch. Other similar issues:  V523 The 'then' statement is equivalent to the 'else' statement. ShapeRaster.cpp 1795  V523 The 'then' statement is equivalent to the 'else' statement. PathCutting.cpp 1323  V523 The 'then' statement is equivalent to the 'else' statement. ShapeSweep.cpp 2340 Conclusion This analysis revealed a lot of programmer mistakes caused by lack of attention. PVS-Studio static analyzer is very good at detecting such errors, which helps save programmers' time and nerves. The most important thing about static analysis is that it should be done regularly, so that the tool can catch
  • 14. typos and other defects as soon as they appear. One-time checks, like this one, are good for promoting PVS-Studio but aren't really effective. Think of static analyzer warnings as extended compiler warnings, and compiler warnings are something you want to deal with all the time, not just once before a release. I hope any programmer who cares about their code's quality can relate to this analogy. Welcome to download PVS-Studio and try it with your own projects. P.S. We decided to launch an Instagram account and give it a try. We don't know yet if we are going to get far with it, but we encourage you to follow us at "pvsstudio".