SlideShare a Scribd company logo
1 of 16
Download to read offline
Toonz code leaves much to be desired
Author: Svyatoslav Razmyslov
Date: 07.04.2016
Recently the world got to know that Digital Video, the makers of TOONZ, and DWANGO, a Japanese
publisher, have signed an agreement for the acquisition by Dwango of Toonz, an animation software
which was independently developed by Digital Video (Rome, Italy).
Digital Video and Dwango agreed to close the deal under the condition Dwango will publish, and
develop, an Open Source platform based on Toonz (OpenToonz). It will include features developed by
Studio Ghibli (*Toonz Ghibli Edition) which has been a long time Toonz user. "Howl's Moving Castle",
"Spirited Away", "Ponyo on the Cliff by the Sea" and many other fantasy films - are among the most
known fantasy films. One more cartoon of their production "Futurama" inspired our team to write this
article about the source code of OpenToonz.
Introduction
OpenToonz is a software for producing a 2D animation. It is based on the "Toonz" project, which was
developed by Digital Video in Italy. Later it was customized by Studio Ghibli, and has now been used for
creating its works for many years already. Besides the animation films, this project was also used for
creation of computer games - Discworld, and Claw, for instance.
It should be noted that the price of the kit was about $10000, but the code quality leaves much to be
desired. This project is a treasure trove for a static analyzer. The size of OpenToonz source code is about
1/10 of FreeBSD kernel, where we've found more than 40 serious bugs with the help of PVS-Studio, but
here we have found much more!
OpenToonz was checked in Visual Studio 2013 using PVS-Studio, version 6.03, which supports C/C++/C#,
different build systems, and is still being actively developed. The compilation stage already aroused a lot
of suspicion when I saw the number of compiler warnings - by the end of the build there were 1211 of
them! It shows that the code wasn't really cared for! Moreover, some of the compiler warnings were
disabled by #pragma warning, and even there were several bugs there, that I will speak about later. This
article will be a little atypical - we are presenting bugs found in the project, which are usually common
for novice programmers who have just started learning C/C++. I will start the description with analyzer
warnings which are connected with incorrect usage of memory and pointers.
Incorrect work with memory
V611 The memory was allocated using 'new' operator but was released using the 'free' function.
Consider inspecting operation logics behind the 'row' variable. motionblurfx.cpp 288
template <class T>
void doDirectionalBlur(....)
{
T *row, *buffer;
....
row = new T[lx + 2 * brad + 2]; // <=
if (!row)
return;
memset(row, 0, (lx + 2 * brad + 2) * sizeof(T));
....
free(row); // <=
r->unlock();
}
The analyzer detected that dynamic memory is allocated and freed in incompatible ways. After the call
of new[] operator the memory must be freed with the delete[] operator. Note that square brackets are
used here. I want to draw your attention to this for a reason - have a look at the following example:
V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator.
Consider inspecting this code. It's probably better to use 'delete [] uPrime;'. tstroke.cpp 3353
double *reparameterize3D(....)
{
double *uPrime = new double[size]; // <=
for (int i = 0; i < size; i++) {
uPrime[i] = NewtonRaphsonRootFind3D(....);
if (!_finite(uPrime[i])) {
delete uPrime; // <=
return 0;
}
}
....
}
In C++ operators new/delete and new[]/delete[] are used in pairs. The use of different operators for
allocation and deallocation of dynamic memory is an error. In the code given above, the memory that is
allocated for the uPrime array won't be correctly freed.
Unfortunately, this fragment is not the only one. I have noted down 20 more fragments in the file
OpenToonz_V611.txt.
V554 Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete'.
screensavermaker.cpp 29
void makeScreenSaver(....)
{
....
std::auto_ptr<char> swf(new char[swfSize]);
....
}
Here we have an alternative variant of the bug we have just seen, but here the operator delete is
"hidden" inside of the pointer std::auto_ptr. This also leads to undefined behavior.
To correct this, you must specify that delete[] must be used here.
The correct code variant:
std::unique_ptr<char[]> swf(new char[swfSize]);
V599 The destructor was not declared as a virtual one, although the 'TTileSet' class contains virtual
functions. cellselection.cpp 891
void redo() const
{
insertLevelAndFrameIfNeeded();
TTileSet *tiles; // <=
bool isLevelCreated;
pasteRasterImageInCellWithoutUndo(...., &tiles, ....);
delete tiles; // <=
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
Now let's talk about memory leaks and partial destruction of objects. In this example the objects,
inherited from the TTileSet class will not be completely destroyed.
Description of the class TTileSet:
class DVAPI TTileSet
{
....
protected:
TDimension m_srcImageSize;
typedef std::vector<Tile *> Tiles;
Tiles m_tiles;
public:
TTileSet(const TDimension &dim) : m_srcImageSize(dim)
{
}
~TTileSet(); // <=
....
virtual void add(const TRasterP &ras, TRect rect) = 0;
....
virtual TTileSet *clone() const = 0;
};
The class is abstract and contains pure virtual functions. You cannot create objects of this class as it is
only used by derived classes. Thus, due to the missing virtual destructor in TTileSet (there is a destructor,
but it isn't marked as a virtual one), all derived classes will fail to be completely cleaned.
In the OpenToonz code I found several classes that are inherited from TTileSet:
class DVAPI TTileSetCM32 : public TTileSet
class DVAPI TTileSetCM32 : public TTileSet
class DVAPI TTileSetFullColor : public TTileSet
class DVAPI Tile : public TTileSet::Tile
Each of these object classes (or those derived from them), will not be destroyed completely. The
probable outcome, is undefined behavior; in practice, this is likely to lead to memory leaks, and other
resource leaks.
Developers should review the following fragments too:
 V599 The virtual destructor is not present, although the 'MessageParser' class contains virtual
functions. tipcsrv.cpp 91
 V599 The virtual destructor is not present, although the 'ColumnToCurveMapper' class contains
virtual functions. functionselection.cpp 278
Dangerous use of pointers
V503 This is a nonsensical comparison: pointer < 0. styleselection.cpp 104
bool pasteStylesDataWithoutUndo(....)
{
....
if (palette->getStylePage(styleId) < 0) { // <=
// styleId non e' utilizzato: uso quello
// (cut/paste utilizzato per spostare stili)
palette->setStyle(styleId, style);
} else {
// styleId e' gia' utilizzato. ne devo prendere un altro
styleId = palette->getFirstUnpagedStyle();
if (styleId >= 0)
palette->setStyle(styleId, style);
else
styleId = palette->addStyle(style);
}
....
}
The getStylePage() function returns a pointer to some page: TPalette::Page*. Such a comparison with 0
doesn't make sense. I have researched the way the function getStylePage() is used, and saw that in all
other cases the result of this function is verified against null, but here the programmer made a mistake.
V522 Dereferencing of the null pointer 'region' might take place. Check the logical condition.
palettecmd.cpp 102
bool isStyleUsed(const TVectorImageP vi, int styleId)
{
....
TRegion *region = vi->getRegion(i);
if (region || region->getStyle() != styleId)
return true;
....
}
Most likely, the programmer put operators'&&' and '||' in the incorrect places. Otherwise, if the pointer
region is null, it will be dereferenced.
V614 Potentially uninitialized pointer 'socket' used. Consider checking the first actual argument of the
'connect' function. tmsgcore.cpp 36
void TMsgCore::OnNewConnection() //server side
{
QTcpSocket *socket;
if (m_tcpServer) // <=
socket = m_tcpServer->nextPendingConnection(); // <=
assert(socket);
bool ret = connect(socket, ....); // <=
ret = ret && connect(socket, ....); // <=
assert(ret);
m_sockets.insert(socket);
}
The Analyzer detected potential use of an uninitialized pointer socket. If the variable m_tcpServer is
false, the pointer will not be initialized. But, being uninitialized, it can still be passed to the connect()
function.
V595 The 'batchesTask' pointer was utilized before it was verified against nullptr. Check lines: 1064,
1066. batches.cpp 1064
void BatchesController::update()
{
....
TFarmTask *batchesTask = getTask(batchesTaskId); // <=
TFarmTask farmTask = *batchesTask; // <=
if (batchesTask) { // <=
QString batchesTaskParentId = batchesTask->m_parentId;
m_controller->queryTaskInfo(farmTaskId, farmTask);
int chunkSize = batchesTask->m_chunkSize;
*batchesTask = farmTask;
batchesTask->m_chunkSize = chunkSize;
batchesTask->m_id = batchesTaskId;
batchesTask->m_parentId = batchesTaskParentId;
}
....
}
There are a lot of fragments where we may potentially have null pointer dereference. Usually there is a
necessary check, but one or more fragments are still unsafe. For example, there is a check batchesTask,
but the pointer was already dereferenced before the check.
29 similar fragments are shown here, in the file: OpenToonz_V595.txt
Errors related to working with strings
V530 The return value of function 'toUpper' is required to be utilized. sceneviewerevents.cpp 847
void SceneViewer::keyPressEvent(QKeyEvent *event)
{
....
QString text = event->text();
if ((event->modifiers() & Qt::ShiftModifier))
text.toUpper();
....
}
ToUpper() method does not change the string 'text'. In the documentation it is described as: QString
QString::toUpper(), i.e. it is a constant method.
Correct code variant:
QString text = event->text();
if ((event->modifiers() & Qt::ShiftModifier))
text = text.toUpper();
In the code there are three functions, whose return value is not used. All of these fragments need to be
edited:
 V530 The return value of function 'left' is required to be utilized. tfarmserver.cpp 569
 V530 The return value of function 'ftell' is required to be utilized. tiio_bmp.cpp 804
 V530 The return value of function 'accumulate' is required to be utilized. bendertool.cpp 374
V614 Uninitialized iterator 'it1' used. fxcommand.cpp 2096
QString DeleteLinksUndo::getHistoryString()
{
....
std::list<TFxP>::const_iterator it1; // <=
std::list<TFx *>::const_iterator ft;
for (ft = m_terminalFxs.begin(); ft != ....end(); ++ft) {
if (ft != m_terminalFxs.begin())
str += QString(", ");
str += QString("%1- -Xsheet")
.arg(QString::fromStdWString((*it1)->getName())); // <=
}
....
}
The uninitialized iterator it1 is used in the string operations. Most likely, the programmer forgot to
replace it with ft iterator.
V642 Saving the '_wcsicmp' function result inside the 'char' type variable is inappropriate. The significant
bits could be lost, breaking the program's logic. tfilepath.cpp 328
bool TFilePath::operator<(const TFilePath &fp) const
{
....
char differ;
differ = _wcsicmp(iName.c_str(), jName.c_str());
if (differ != 0)
return differ < 0 ? true : false;
....
}
_wcsicmp function returns the following values of int type:
 < 0 - string1 less then string2;
 0 - string1 identical to string2;
 > 0 - string1 greater than string2.
Please note that '>0' can be any number, not only 1. These numbers can be: 2, 3, 100, 256, 1024, 5555,
and so on. _wcsicmp function result may not fit into a variable of char type, so the comparison operator
will return an unexpected result.
V643 Unusual pointer arithmetic: "" + v[i]. The value of the 'char' type is being added to the string
pointer. tstream.cpp 31
string escape(string v)
{
int i = 0;
for (;;) {
i = v.find_first_of("'"", i);
if (i == (int)string::npos)
break;
string h = "" + v[i]; // <=
v.insert(i, "");
i = i + 2;
}
return v;
}
The analyzer detected an error caused by adding a character constant to a string literal. It was expected
that a symbol would be added to the string, but a numeric value gets added to the pointer to the string,
which leads to access beyond the string literal boundary, and an unexpected result.
Here is what this code is equal to:
const char *p1 = "";
const int delta = v[i];
const char *p2 = *p1 + delta;
string h = p2;
Correct code variant:
string h = string("") + v[i];
V655 The strings were concatenated, but are not utilized. Consider inspecting the 'alias + "]"' expression.
plasticdeformerfx.cpp 150
string PlasticDeformerFx::getAlias(....) const
{
std::string alias(getFxType());
alias += "[";
....
if (sd)
alias += ", "+toString(sd, meshColumnObj->paramsTime(frame));
alias + "]"; // <=
return alias;
}
The analyzer detected an expression whose result is not used. Most likely, '+' operator was accidentally
written instead of '+='. As a result, a square bracket isn't added to the alias string, as the programmer
planned.
Incorrect exceptions
V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw
domain_error(FOO); pluginhost.cpp 1486
void Loader::doLoad(const QString &file)
{
....
int ret = pi->ini_(host);
if (ret) {
delete host;
std::domain_error("failed initialized: error on ....");
}
....
}
The keyword throw was accidentally forgotten in the function. As a result, this code does not generate
an exception in case of an error situation. Correct code variant:
throw std::domain_error("failed initialized: error on ....");
V746 Type slicing. An exception should be caught by reference rather than by value. iocommand.cpp
1620
bool IoCmd::saveLevel(....)
{
....
try {
sl->save(fp, TFilePath(), overwritePalette);
} catch (TSystemException se) { // <=
QApplication::restoreOverrideCursor();
MsgBox(WARNING, QString::fromStdWString(se.getMessage()));
return false;
} catch (...) {
....
}
....
}
The analyzer detected a potential error, related to catching the exception by value. This means that a
new se object of TSystemException will be constructed with the help of a copy constructor. At the same
time, the code will lose some information about the exception that was stored in the classes, inherited
from TSystemException.
Similar suspicious fragments:
 V746 Type slicing. An exception should be caught by reference rather than by value.
iocommand.cpp 2650
 V746 Type slicing. An exception should be caught by reference rather than by value.
projectpopup.cpp 522
 V746 Type slicing. An exception should be caught by reference rather than by value.
projectpopup.cpp 537
 V746 Type slicing. An exception should be caught by reference rather than by value.
projectpopup.cpp 635
 V746 Type slicing. An exception should be caught by reference rather than by value.
tlevel_io.cpp 130
 V746 Type slicing. An exception should be caught by reference rather than by value.
calligraph.cpp 161
 V746 Type slicing. An exception should be caught by reference rather than by value.
calligraph.cpp 165
 V746 Type slicing. An exception should be caught by reference rather than by value.
patternmap.cpp 210
 V746 Type slicing. An exception should be caught by reference rather than by value.
patternmap.cpp 214
 V746 Type slicing. An exception should be caught by reference rather than by value.
patternmap.cpp 218
 V746 Type slicing. An exception should be caught by reference rather than by value.
scriptbinding_level.cpp 221
Incorrect conditions
V547 Expression '(int) startOutPoints.size() % 2 != 2' is always true. rasterselection.cpp 852
TStroke getIntersectedStroke(TStroke &stroke, TRectD bbox)
{
....
for (t = 0; t < (int)outPoints.size(); t++)
addPointToVector(...., (int)startOutPoints.size() % 2 != 2);
....
}
An interesting bug. Perhaps the programmer wanted to check if the size() value is even or odd. That's
why the remainder of division by 2 must be compared with zero.
V502 Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a
lower priority than the '+' operator. igs_motion_wind_pixel.cpp 127
void rgb_to_lightness_(
const double re, const double gr, const double bl, double &li)
{
li=((re < gr) ? ((gr < bl) ? bl : gr) : ((re < bl) ? bl : re) +
(gr < re)
? ((bl < gr) ? bl : gr)
: ((bl < re) ? bl : re)) / 2.0;
}
In this code snippet, the programmer made a mistake related to the priority of the ternary operator ':?' .
Its priority is lower than that of the addition operator. Consequently, if the condition (re < gr) is false,
the following evaluations will be done incorrectly: real variables will be added to logical ones.
Never use several ternary operators at once - it's the easiest way to make an error.
V590 Consider inspecting the 'state == (- 3) || state != 0' expression. The expression is excessive or
contains a misprint. psdutils.cpp 174
int psdUnzipWithoutPrediction(....)
{
....
do {
state = inflate(&stream, Z_PARTIAL_FLUSH);
if (state == Z_STREAM_END)
break;
if (state == Z_DATA_ERROR || state != Z_OK) // <=
break;
} while (stream.avail_out > 0);
....
}
The condition marked by an arrow does not depend on the result of the subexpression "state ==
Z_DATA_ERROR". This is easy to check, if you build a truth table of the whole conditional expression.
Copy-paste programming
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 1448, 1454. tcenterlineskeletonizer.cpp 1448
inline void Event::processVertexEvent()
{
....
if (newLeftNode->m_concave) { // <=
newLeftNode->m_notOpposites = m_generator->m_notOpposites;
append<vector<ContourEdge *>, vector<ContourEdge *>::....
newLeftNode->m_notOpposites.push_back(newRightNode->m_edge);
newLeftNode->m_notOpposites.push_back(newRightNode->....);
} else if (newLeftNode->m_concave) { // <=
newRightNode->m_notOpposites = m_generator->m_notOpposites;
append<vector<ContourEdge *>, vector<ContourEdge *>::....
newRightNode->m_notOpposites.push_back(newLeftNode->m_edge);
newRightNode->m_notOpposites.push_back(newLeftNode->....);
}
....
}
We see that newLeftNode and newRightNode variables are confused in the conditions. As a result of this
error, the else branch is never executed. Most probably, one of the conditions should be as follows: if
(newRightNode-> m_concave).
V501 There are identical sub-expressions to the left and to the right of the '||' operator: m_cutLx ||
m_cutLx canvassizepopup.cpp 271
bool m_cutLx, m_cutLy;
void PeggingWidget::on00()
{
....
m_11->setIcon(...).rotate(m_cutLx || m_cutLx ? -90 : 90),....));
....
}
There are two logical variables in the code: m_cutLx and m_cutLy that differ just in one letter. But in the
example given we see that only m_cutLx gets used. Perhaps, there is a typo in one of them.
V501 There are identical sub-expressions 'parentTask->m_status == Aborted' to the left and to the right
of the '||' operator. tfarmcontroller.cpp 1857
void FarmController::taskSubmissionError(....)
{
....
if (parentTask->m_status == Aborted || // <=
parentTask->m_status == Aborted) { // <=
parentTask->m_completionDate = task->m_completionDate;
if (parentTask->m_toBeDeleted)
m_tasks.erase(itParent);
}
....
}
The analyzer detected two similar comparisons with the constant Aborted. Having done a search in the
file, I found a similar code block in line 2028 with this condition:
if (parentTask->m_status == Completed ||
parentTask->m_status == Aborted) {
Perhaps, the condition should be similar in this fragment.
V501 There are identical sub-expressions 'cornerCoords.y > upperBound' to the left and to the right of
the '||' operator. tellipticbrush.cpp 1020
template <typename T>
void tellipticbrush::OutlineBuilder::addMiterSideCaps(....)
{
....
if (cornerCoords == TConsts::napd ||
cornerCoords.x < lowerBound || cornerCoords.y > upperBound ||
cornerCoords.y < lowerBound || cornerCoords.y > upperBound) {
....
}
....
}
Here the programmer made a small typo, using y instead of x.
I won't describe six more typos caused by copy-paste programming, I will just give them as a list. These
fragments should also be definitely reviewed by the developers:
 V501 There are identical sub-expressions 's.m_repoStatus == "modified"' to the left and to the
right of the '||' operator. svnupdatedialog.cpp 210
 V501 There are identical sub-expressions 'm_lineEdit->hasFocus()' to the left and to the right of
the '||' operator. framenavigator.cpp 44
 V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical
error presence. Check lines: 750, 825. tpalette.cpp 750
 V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical
error presence. Check lines: 123, 126. igs_density.cpp 123
 V523 The 'then' statement is equivalent to the 'else' statement. typetool.cpp 813
 V583 The '?:' operator, regardless of its conditional expression, always returns one and the same
value: Comma. tgrammar.cpp 731
Miscellaneous errors
V665 Possibly, the usage of '#pragma warning(default: X)' is incorrect in this context. The '#pragma
warning(push/pop)' should be used instead. Check lines: 20, 205. tspectrum.h 205
#ifdef WIN32
#pragma warning(disable : 4251)
#endif
....
#ifdef WIN32
#pragma warning(default : 4251)
#endif
Here is how the compiler disables the warnings that were finally noticed in this project. The error is that
the #pragma warning(default : X) doesn't turn on the warning, but sets it as a DEFAULT one, which can
be different from what the programmer expects. The correct variant of the code should be:
#ifdef WIN32
#pragma warning(push)
#pragma warning(disable : 4251)
#endif
....
#ifdef WIN32
#pragma warning(pop)
#endif
V546 Member of a class is initialized by itself: 'm_subId(m_subId)'. tfarmcontroller.cpp 572
class TaskId
{
int m_id;
int m_subId;
public:
TaskId(int id, int subId = -1) : m_id(id), m_subId(m_subId){};
An interesting bug in the list of class initialization. The field m_subld is initialized by itself; perhaps the
programmer wanted to write m_subId(subId).
V557 Array overrun is possible. The '9' index is pointing beyond array bound. tconvolve.cpp 123
template <class PIXOUT>
void doConvolve_cm32_row_9_i(....)
{
TPixel32 val[9]; // <=
....
for (int i = 0; i < 9; ++i) { // <= OK
....
else if (tone == 0)
val[i] = inks[ink];
else
val[i] = blend(....);
}
pixout->r = (typename PIXOUT::Channel)((
val[1].r * w1 + val[2].r * w2 + val[3].r * w3 +
val[4].r * w4 + val[5].r * w5 + val[6].r * w6 +
val[7].r * w7 + val[8].r * w8 + val[9].r * w9 + // <= ERR
(1 << 15)) >> 16);
pixout->g = (typename PIXOUT::Channel)((
val[1].g * w1 + val[2].g * w2 + val[3].g * w3 +
val[4].g * w4 + val[5].g * w5 + val[6].g * w6 +
val[7].g * w7 + val[8].g * w8 + val[9].g * w9 + // <= ERR
(1 << 15)) >> 16);
pixout->b = (typename PIXOUT::Channel)((
val[1].b * w1 + val[2].b * w2 + val[3].b * w3 +
val[4].b * w4 + val[5].b * w5 + val[6].b * w6 +
val[7].b * w7 + val[8].b * w8 + val[9].b * w9 + // <= ERR
(1 << 15)) >> 16);
pixout->m = (typename PIXOUT::Channel)((
val[1].m * w1 + val[2].m * w2 + val[3].m * w3 +
val[4].m * w4 + val[5].m * w5 + val[6].m * w6 +
val[7].m * w7 + val[8].m * w8 + val[9].m * w9 + // <= ERR
(1 << 15)) >> 16);
....
}
It's a large code fragment, where a programmer accesses a val array, consisting of 9 elements, by the
index from 1 to 9. Although, there is a loop where we see correct access of the array by the index from 0
to 8.
V556 The values of different enum types are compared: m_action != EDIT_SEGMENT. Types: Action,
CursorType. controlpointeditortool.cpp 257
enum Action { NONE,
RECT_SELECTION,
CP_MOVEMENT,
SEGMENT_MOVEMENT,
IN_SPEED_MOVEMENT,
OUT_SPEED_MOVEMENT };
enum CursorType { NORMAL,
ADD,
EDIT_SPEED,
EDIT_SEGMENT,
NO_ACTIVE };
void ControlPointEditorTool::drawMovingSegment()
{
int beforeIndex = m_moveSegmentLimitation.first;
int nextIndex = m_moveSegmentLimitation.second;
if (m_action != EDIT_SEGMENT || // <=
beforeIndex == -1 ||
nextIndex == -1 ||
!m_moveControlPointEditorStroke.getStroke())
return;
....
}
The analyzer detected the comparison of enum values which have different types. Using code search I
also found that the field of m_action class is initialized with a correct type, but in this fragment it is
compared with a constant of a different type.
Conclusion
As was already mentioned, OpenToonz project is a great find for a static code analyzer: even being quite
small, it has a great number of serious bugs. Not all bugs are listed in this article; moreover, we weren't
able to fit some serious warnings because of their big number. We will notify the developers about the
bugs found, perhaps they will be interested in improving their code.
Pixar company also expressed their intention to open the source code of Universal Scene Description
(USD). We are looking forward to this.
For those who may be interested: you may find PVS-Studio here, and run it on your C/C++/C# projects.
The analyzer works in the Windows environment, and supports various build systems.

More Related Content

What's hot

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 MicrocosmAndrey Karpov
 
Anomalies in X-Ray Engine
Anomalies in X-Ray EngineAnomalies in X-Ray Engine
Anomalies in X-Ray EnginePVS-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
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Platonov Sergey
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio
 
PVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2PVS-Studio
 
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerRechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerAndrey Karpov
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs ChromiumAndrey Karpov
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Sergey Platonov
 
Tiramisu をちょっと、味見してみました。
Tiramisu をちょっと、味見してみました。Tiramisu をちょっと、味見してみました。
Tiramisu をちょっと、味見してみました。Mr. Vengineer
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Oky Firmansyah
 
Welcome to Modern C++
Welcome to Modern C++Welcome to Modern C++
Welcome to Modern C++Seok-joon Yun
 
Pro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptPro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptSeok-joon Yun
 
Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Andrey Karpov
 
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
ITGM #9 - Коварный CodeType, или от segfault'а к работающему кодуITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
ITGM #9 - Коварный CodeType, или от segfault'а к работающему кодуdelimitry
 
from java to c
from java to cfrom java to c
from java to cVõ Hòa
 

What's hot (20)

Namespaces
NamespacesNamespaces
Namespaces
 
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
 
Smart Pointers in C++
Smart Pointers in C++Smart Pointers in C++
Smart Pointers in C++
 
Anomalies in X-Ray Engine
Anomalies in X-Ray EngineAnomalies in X-Ray Engine
Anomalies in X-Ray Engine
 
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
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave
 
PVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - Continuation
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
 
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code AnalyzerRechecking TortoiseSVN with the PVS-Studio Code Analyzer
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs Chromium
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs Chromium
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >
 
Tiramisu をちょっと、味見してみました。
Tiramisu をちょっと、味見してみました。Tiramisu をちょっと、味見してみました。
Tiramisu をちょっと、味見してみました。
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)
 
Welcome to Modern C++
Welcome to Modern C++Welcome to Modern C++
Welcome to Modern C++
 
Pro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptPro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScript
 
Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2
 
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
ITGM #9 - Коварный CodeType, или от segfault'а к работающему кодуITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
ITGM #9 - Коварный CodeType, или от segfault'а к работающему коду
 
from java to c
from java to cfrom java to c
from java to c
 

Viewers also liked

Aula 01 animação 2 d
Aula 01 animação 2 dAula 01 animação 2 d
Aula 01 animação 2 dVenise Melo
 
Oficina camila menegali r uberlandia
Oficina camila menegali r uberlandiaOficina camila menegali r uberlandia
Oficina camila menegali r uberlandiakamidadepressao
 
Apresentação1 Animação Digital 2D I
Apresentação1 Animação Digital 2D IApresentação1 Animação Digital 2D I
Apresentação1 Animação Digital 2D IJoão Leal
 
Animação (2)
Animação (2)Animação (2)
Animação (2)Martinha5
 
Diagnosis ⇒ Initiatives Strategy
Diagnosis ⇒ Initiatives StrategyDiagnosis ⇒ Initiatives Strategy
Diagnosis ⇒ Initiatives StrategyAncoraFoundation
 
Diagnosis ⇒ Initiatives ⇒ Strategy
Diagnosis ⇒ Initiatives ⇒ StrategyDiagnosis ⇒ Initiatives ⇒ Strategy
Diagnosis ⇒ Initiatives ⇒ StrategyAncoraFoundation
 
Teach us UK Q&A
Teach us UK Q&ATeach us UK Q&A
Teach us UK Q&ARoamler
 
工商E通培训材料
工商E通培训材料工商E通培训材料
工商E通培训材料xuelili
 
无线Vpdn产品宣介
无线Vpdn产品宣介无线Vpdn产品宣介
无线Vpdn产品宣介xuelili
 
综合办公业务介绍
综合办公业务介绍综合办公业务介绍
综合办公业务介绍xuelili
 
交通E通(业务介绍)
交通E通(业务介绍)交通E通(业务介绍)
交通E通(业务介绍)xuelili
 
Proiect manusa iri ''.
Proiect manusa iri ''.Proiect manusa iri ''.
Proiect manusa iri ''.mariahodan
 
My proposal for my 2D animation
My proposal for my 2D animationMy proposal for my 2D animation
My proposal for my 2D animationEmily Hales
 
Cinema de animação nas escolas final 2
Cinema de animação nas escolas final 2Cinema de animação nas escolas final 2
Cinema de animação nas escolas final 2José Serpa
 
Curbing Corruption while Promoting Business & Economic Growth
Curbing Corruption while Promoting Business & Economic GrowthCurbing Corruption while Promoting Business & Economic Growth
Curbing Corruption while Promoting Business & Economic GrowthAncoraFoundation
 
2d animation proposal
2d animation proposal2d animation proposal
2d animation proposalMike Kenny
 
An unusual bug in Lucene.Net
An unusual bug in Lucene.NetAn unusual bug in Lucene.Net
An unusual bug in Lucene.NetPVS-Studio
 

Viewers also liked (20)

Aula 01 animação 2 d
Aula 01 animação 2 dAula 01 animação 2 d
Aula 01 animação 2 d
 
Oficina camila menegali r uberlandia
Oficina camila menegali r uberlandiaOficina camila menegali r uberlandia
Oficina camila menegali r uberlandia
 
Apresentação1 Animação Digital 2D I
Apresentação1 Animação Digital 2D IApresentação1 Animação Digital 2D I
Apresentação1 Animação Digital 2D I
 
Animação (2)
Animação (2)Animação (2)
Animação (2)
 
Diagnosis ⇒ Initiatives Strategy
Diagnosis ⇒ Initiatives StrategyDiagnosis ⇒ Initiatives Strategy
Diagnosis ⇒ Initiatives Strategy
 
Diagnosis ⇒ Initiatives ⇒ Strategy
Diagnosis ⇒ Initiatives ⇒ StrategyDiagnosis ⇒ Initiatives ⇒ Strategy
Diagnosis ⇒ Initiatives ⇒ Strategy
 
Teach us UK Q&A
Teach us UK Q&ATeach us UK Q&A
Teach us UK Q&A
 
工商E通培训材料
工商E通培训材料工商E通培训材料
工商E通培训材料
 
无线Vpdn产品宣介
无线Vpdn产品宣介无线Vpdn产品宣介
无线Vpdn产品宣介
 
综合办公业务介绍
综合办公业务介绍综合办公业务介绍
综合办公业务介绍
 
交通E通(业务介绍)
交通E通(业务介绍)交通E通(业务介绍)
交通E通(业务介绍)
 
Reiki presentation
Reiki presentationReiki presentation
Reiki presentation
 
Proiect manusa iri ''.
Proiect manusa iri ''.Proiect manusa iri ''.
Proiect manusa iri ''.
 
My proposal for my 2D animation
My proposal for my 2D animationMy proposal for my 2D animation
My proposal for my 2D animation
 
Cinema de animação nas escolas final 2
Cinema de animação nas escolas final 2Cinema de animação nas escolas final 2
Cinema de animação nas escolas final 2
 
Curbing Corruption while Promoting Business & Economic Growth
Curbing Corruption while Promoting Business & Economic GrowthCurbing Corruption while Promoting Business & Economic Growth
Curbing Corruption while Promoting Business & Economic Growth
 
2d animation proposal
2d animation proposal2d animation proposal
2d animation proposal
 
2d animation
2d animation2d animation
2d animation
 
An unusual bug in Lucene.Net
An unusual bug in Lucene.NetAn unusual bug in Lucene.Net
An unusual bug in Lucene.Net
 
História da Animação
História da AnimaçãoHistória da Animação
História da Animação
 

Similar to Toonz code leaves much to be desired

Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckAndrey Karpov
 
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
 
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
 
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
 
Monitoring a program that monitors computer networks
Monitoring a program that monitors computer networksMonitoring a program that monitors computer networks
Monitoring a program that monitors computer networksAndrey 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
 
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...Andrey Karpov
 
Tesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareTesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareAndrey Karpov
 
Analysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSAnalysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSPVS-Studio
 
(Slightly) Smarter Smart Pointers
(Slightly) Smarter Smart Pointers(Slightly) Smarter Smart Pointers
(Slightly) Smarter Smart PointersCarlo Pescio
 
Critical errors in CryEngine V code
Critical errors in CryEngine V codeCritical errors in CryEngine V code
Critical errors in CryEngine V codePVS-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
 
Implementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresImplementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresGowtham Reddy
 
Cpp17 and Beyond
Cpp17 and BeyondCpp17 and Beyond
Cpp17 and BeyondComicSansMS
 
Checking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerChecking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerPVS-Studio
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitAndrey Karpov
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1PVS-Studio
 
ChakraCore: analysis of JavaScript-engine for Microsoft Edge
ChakraCore: analysis of JavaScript-engine for Microsoft EdgeChakraCore: analysis of JavaScript-engine for Microsoft Edge
ChakraCore: analysis of JavaScript-engine for Microsoft EdgePVS-Studio
 
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docxgertrudebellgrove
 

Similar to Toonz code leaves much to be desired (20)

Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after Cppcheck
 
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
 
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
 
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
 
Monitoring a program that monitors computer networks
Monitoring a program that monitors computer networksMonitoring a program that monitors computer networks
Monitoring a program that monitors computer networks
 
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
 
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
 
Tesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition SoftwareTesseract. Recognizing Errors in Recognition Software
Tesseract. Recognizing Errors in Recognition Software
 
Analysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSAnalysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMS
 
(Slightly) Smarter Smart Pointers
(Slightly) Smarter Smart Pointers(Slightly) Smarter Smart Pointers
(Slightly) Smarter Smart Pointers
 
Critical errors in CryEngine V code
Critical errors in CryEngine V codeCritical errors in CryEngine V code
Critical errors in CryEngine V code
 
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
 
Implementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresImplementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphores
 
Cpp17 and Beyond
Cpp17 and BeyondCpp17 and Beyond
Cpp17 and Beyond
 
Checking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzerChecking the code of Valgrind dynamic analyzer by a static analyzer
Checking the code of Valgrind dynamic analyzer by a static analyzer
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGit
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
 
ChakraCore: analysis of JavaScript-engine for Microsoft Edge
ChakraCore: analysis of JavaScript-engine for Microsoft EdgeChakraCore: analysis of JavaScript-engine for Microsoft Edge
ChakraCore: analysis of JavaScript-engine for Microsoft Edge
 
Cc code cards
Cc code cardsCc code cards
Cc code cards
 
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx
#ifndef CRYPTO_HPP#define CRYPTO_HPP#include functional#.docx
 

Recently uploaded

英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
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
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....kzayra69
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
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
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
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
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 

Recently uploaded (20)

英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
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)
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
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...
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
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...
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
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
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 

Toonz code leaves much to be desired

  • 1. Toonz code leaves much to be desired Author: Svyatoslav Razmyslov Date: 07.04.2016 Recently the world got to know that Digital Video, the makers of TOONZ, and DWANGO, a Japanese publisher, have signed an agreement for the acquisition by Dwango of Toonz, an animation software which was independently developed by Digital Video (Rome, Italy). Digital Video and Dwango agreed to close the deal under the condition Dwango will publish, and develop, an Open Source platform based on Toonz (OpenToonz). It will include features developed by Studio Ghibli (*Toonz Ghibli Edition) which has been a long time Toonz user. "Howl's Moving Castle", "Spirited Away", "Ponyo on the Cliff by the Sea" and many other fantasy films - are among the most known fantasy films. One more cartoon of their production "Futurama" inspired our team to write this article about the source code of OpenToonz. Introduction OpenToonz is a software for producing a 2D animation. It is based on the "Toonz" project, which was developed by Digital Video in Italy. Later it was customized by Studio Ghibli, and has now been used for creating its works for many years already. Besides the animation films, this project was also used for creation of computer games - Discworld, and Claw, for instance. It should be noted that the price of the kit was about $10000, but the code quality leaves much to be desired. This project is a treasure trove for a static analyzer. The size of OpenToonz source code is about 1/10 of FreeBSD kernel, where we've found more than 40 serious bugs with the help of PVS-Studio, but here we have found much more! OpenToonz was checked in Visual Studio 2013 using PVS-Studio, version 6.03, which supports C/C++/C#, different build systems, and is still being actively developed. The compilation stage already aroused a lot of suspicion when I saw the number of compiler warnings - by the end of the build there were 1211 of them! It shows that the code wasn't really cared for! Moreover, some of the compiler warnings were disabled by #pragma warning, and even there were several bugs there, that I will speak about later. This article will be a little atypical - we are presenting bugs found in the project, which are usually common
  • 2. for novice programmers who have just started learning C/C++. I will start the description with analyzer warnings which are connected with incorrect usage of memory and pointers. Incorrect work with memory V611 The memory was allocated using 'new' operator but was released using the 'free' function. Consider inspecting operation logics behind the 'row' variable. motionblurfx.cpp 288 template <class T> void doDirectionalBlur(....) { T *row, *buffer; .... row = new T[lx + 2 * brad + 2]; // <= if (!row) return; memset(row, 0, (lx + 2 * brad + 2) * sizeof(T)); .... free(row); // <= r->unlock(); } The analyzer detected that dynamic memory is allocated and freed in incompatible ways. After the call of new[] operator the memory must be freed with the delete[] operator. Note that square brackets are used here. I want to draw your attention to this for a reason - have a look at the following example: V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] uPrime;'. tstroke.cpp 3353 double *reparameterize3D(....) { double *uPrime = new double[size]; // <= for (int i = 0; i < size; i++) { uPrime[i] = NewtonRaphsonRootFind3D(....); if (!_finite(uPrime[i])) { delete uPrime; // <= return 0;
  • 3. } } .... } In C++ operators new/delete and new[]/delete[] are used in pairs. The use of different operators for allocation and deallocation of dynamic memory is an error. In the code given above, the memory that is allocated for the uPrime array won't be correctly freed. Unfortunately, this fragment is not the only one. I have noted down 20 more fragments in the file OpenToonz_V611.txt. V554 Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete'. screensavermaker.cpp 29 void makeScreenSaver(....) { .... std::auto_ptr<char> swf(new char[swfSize]); .... } Here we have an alternative variant of the bug we have just seen, but here the operator delete is "hidden" inside of the pointer std::auto_ptr. This also leads to undefined behavior. To correct this, you must specify that delete[] must be used here. The correct code variant: std::unique_ptr<char[]> swf(new char[swfSize]); V599 The destructor was not declared as a virtual one, although the 'TTileSet' class contains virtual functions. cellselection.cpp 891 void redo() const { insertLevelAndFrameIfNeeded(); TTileSet *tiles; // <= bool isLevelCreated; pasteRasterImageInCellWithoutUndo(...., &tiles, ....); delete tiles; // <= TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } Now let's talk about memory leaks and partial destruction of objects. In this example the objects, inherited from the TTileSet class will not be completely destroyed. Description of the class TTileSet: class DVAPI TTileSet { .... protected: TDimension m_srcImageSize; typedef std::vector<Tile *> Tiles; Tiles m_tiles;
  • 4. public: TTileSet(const TDimension &dim) : m_srcImageSize(dim) { } ~TTileSet(); // <= .... virtual void add(const TRasterP &ras, TRect rect) = 0; .... virtual TTileSet *clone() const = 0; }; The class is abstract and contains pure virtual functions. You cannot create objects of this class as it is only used by derived classes. Thus, due to the missing virtual destructor in TTileSet (there is a destructor, but it isn't marked as a virtual one), all derived classes will fail to be completely cleaned. In the OpenToonz code I found several classes that are inherited from TTileSet: class DVAPI TTileSetCM32 : public TTileSet class DVAPI TTileSetCM32 : public TTileSet class DVAPI TTileSetFullColor : public TTileSet class DVAPI Tile : public TTileSet::Tile Each of these object classes (or those derived from them), will not be destroyed completely. The probable outcome, is undefined behavior; in practice, this is likely to lead to memory leaks, and other resource leaks. Developers should review the following fragments too:  V599 The virtual destructor is not present, although the 'MessageParser' class contains virtual functions. tipcsrv.cpp 91  V599 The virtual destructor is not present, although the 'ColumnToCurveMapper' class contains virtual functions. functionselection.cpp 278 Dangerous use of pointers V503 This is a nonsensical comparison: pointer < 0. styleselection.cpp 104 bool pasteStylesDataWithoutUndo(....)
  • 5. { .... if (palette->getStylePage(styleId) < 0) { // <= // styleId non e' utilizzato: uso quello // (cut/paste utilizzato per spostare stili) palette->setStyle(styleId, style); } else { // styleId e' gia' utilizzato. ne devo prendere un altro styleId = palette->getFirstUnpagedStyle(); if (styleId >= 0) palette->setStyle(styleId, style); else styleId = palette->addStyle(style); } .... } The getStylePage() function returns a pointer to some page: TPalette::Page*. Such a comparison with 0 doesn't make sense. I have researched the way the function getStylePage() is used, and saw that in all other cases the result of this function is verified against null, but here the programmer made a mistake. V522 Dereferencing of the null pointer 'region' might take place. Check the logical condition. palettecmd.cpp 102 bool isStyleUsed(const TVectorImageP vi, int styleId) { .... TRegion *region = vi->getRegion(i); if (region || region->getStyle() != styleId) return true; .... } Most likely, the programmer put operators'&&' and '||' in the incorrect places. Otherwise, if the pointer region is null, it will be dereferenced. V614 Potentially uninitialized pointer 'socket' used. Consider checking the first actual argument of the 'connect' function. tmsgcore.cpp 36 void TMsgCore::OnNewConnection() //server side { QTcpSocket *socket; if (m_tcpServer) // <= socket = m_tcpServer->nextPendingConnection(); // <= assert(socket); bool ret = connect(socket, ....); // <= ret = ret && connect(socket, ....); // <= assert(ret); m_sockets.insert(socket); } The Analyzer detected potential use of an uninitialized pointer socket. If the variable m_tcpServer is false, the pointer will not be initialized. But, being uninitialized, it can still be passed to the connect() function.
  • 6. V595 The 'batchesTask' pointer was utilized before it was verified against nullptr. Check lines: 1064, 1066. batches.cpp 1064 void BatchesController::update() { .... TFarmTask *batchesTask = getTask(batchesTaskId); // <= TFarmTask farmTask = *batchesTask; // <= if (batchesTask) { // <= QString batchesTaskParentId = batchesTask->m_parentId; m_controller->queryTaskInfo(farmTaskId, farmTask); int chunkSize = batchesTask->m_chunkSize; *batchesTask = farmTask; batchesTask->m_chunkSize = chunkSize; batchesTask->m_id = batchesTaskId; batchesTask->m_parentId = batchesTaskParentId; } .... } There are a lot of fragments where we may potentially have null pointer dereference. Usually there is a necessary check, but one or more fragments are still unsafe. For example, there is a check batchesTask, but the pointer was already dereferenced before the check. 29 similar fragments are shown here, in the file: OpenToonz_V595.txt Errors related to working with strings V530 The return value of function 'toUpper' is required to be utilized. sceneviewerevents.cpp 847 void SceneViewer::keyPressEvent(QKeyEvent *event) { .... QString text = event->text(); if ((event->modifiers() & Qt::ShiftModifier)) text.toUpper(); ....
  • 7. } ToUpper() method does not change the string 'text'. In the documentation it is described as: QString QString::toUpper(), i.e. it is a constant method. Correct code variant: QString text = event->text(); if ((event->modifiers() & Qt::ShiftModifier)) text = text.toUpper(); In the code there are three functions, whose return value is not used. All of these fragments need to be edited:  V530 The return value of function 'left' is required to be utilized. tfarmserver.cpp 569  V530 The return value of function 'ftell' is required to be utilized. tiio_bmp.cpp 804  V530 The return value of function 'accumulate' is required to be utilized. bendertool.cpp 374 V614 Uninitialized iterator 'it1' used. fxcommand.cpp 2096 QString DeleteLinksUndo::getHistoryString() { .... std::list<TFxP>::const_iterator it1; // <= std::list<TFx *>::const_iterator ft; for (ft = m_terminalFxs.begin(); ft != ....end(); ++ft) { if (ft != m_terminalFxs.begin()) str += QString(", "); str += QString("%1- -Xsheet") .arg(QString::fromStdWString((*it1)->getName())); // <= } .... } The uninitialized iterator it1 is used in the string operations. Most likely, the programmer forgot to replace it with ft iterator. V642 Saving the '_wcsicmp' function result inside the 'char' type variable is inappropriate. The significant bits could be lost, breaking the program's logic. tfilepath.cpp 328 bool TFilePath::operator<(const TFilePath &fp) const { .... char differ; differ = _wcsicmp(iName.c_str(), jName.c_str()); if (differ != 0) return differ < 0 ? true : false; .... } _wcsicmp function returns the following values of int type:  < 0 - string1 less then string2;  0 - string1 identical to string2;  > 0 - string1 greater than string2.
  • 8. Please note that '>0' can be any number, not only 1. These numbers can be: 2, 3, 100, 256, 1024, 5555, and so on. _wcsicmp function result may not fit into a variable of char type, so the comparison operator will return an unexpected result. V643 Unusual pointer arithmetic: "" + v[i]. The value of the 'char' type is being added to the string pointer. tstream.cpp 31 string escape(string v) { int i = 0; for (;;) { i = v.find_first_of("'"", i); if (i == (int)string::npos) break; string h = "" + v[i]; // <= v.insert(i, ""); i = i + 2; } return v; } The analyzer detected an error caused by adding a character constant to a string literal. It was expected that a symbol would be added to the string, but a numeric value gets added to the pointer to the string, which leads to access beyond the string literal boundary, and an unexpected result. Here is what this code is equal to: const char *p1 = ""; const int delta = v[i]; const char *p2 = *p1 + delta; string h = p2; Correct code variant: string h = string("") + v[i]; V655 The strings were concatenated, but are not utilized. Consider inspecting the 'alias + "]"' expression. plasticdeformerfx.cpp 150 string PlasticDeformerFx::getAlias(....) const { std::string alias(getFxType()); alias += "["; .... if (sd) alias += ", "+toString(sd, meshColumnObj->paramsTime(frame)); alias + "]"; // <= return alias; } The analyzer detected an expression whose result is not used. Most likely, '+' operator was accidentally written instead of '+='. As a result, a square bracket isn't added to the alias string, as the programmer planned.
  • 9. Incorrect exceptions V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw domain_error(FOO); pluginhost.cpp 1486 void Loader::doLoad(const QString &file) { .... int ret = pi->ini_(host); if (ret) { delete host; std::domain_error("failed initialized: error on ...."); } .... } The keyword throw was accidentally forgotten in the function. As a result, this code does not generate an exception in case of an error situation. Correct code variant: throw std::domain_error("failed initialized: error on ...."); V746 Type slicing. An exception should be caught by reference rather than by value. iocommand.cpp 1620 bool IoCmd::saveLevel(....) { .... try { sl->save(fp, TFilePath(), overwritePalette); } catch (TSystemException se) { // <= QApplication::restoreOverrideCursor(); MsgBox(WARNING, QString::fromStdWString(se.getMessage())); return false; } catch (...) { .... } .... }
  • 10. The analyzer detected a potential error, related to catching the exception by value. This means that a new se object of TSystemException will be constructed with the help of a copy constructor. At the same time, the code will lose some information about the exception that was stored in the classes, inherited from TSystemException. Similar suspicious fragments:  V746 Type slicing. An exception should be caught by reference rather than by value. iocommand.cpp 2650  V746 Type slicing. An exception should be caught by reference rather than by value. projectpopup.cpp 522  V746 Type slicing. An exception should be caught by reference rather than by value. projectpopup.cpp 537  V746 Type slicing. An exception should be caught by reference rather than by value. projectpopup.cpp 635  V746 Type slicing. An exception should be caught by reference rather than by value. tlevel_io.cpp 130  V746 Type slicing. An exception should be caught by reference rather than by value. calligraph.cpp 161  V746 Type slicing. An exception should be caught by reference rather than by value. calligraph.cpp 165  V746 Type slicing. An exception should be caught by reference rather than by value. patternmap.cpp 210  V746 Type slicing. An exception should be caught by reference rather than by value. patternmap.cpp 214  V746 Type slicing. An exception should be caught by reference rather than by value. patternmap.cpp 218  V746 Type slicing. An exception should be caught by reference rather than by value. scriptbinding_level.cpp 221 Incorrect conditions V547 Expression '(int) startOutPoints.size() % 2 != 2' is always true. rasterselection.cpp 852 TStroke getIntersectedStroke(TStroke &stroke, TRectD bbox) { .... for (t = 0; t < (int)outPoints.size(); t++) addPointToVector(...., (int)startOutPoints.size() % 2 != 2); ....
  • 11. } An interesting bug. Perhaps the programmer wanted to check if the size() value is even or odd. That's why the remainder of division by 2 must be compared with zero. V502 Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '+' operator. igs_motion_wind_pixel.cpp 127 void rgb_to_lightness_( const double re, const double gr, const double bl, double &li) { li=((re < gr) ? ((gr < bl) ? bl : gr) : ((re < bl) ? bl : re) + (gr < re) ? ((bl < gr) ? bl : gr) : ((bl < re) ? bl : re)) / 2.0; } In this code snippet, the programmer made a mistake related to the priority of the ternary operator ':?' . Its priority is lower than that of the addition operator. Consequently, if the condition (re < gr) is false, the following evaluations will be done incorrectly: real variables will be added to logical ones. Never use several ternary operators at once - it's the easiest way to make an error. V590 Consider inspecting the 'state == (- 3) || state != 0' expression. The expression is excessive or contains a misprint. psdutils.cpp 174 int psdUnzipWithoutPrediction(....) { .... do { state = inflate(&stream, Z_PARTIAL_FLUSH); if (state == Z_STREAM_END) break; if (state == Z_DATA_ERROR || state != Z_OK) // <= break; } while (stream.avail_out > 0); .... } The condition marked by an arrow does not depend on the result of the subexpression "state == Z_DATA_ERROR". This is easy to check, if you build a truth table of the whole conditional expression. Copy-paste programming
  • 12. V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 1448, 1454. tcenterlineskeletonizer.cpp 1448 inline void Event::processVertexEvent() { .... if (newLeftNode->m_concave) { // <= newLeftNode->m_notOpposites = m_generator->m_notOpposites; append<vector<ContourEdge *>, vector<ContourEdge *>::.... newLeftNode->m_notOpposites.push_back(newRightNode->m_edge); newLeftNode->m_notOpposites.push_back(newRightNode->....); } else if (newLeftNode->m_concave) { // <= newRightNode->m_notOpposites = m_generator->m_notOpposites; append<vector<ContourEdge *>, vector<ContourEdge *>::.... newRightNode->m_notOpposites.push_back(newLeftNode->m_edge); newRightNode->m_notOpposites.push_back(newLeftNode->....); } .... } We see that newLeftNode and newRightNode variables are confused in the conditions. As a result of this error, the else branch is never executed. Most probably, one of the conditions should be as follows: if (newRightNode-> m_concave). V501 There are identical sub-expressions to the left and to the right of the '||' operator: m_cutLx || m_cutLx canvassizepopup.cpp 271 bool m_cutLx, m_cutLy; void PeggingWidget::on00() { .... m_11->setIcon(...).rotate(m_cutLx || m_cutLx ? -90 : 90),....)); .... } There are two logical variables in the code: m_cutLx and m_cutLy that differ just in one letter. But in the example given we see that only m_cutLx gets used. Perhaps, there is a typo in one of them. V501 There are identical sub-expressions 'parentTask->m_status == Aborted' to the left and to the right of the '||' operator. tfarmcontroller.cpp 1857 void FarmController::taskSubmissionError(....) { .... if (parentTask->m_status == Aborted || // <= parentTask->m_status == Aborted) { // <= parentTask->m_completionDate = task->m_completionDate; if (parentTask->m_toBeDeleted) m_tasks.erase(itParent); } .... }
  • 13. The analyzer detected two similar comparisons with the constant Aborted. Having done a search in the file, I found a similar code block in line 2028 with this condition: if (parentTask->m_status == Completed || parentTask->m_status == Aborted) { Perhaps, the condition should be similar in this fragment. V501 There are identical sub-expressions 'cornerCoords.y > upperBound' to the left and to the right of the '||' operator. tellipticbrush.cpp 1020 template <typename T> void tellipticbrush::OutlineBuilder::addMiterSideCaps(....) { .... if (cornerCoords == TConsts::napd || cornerCoords.x < lowerBound || cornerCoords.y > upperBound || cornerCoords.y < lowerBound || cornerCoords.y > upperBound) { .... } .... } Here the programmer made a small typo, using y instead of x. I won't describe six more typos caused by copy-paste programming, I will just give them as a list. These fragments should also be definitely reviewed by the developers:  V501 There are identical sub-expressions 's.m_repoStatus == "modified"' to the left and to the right of the '||' operator. svnupdatedialog.cpp 210  V501 There are identical sub-expressions 'm_lineEdit->hasFocus()' to the left and to the right of the '||' operator. framenavigator.cpp 44  V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 750, 825. tpalette.cpp 750  V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 123, 126. igs_density.cpp 123  V523 The 'then' statement is equivalent to the 'else' statement. typetool.cpp 813  V583 The '?:' operator, regardless of its conditional expression, always returns one and the same value: Comma. tgrammar.cpp 731
  • 14. Miscellaneous errors V665 Possibly, the usage of '#pragma warning(default: X)' is incorrect in this context. The '#pragma warning(push/pop)' should be used instead. Check lines: 20, 205. tspectrum.h 205 #ifdef WIN32 #pragma warning(disable : 4251) #endif .... #ifdef WIN32 #pragma warning(default : 4251) #endif Here is how the compiler disables the warnings that were finally noticed in this project. The error is that the #pragma warning(default : X) doesn't turn on the warning, but sets it as a DEFAULT one, which can be different from what the programmer expects. The correct variant of the code should be: #ifdef WIN32 #pragma warning(push) #pragma warning(disable : 4251) #endif .... #ifdef WIN32 #pragma warning(pop) #endif V546 Member of a class is initialized by itself: 'm_subId(m_subId)'. tfarmcontroller.cpp 572 class TaskId { int m_id; int m_subId; public: TaskId(int id, int subId = -1) : m_id(id), m_subId(m_subId){}; An interesting bug in the list of class initialization. The field m_subld is initialized by itself; perhaps the programmer wanted to write m_subId(subId). V557 Array overrun is possible. The '9' index is pointing beyond array bound. tconvolve.cpp 123
  • 15. template <class PIXOUT> void doConvolve_cm32_row_9_i(....) { TPixel32 val[9]; // <= .... for (int i = 0; i < 9; ++i) { // <= OK .... else if (tone == 0) val[i] = inks[ink]; else val[i] = blend(....); } pixout->r = (typename PIXOUT::Channel)(( val[1].r * w1 + val[2].r * w2 + val[3].r * w3 + val[4].r * w4 + val[5].r * w5 + val[6].r * w6 + val[7].r * w7 + val[8].r * w8 + val[9].r * w9 + // <= ERR (1 << 15)) >> 16); pixout->g = (typename PIXOUT::Channel)(( val[1].g * w1 + val[2].g * w2 + val[3].g * w3 + val[4].g * w4 + val[5].g * w5 + val[6].g * w6 + val[7].g * w7 + val[8].g * w8 + val[9].g * w9 + // <= ERR (1 << 15)) >> 16); pixout->b = (typename PIXOUT::Channel)(( val[1].b * w1 + val[2].b * w2 + val[3].b * w3 + val[4].b * w4 + val[5].b * w5 + val[6].b * w6 + val[7].b * w7 + val[8].b * w8 + val[9].b * w9 + // <= ERR (1 << 15)) >> 16); pixout->m = (typename PIXOUT::Channel)(( val[1].m * w1 + val[2].m * w2 + val[3].m * w3 + val[4].m * w4 + val[5].m * w5 + val[6].m * w6 + val[7].m * w7 + val[8].m * w8 + val[9].m * w9 + // <= ERR (1 << 15)) >> 16); .... } It's a large code fragment, where a programmer accesses a val array, consisting of 9 elements, by the index from 1 to 9. Although, there is a loop where we see correct access of the array by the index from 0 to 8. V556 The values of different enum types are compared: m_action != EDIT_SEGMENT. Types: Action, CursorType. controlpointeditortool.cpp 257 enum Action { NONE, RECT_SELECTION, CP_MOVEMENT, SEGMENT_MOVEMENT, IN_SPEED_MOVEMENT, OUT_SPEED_MOVEMENT }; enum CursorType { NORMAL, ADD, EDIT_SPEED, EDIT_SEGMENT, NO_ACTIVE };
  • 16. void ControlPointEditorTool::drawMovingSegment() { int beforeIndex = m_moveSegmentLimitation.first; int nextIndex = m_moveSegmentLimitation.second; if (m_action != EDIT_SEGMENT || // <= beforeIndex == -1 || nextIndex == -1 || !m_moveControlPointEditorStroke.getStroke()) return; .... } The analyzer detected the comparison of enum values which have different types. Using code search I also found that the field of m_action class is initialized with a correct type, but in this fragment it is compared with a constant of a different type. Conclusion As was already mentioned, OpenToonz project is a great find for a static code analyzer: even being quite small, it has a great number of serious bugs. Not all bugs are listed in this article; moreover, we weren't able to fit some serious warnings because of their big number. We will notify the developers about the bugs found, perhaps they will be interested in improving their code. Pixar company also expressed their intention to open the source code of Universal Scene Description (USD). We are looking forward to this. For those who may be interested: you may find PVS-Studio here, and run it on your C/C++/C# projects. The analyzer works in the Windows environment, and supports various build systems.