SlideShare a Scribd company logo
1 of 10
Download to read offline
Spring RTS Engine Checkup
Author: Svyatoslav Razmyslov
Date: 03.12.2014
Spring RTS is a game engine for real-time strategy (RTS) video games. Spring was originally created to
reproduce the Total Annihilation game popular in the 9000-s. During the later years, a lot of other nice
and interesting strategy games, including commercial ones, were developed based on this engine.
Spring RTS based games are cross-platform 3D real-time strategies with huge maps and numbers of
combat and building units. However, they face certain stability issues. Let's take a look at the source
codes (thanks god, this project is open-source).
Official site.
Source code.
Being an open-source project, Spring RTS includes a number of open-source third-party libraries that
may also contain bugs which ultimately become part of the engine or games. Some diagnostic messages
cited in this article are related to the libraries that come with the engine. Especially many warnings were
triggered by Assimp (Open Asset Import Library).
Code analysis was done with the PVS-Studio tool. The article covers far not all of the bugs the analyzer
has found in the code. That's why you shouldn't treat it as a guide on bug fixing. For analysis to be much
more efficient, the developers should check the project themselves.
Typos
V501 There are identical sub-expressions 'aha->mNumWeights != oha->mNumWeights' to the left and
to the right of the '||' operator. assimp findinstancesprocess.cpp 87
struct aiBone
{
C_STRUCT aiString mName;
unsigned int mNumWeights;
C_STRUCT aiVertexWeight* mWeights;
C_STRUCT aiMatrix4x4 mOffsetMatrix;
....
};
bool CompareBones(const aiMesh* orig, const aiMesh* inst)
{
....
aiBone* aha = orig->mBones[i];
aiBone* oha = inst->mBones[i];
if (aha->mNumWeights != oha->mNumWeights || //<==
aha->mOffsetMatrix != oha->mOffsetMatrix ||
aha->mNumWeights != oha->mNumWeights) { //<==
return false;
}
....
}
There are two identical conditional expressions. In one of them, the 'mName' or 'mWeights' field of the
aiBone structure should probably be compared.
V501 There are identical sub-expressions to the left and to the right of the '||' operator: 0 == pArchive
|| 0 == pArchive assimp q3bspfileimporter.cpp 631
bool Q3BSPFileImporter::importTextureFromArchive(
const Q3BSP::Q3BSPModel *pModel,
Q3BSP::Q3BSPZipArchive *pArchive, aiScene* /*pScene*/,
aiMaterial *pMatHelper, int textureId )
{
....
if( NULL == pArchive || NULL == pArchive || NULL == pMatHelper)
{
return false;
}
if ( textureId < 0 ||
textureId >= static_cast<int>( pModel->m_Textures.size() ) )
{
return false;
}
....
}
Two more identical checks. A check for the 'pModel' pointer is most likely missing as it is pointers passed
into the function that are checked in this fragment.
V560 A part of conditional expression is always true: 0xFFFF. engine-dedicated%engine-
headless%engine-legacy%unitsync cpuid.cpp 144
void CpuId::getMasksIntelLeaf11Enumerate()
{
....
if ((ebx && 0xFFFF) == 0) //<==
return;
if (((ecx >> 8) & 0xFF) == 1) {
LOG_L(L_DEBUG,"[CpuId] SMT level found");
shiftCore = eax & 0xf;
} else {
LOG_L(L_DEBUG,"[CpuId] No SMT level supported");
}
....
}
The '&' operator should be used instead of '&&'.
V530 The return value of function 'size' is required to be utilized. assimp b3dimporter.cpp 536
void B3DImporter::ReadBB3D( aiScene *scene ){
_textures.clear();
_materials.size(); //<==
_vertices.clear();
_meshes.clear();
....
}
Calling the size() function without using its return value doesn't make any sense. Most likely, it is
necessary to call the clear() function here, like in the other lines.
V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is
unnecessary or misprint is present. engineSim weapon.cpp 597
bool CWeapon::AttackUnit(CUnit* newTargetUnit, bool isUserTarget)
{
if ((!isUserTarget && weaponDef->noAutoTarget)) {
return false;
}
....
}
The entire conditional expression is embraced in double parentheses. But it is probably the whole
expression that the complementary operator should actually be applied to, not just the 'isUserTarget'
variable. For example:
if (!(isUserTarget && weaponDef->noAutoTarget)) {
return false;
}
V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the value does
not correspond with the length of a string which was passed with the second argument. assimp
plyparser.cpp 185
PLY::ESemantic PLY::Property::ParseSemantic(....)
{
....
else if (TokenMatch(pCur,"specular_alpha",14))
{
eOut = PLY::EST_SpecularAlpha;
}
else if (TokenMatch(pCur,"opacity",7))
{
eOut = PLY::EST_Opacity;
}
else if (TokenMatch(pCur,"specular_power",6))
{
eOut = PLY::EST_PhongPower;
}
....
}
A string and its length, which is obviously different in one place, are passed into the 'TokenMatch'
function.
Other two places:
 V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the
value does not correspond with the length of a string which was passed with the second
argument. assimp aseparser.cpp 1561
 V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the
value does not correspond with the length of a string which was passed with the second
argument. assimp aseparser.cpp 1527
Copy-Paste
Apart from plain typos that occur when typing text, I singled out certain suspicious fragments cited
below. The following examples show "successfully" edited code written through the copy-paste
technique.
V519 The 'pTexture->achFormatHint[2]' variable is assigned values twice successively. Perhaps this is a
mistake. Check lines: 663, 664. assimp q3bspfileimporter.cpp 664
bool Q3BSPFileImporter::importTextureFromArchive(....)
{
....
pTexture->achFormatHint[ 0 ] = ext[ 0 ];
pTexture->achFormatHint[ 1 ] = ext[ 1 ];
pTexture->achFormatHint[ 2 ] = ext[ 2 ];
pTexture->achFormatHint[ 2 ] = '0';
....
}
The last significant character was accidentally zeroed. We even have a special article on such bugs: The
Last Line Effect.
V583 The '?:' operator, regardless of its conditional expression, always returns one and the same value:
player.cpuUsage. engine-dedicated%engine-headless%engine-legacy gameserver.cpp 902
void CGameServer::LagProtection()
{
....
const float playerCpuUsage =
player.isLocal ? player.cpuUsage : player.cpuUsage; //<==
....
}
I don't think anyone uses conditional constructs when there is no choice. Looks like the programmer
forgot to fix one variable here.
V524 It is odd that the body of '-' function is fully equivalent to the body of '+' function. assimp%engine-
headless%engine-legacy types.h 183
/** Component-wise addition */
aiColor3D operator+(const aiColor3D& c) const {
return aiColor3D(r+c.r,g+c.g,b+c.b);
}
/** Component-wise subtraction */
aiColor3D operator-(const aiColor3D& c) const {
return aiColor3D(r+c.r,g+c.g,b+c.b);
}
Addition and subtraction functions are implemented in a suspiciously similar fashion. It must be that the
programmer forgot to change the sign in the subtraction function.
V524 It is odd that the body of '>' function is fully equivalent to the body of '<' function. assimp
3dshelper.h 470
bool operator < (const aiFloatKey& o) const
{return mTime < o.mTime;}
bool operator > (const aiFloatKey& o) const
{return mTime < o.mTime;}
Comparison operators opposed in their meaning look even stranger when implemented in the same
way.
Formatting
In this section, we are going to discuss suspicious fragments related to code formatting. If the issues
described here are genuine errors or not is up to the authors to decide, but the programming style in
these fragments is obviously far from perfect.
V628 It's possible that the line was commented out improperly, thus altering the program's operation
logics. assimp colladaparser.cpp 2281
void ColladaParser::ReadSceneLibrary()
{
....
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
{
if( strcmp( mReader->getNodeName(), "....") == 0)
//ThrowException( "Expected end of "...." element.");
break;
}
....
}
It was 'break' that used to be called all the time in this code originally, but now the loop is terminated
only by condition. Perhaps the condition itself should have been commented out too.
V640 The code's operational logic does not correspond with its formatting. The second statement will
always be executed. It is possible that curly brackets are missing. sound oggstream.cpp 256
bool COggStream::UpdateBuffers()
{
....
active = DecodeStream(buffer);
if (active)
alSourceQueueBuffers(source, 1, &buffer); CheckError("....");
....
}
The CheckError() function is not part of the condition although it is written as if it were.
V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. streflop
s_atanf.cpp 90
Simple __atanf(Simple x)
{
....
ix = hx&0x7fffffff;
if(ix>=0x50800000) { /* if |x| >= 2^34 */
if(ix>0x7f800000)
return x+x; /* NaN */
if(hx>0) return atanhi[3]+atanlo[3];
else return -atanhi[3]-atanlo[3];
} if (ix < 0x3ee00000) { /* |x| < 0.4375f */ //<==
if (ix < 0x31000000) { /* |x| < 2^-29 */
if(huge+x>one) return x; /* raise inexact */
}
id = -1;
} else {
....
}
....
}
The if operator is in the same line as the closing brace of the previous if. There may be the keyword
'else' missing in this place and then the program works quite differently than the programmer expected.
V640 The code's operational logic does not correspond with its formatting. The statement is indented to
the right, but it is always executed. It is possible that curly brackets are missing. AAI aaibrain.cpp 1138
void AAIBrain::BuildUnitOfMovementType(....)
{
....
if(ai->Getbt()->units_static[unit].cost < ....)
{
if(ai->Getexecute()->AddUnitToBuildqueue(unit, 3, urgent))
{
ai->Getbt()->units_dynamic[unit].requested += 3;
ai->Getut()->UnitRequested(....);
}
}
else if(ai->Getbt()->units_static[unit].cost < ....)
{
if(ai->Getexecute()->AddUnitToBuildqueue(unit, 2, urgent))
ai->Getbt()->units_dynamic[unit].requested += 2;
ai->Getut()->UnitRequested(....);
}
else
{
if(ai->Getexecute()->AddUnitToBuildqueue(unit, 1, urgent))
ai->Getbt()->units_dynamic[unit].requested += 1;
ai->Getut()->UnitRequested(....);
}
....
}
Two operators in conditions are shifted here at once. It wouldn't look that strange but for another
similar condition with correctly arranged braces earlier in the code.
Pointers
V571 Recurring check. The 'if (0 == MatFilePtr)' condition was already verified in line 140. assimp
ogrematerial.cpp 143
aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName)
const
{
....
MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName);
if(NULL==MatFilePtr)
{
//try the default mat Library
if(NULL==MatFilePtr)
{
MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename);
....
}
}
....
}
Repeating checks are not errors, but there are a lot of fragments in the project where checks are really
missing.
V595 The 'model->GetRootPiece()' pointer was utilized before it was verified against nullptr. Check lines:
236, 238. engine-headless%engine-legacy imodelparser.cpp 236
S3DModel* C3DModelLoader::Load3DModel(std::string modelName)
{
....
model->GetRootPiece()->SetCollisionVolume( //<==
new CollisionVolume("box", -UpVector, ZeroVector));
if (model->GetRootPiece() != NULL) { //<==
CreateLists(model->GetRootPiece());
}
....
}
In this code fragment, for instance, the programmer should have checked the pointer before
dereferencing it.
Other similar fragments:
 V595 The 'szComment' pointer was utilized before it was verified against nullptr. Check lines:
1559, 1564. assimp unzip.c 1559
 V595 The 'facCAI' pointer was utilized before it was verified against nullptr. Check lines: 1059,
1064. engineSim commandai.cpp 1059
 V595 The 'projectileDrawer' pointer was utilized before it was verified against nullptr. Check
lines: 170, 176. engineSim shieldprojectile.cpp 170
 V595 The 'szComment' pointer was utilized before it was verified against nullptr. Check lines:
2068, 2073. minizip unzip.c 2068
V576 Incorrect format. Consider checking the fifth actual argument of the 'sprintf' function. To print the
value of pointer the '%p' should be used. engine-dedicated%engine-headless%engine-legacy seh.cpp 45
void __cdecl
se_translator_function(unsigned int err,
struct _EXCEPTION_POINTERS* ep)
{
char buf[128];
sprintf(buf,"%s(0x%08x) at 0x%08x",ExceptionName(err), //<==
errep->ExceptionRecord->ExceptionAddress); //<==
CrashHandler::ExceptionHandler(ep);
throw std::exception(buf);
}
To print a pointer, the %p specifier should be used. The current code will work correctly as long as the
pointer size coincides with that of the 'int' type.
V643 Unusual pointer arithmetic: ".." + io->getOsSeparator(). The value of the 'char' type is being added
to the string pointer. assimp lwsloader.cpp 467
std::string LWSImporter::FindLWOFile(const std::string& in)
{
....
std::string test = ".." + io->getOsSeparator() + tmp; //<==
if (io->Exists(test))
return test;
test = ".." + io->getOsSeparator() + test; //<==
if (io->Exists(test)) {
return test;
}
....
}
The programmer expected that the "..tmp" string would be received, but in this case an integer value
will be added to the pointer to the ".." string instead. It will surely cause a string literal overflow. To
prevent issues like that, one should avoid using such arithmetic operations over string and character
variables.
The correct code:
std::string test = std::string("..") + io->getOsSeparator() + tmp;
Memory handling
V512 A call of the 'memset' function will lead to underflow of the buffer 'area'. RAI gterrainmap.h 84
#define MAP_AREA_LIST_SIZE 50
struct TerrainMapMobileType
{
TerrainMapMobileType()
{
....
memset(area,0,MAP_AREA_LIST_SIZE); //<==
};
TerrainMapArea *area[MAP_AREA_LIST_SIZE]; //<==
....
};
Incomplete memory zeroing. An array of 50 pointers is declared but only 50 bytes are zeroed, the size of
the array being 50*sizeof(pointer) bytes.
Other similar issues:
 V512 A call of the 'memset' function will lead to underflow of the buffer 'BQ'. RAI builder.cpp 67
 V512 A call of the 'memset' function will lead to underflow of the buffer 'SL'. RAI
unitmanager.cpp 28
 V512 A call of the 'memset' function will lead to underflow of the buffer 'Group'. RAI
unitmanager.cpp 29
 V512 A call of the 'memset' function will lead to underflow of the buffer 'eventList'. RAI rai.cpp
77
V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'dest' is lost.
Consider assigning realloc() to a temporary pointer. assimp blenderloader.cpp 217
void BlenderImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
....
dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
memcpy(dest + total - have,block,have);
....
}
If the size of a memory block can't be changed, the realloc() function will return a null pointer, while the
pointer to the previous memory area will be lost. It is necessary to save the pointer into a buffer variable
and make corresponding checks.
Another issue of that kind:
 V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'dest' is
lost. Consider assigning realloc() to a temporary pointer. assimp xglloader.cpp 181
Undefined behavior
V610 Undefined behavior. Check the shift operator '<<. The left operand '(- 1)' is negative. engine-
dedicated%engine-headless%engine-legacy%unitsync cpuid.cpp 176
void CpuId::getMasksIntelLeaf11()
{
getMasksIntelLeaf11Enumerate();
// We determined the shifts now compute the masks
maskVirtual = ~((-1) << shiftCore);
maskCore = (~((-1) << shiftPackage)) ^ maskVirtual;
maskPackage = (-1) << shiftPackage;
}
Under the C++11 language standard, shifting a negative number causes undefined behavior.
Conclusion
I hope improving this project's quality will also stimulate improvement of all the products based on it.
It's quite a nice project for beginner game developers and ordinary gamers, followers of the RTS genre.
Using static analysis regularly will help you save plenty of time to solve more serious tasks.

More Related Content

What's hot

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
 
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
 
Checking OpenCV with PVS-Studio
Checking OpenCV with PVS-StudioChecking OpenCV with PVS-Studio
Checking OpenCV with PVS-StudioPVS-Studio
 
PVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio
 
Checking Wine with PVS-Studio and Clang Static Analyzer
Checking Wine with PVS-Studio and Clang Static AnalyzerChecking Wine with PVS-Studio and Clang Static Analyzer
Checking Wine with PVS-Studio and Clang Static AnalyzerAndrey Karpov
 
Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016PVS-Studio
 
Dusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind projectDusting the globe: analysis of NASA World Wind project
Dusting the globe: analysis of NASA World Wind projectPVS-Studio
 
Analyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectAnalyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectPVS-Studio
 
Toonz code leaves much to be desired
Toonz code leaves much to be desiredToonz code leaves much to be desired
Toonz code leaves much to be desiredPVS-Studio
 
A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)A Slipshod Check of the Visual C++ 2013 Library (update 3)
A Slipshod Check of the Visual C++ 2013 Library (update 3)Andrey Karpov
 
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Mr. Vengineer
 
Linux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLiteLinux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLitePVS-Studio
 
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Mr. Vengineer
 
Python and Ruby implementations compared by the error density
Python and Ruby implementations compared by the error densityPython and Ruby implementations compared by the error density
Python and Ruby implementations compared by the error densityPVS-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
 
A fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBoxA fresh eye on Oracle VM VirtualBox
A fresh eye on Oracle VM VirtualBoxPVS-Studio
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckAndrey Karpov
 
HailDB: A NoSQL API Direct to InnoDB
HailDB: A NoSQL API Direct to InnoDBHailDB: A NoSQL API Direct to InnoDB
HailDB: A NoSQL API Direct to InnoDBstewartsmith
 
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2 「エッジAIモダン計測制御の世界」オ...
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2  「エッジAIモダン計測制御の世界」オ...Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2  「エッジAIモダン計測制御の世界」オ...
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2 「エッジAIモダン計測制御の世界」オ...Mr. Vengineer
 

What's hot (20)

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
 
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
 
Checking OpenCV with PVS-Studio
Checking OpenCV with PVS-StudioChecking OpenCV with PVS-Studio
Checking OpenCV with PVS-Studio
 
PVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - ContinuationPVS-Studio vs Chromium - Continuation
PVS-Studio vs Chromium - Continuation
 
Checking Wine with PVS-Studio and Clang Static Analyzer
Checking Wine with PVS-Studio and Clang Static AnalyzerChecking Wine with PVS-Studio and Clang Static Analyzer
Checking Wine with PVS-Studio and Clang Static Analyzer
 
Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016Top 10 C# projects errors found in 2016
Top 10 C# projects errors found in 2016
 
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
 
Analyzing the Dolphin-emu project
Analyzing the Dolphin-emu projectAnalyzing the Dolphin-emu project
Analyzing the Dolphin-emu project
 
Toonz code leaves much to be desired
Toonz code leaves much to be desiredToonz code leaves much to be desired
Toonz code leaves much to be desired
 
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)
 
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
 
Linux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLiteLinux version of PVS-Studio couldn't help checking CodeLite
Linux version of PVS-Studio couldn't help checking CodeLite
 
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
 
Python and Ruby implementations compared by the error density
Python and Ruby implementations compared by the error densityPython and Ruby implementations compared by the error density
Python and Ruby implementations compared by the error density
 
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
 
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
 
Picking Mushrooms after Cppcheck
Picking Mushrooms after CppcheckPicking Mushrooms after Cppcheck
Picking Mushrooms after Cppcheck
 
HailDB: A NoSQL API Direct to InnoDB
HailDB: A NoSQL API Direct to InnoDBHailDB: A NoSQL API Direct to InnoDB
HailDB: A NoSQL API Direct to InnoDB
 
TVM VTA (TSIM)
TVM VTA (TSIM) TVM VTA (TSIM)
TVM VTA (TSIM)
 
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2 「エッジAIモダン計測制御の世界」オ...
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2  「エッジAIモダン計測制御の世界」オ...Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2  「エッジAIモダン計測制御の世界」オ...
Google Edge TPUで TensorFlow Liteを使った時に 何をやっているのかを妄想してみる 2 「エッジAIモダン計測制御の世界」オ...
 

Viewers also liked

Costco case: Costco Mission, Business Model and Strategy
Costco case: Costco Mission, Business Model and StrategyCostco case: Costco Mission, Business Model and Strategy
Costco case: Costco Mission, Business Model and StrategyTran Thang
 
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...Mailing Day
 
Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!PVS-Studio
 
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?Why Don't Software Developers Use Static Analysis Tools to Find Bugs?
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?PVS-Studio
 
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.PVS-Studio
 
Type Conversion in C++ and C# Arithmetic Expressions
Type Conversion in C++ and C# Arithmetic ExpressionsType Conversion in C++ and C# Arithmetic Expressions
Type Conversion in C++ and C# Arithmetic ExpressionsPVS-Studio
 
How Applications of BIG DATA Drive Industries
How Applications of BIG DATA Drive IndustriesHow Applications of BIG DATA Drive Industries
How Applications of BIG DATA Drive IndustriesTyrone Systems
 
05.70 JAVA SE_java list
05.70  JAVA SE_java list05.70  JAVA SE_java list
05.70 JAVA SE_java listJefri Fahrian
 
Visualizing & gamifying water & energy consumption for behavioral change
Visualizing & gamifying water & energy consumption for behavioral changeVisualizing & gamifying water & energy consumption for behavioral change
Visualizing & gamifying water & energy consumption for behavioral changeSmartH2O
 
Contact the Expert Astrology Guru - Mr. Rajat Nayar
Contact the Expert Astrology Guru -  Mr. Rajat NayarContact the Expert Astrology Guru -  Mr. Rajat Nayar
Contact the Expert Astrology Guru - Mr. Rajat NayarRajat Nayar
 
نمونه سوالات مبانی-الهام جهانپور-منطقه فارسان
نمونه سوالات مبانی-الهام جهانپور-منطقه فارساننمونه سوالات مبانی-الهام جهانپور-منطقه فارسان
نمونه سوالات مبانی-الهام جهانپور-منطقه فارسانtarasad
 
06.84 JAVA SE_drawing graphics
06.84 JAVA SE_drawing graphics06.84 JAVA SE_drawing graphics
06.84 JAVA SE_drawing graphicsJefri Fahrian
 
Tonyg_LetterofRecommendation
Tonyg_LetterofRecommendationTonyg_LetterofRecommendation
Tonyg_LetterofRecommendationZachary Cowher
 
2° Codelab - Por onde começar com AngularJS
2° Codelab  - Por onde começar com AngularJS2° Codelab  - Por onde começar com AngularJS
2° Codelab - Por onde começar com AngularJSGDGFoz
 
visions of hope the real deal
visions of hope the real dealvisions of hope the real deal
visions of hope the real dealSylvester Arayomi
 

Viewers also liked (17)

Costco case: Costco Mission, Business Model and Strategy
Costco case: Costco Mission, Business Model and StrategyCostco case: Costco Mission, Business Model and Strategy
Costco case: Costco Mission, Business Model and Strategy
 
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...
Александр Рысь. MailingDay Moscow 2016. Email, sms, web push - идеальный микс...
 
Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!
 
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?Why Don't Software Developers Use Static Analysis Tools to Find Bugs?
Why Don't Software Developers Use Static Analysis Tools to Find Bugs?
 
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.
Celebrating 30-th anniversary of the first C++ compiler: let's find bugs in it.
 
Type Conversion in C++ and C# Arithmetic Expressions
Type Conversion in C++ and C# Arithmetic ExpressionsType Conversion in C++ and C# Arithmetic Expressions
Type Conversion in C++ and C# Arithmetic Expressions
 
How Applications of BIG DATA Drive Industries
How Applications of BIG DATA Drive IndustriesHow Applications of BIG DATA Drive Industries
How Applications of BIG DATA Drive Industries
 
05.70 JAVA SE_java list
05.70  JAVA SE_java list05.70  JAVA SE_java list
05.70 JAVA SE_java list
 
Visualizing & gamifying water & energy consumption for behavioral change
Visualizing & gamifying water & energy consumption for behavioral changeVisualizing & gamifying water & energy consumption for behavioral change
Visualizing & gamifying water & energy consumption for behavioral change
 
Contact the Expert Astrology Guru - Mr. Rajat Nayar
Contact the Expert Astrology Guru -  Mr. Rajat NayarContact the Expert Astrology Guru -  Mr. Rajat Nayar
Contact the Expert Astrology Guru - Mr. Rajat Nayar
 
نمونه سوالات مبانی-الهام جهانپور-منطقه فارسان
نمونه سوالات مبانی-الهام جهانپور-منطقه فارساننمونه سوالات مبانی-الهام جهانپور-منطقه فارسان
نمونه سوالات مبانی-الهام جهانپور-منطقه فارسان
 
Kastellegård tillfälle 6
Kastellegård tillfälle 6Kastellegård tillfälle 6
Kastellegård tillfälle 6
 
06.84 JAVA SE_drawing graphics
06.84 JAVA SE_drawing graphics06.84 JAVA SE_drawing graphics
06.84 JAVA SE_drawing graphics
 
Tonyg_LetterofRecommendation
Tonyg_LetterofRecommendationTonyg_LetterofRecommendation
Tonyg_LetterofRecommendation
 
credential
credentialcredential
credential
 
2° Codelab - Por onde começar com AngularJS
2° Codelab  - Por onde começar com AngularJS2° Codelab  - Por onde começar com AngularJS
2° Codelab - Por onde começar com AngularJS
 
visions of hope the real deal
visions of hope the real dealvisions of hope the real deal
visions of hope the real deal
 

Similar to Spring RTS Engine Checkup

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
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...PVS-Studio
 
Analyzing Firebird 3.0
Analyzing Firebird 3.0Analyzing Firebird 3.0
Analyzing Firebird 3.0PVS-Studio
 
Rechecking Apache HTTP Server
Rechecking Apache HTTP ServerRechecking Apache HTTP Server
Rechecking Apache HTTP ServerPVS-Studio
 
A Post About Analyzing PHP
A Post About Analyzing PHPA Post About Analyzing PHP
A Post About Analyzing PHPAndrey Karpov
 
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ..."Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...PVS-Studio
 
Analysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsAnalysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsPVS-Studio
 
Analysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectAnalysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectPVS-Studio
 
Analysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectAnalysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectPVS-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
 
Headache from using mathematical software
Headache from using mathematical softwareHeadache from using mathematical software
Headache from using mathematical softwarePVS-Studio
 
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-StudioAndrey Karpov
 
Explanations to the article on Copy-Paste
Explanations to the article on Copy-PasteExplanations to the article on Copy-Paste
Explanations to the article on Copy-PastePVS-Studio
 
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) projectPVS-Studio
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio
 
Checking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerChecking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerPVS-Studio
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggyAndrey Karpov
 
The Unicorn Getting Interested in KDE
The Unicorn Getting Interested in KDEThe Unicorn Getting Interested in KDE
The Unicorn Getting Interested in KDEAndrey Karpov
 
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...PVS-Studio
 

Similar to Spring RTS Engine Checkup (20)

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
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
 
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
 
Rechecking Apache HTTP Server
Rechecking Apache HTTP ServerRechecking Apache HTTP Server
Rechecking Apache HTTP Server
 
A Post About Analyzing PHP
A Post About Analyzing PHPA Post About Analyzing PHP
A Post About Analyzing PHP
 
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ..."Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
 
Analysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsAnalysis of Microsoft Code Contracts
Analysis of Microsoft Code Contracts
 
Analysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectAnalysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox project
 
Analysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox projectAnalysis of the Ultimate Toolbox project
Analysis of the Ultimate Toolbox project
 
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
 
Headache from using mathematical software
Headache from using mathematical softwareHeadache from using mathematical software
Headache from using mathematical software
 
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
 
Explanations to the article on Copy-Paste
Explanations to the article on Copy-PasteExplanations to the article on Copy-Paste
Explanations to the article on Copy-Paste
 
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
 
PVS-Studio Meets Octave
PVS-Studio Meets Octave PVS-Studio Meets Octave
PVS-Studio Meets Octave
 
Checking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerChecking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzer
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
The Unicorn Getting Interested in KDE
The Unicorn Getting Interested in KDEThe Unicorn Getting Interested in KDE
The Unicorn Getting Interested in KDE
 
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...
 

Recently uploaded

Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
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
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
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.
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
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
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
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
 
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
 

Recently uploaded (20)

Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
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)
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
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
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
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...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
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
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
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
 
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
 

Spring RTS Engine Checkup

  • 1. Spring RTS Engine Checkup Author: Svyatoslav Razmyslov Date: 03.12.2014 Spring RTS is a game engine for real-time strategy (RTS) video games. Spring was originally created to reproduce the Total Annihilation game popular in the 9000-s. During the later years, a lot of other nice and interesting strategy games, including commercial ones, were developed based on this engine. Spring RTS based games are cross-platform 3D real-time strategies with huge maps and numbers of combat and building units. However, they face certain stability issues. Let's take a look at the source codes (thanks god, this project is open-source). Official site. Source code. Being an open-source project, Spring RTS includes a number of open-source third-party libraries that may also contain bugs which ultimately become part of the engine or games. Some diagnostic messages cited in this article are related to the libraries that come with the engine. Especially many warnings were triggered by Assimp (Open Asset Import Library). Code analysis was done with the PVS-Studio tool. The article covers far not all of the bugs the analyzer has found in the code. That's why you shouldn't treat it as a guide on bug fixing. For analysis to be much more efficient, the developers should check the project themselves.
  • 2. Typos V501 There are identical sub-expressions 'aha->mNumWeights != oha->mNumWeights' to the left and to the right of the '||' operator. assimp findinstancesprocess.cpp 87 struct aiBone { C_STRUCT aiString mName; unsigned int mNumWeights; C_STRUCT aiVertexWeight* mWeights; C_STRUCT aiMatrix4x4 mOffsetMatrix; .... }; bool CompareBones(const aiMesh* orig, const aiMesh* inst) { .... aiBone* aha = orig->mBones[i]; aiBone* oha = inst->mBones[i]; if (aha->mNumWeights != oha->mNumWeights || //<== aha->mOffsetMatrix != oha->mOffsetMatrix || aha->mNumWeights != oha->mNumWeights) { //<== return false; } .... } There are two identical conditional expressions. In one of them, the 'mName' or 'mWeights' field of the aiBone structure should probably be compared. V501 There are identical sub-expressions to the left and to the right of the '||' operator: 0 == pArchive || 0 == pArchive assimp q3bspfileimporter.cpp 631 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, Q3BSP::Q3BSPZipArchive *pArchive, aiScene* /*pScene*/, aiMaterial *pMatHelper, int textureId ) { .... if( NULL == pArchive || NULL == pArchive || NULL == pMatHelper) { return false; } if ( textureId < 0 || textureId >= static_cast<int>( pModel->m_Textures.size() ) ) { return false; } .... } Two more identical checks. A check for the 'pModel' pointer is most likely missing as it is pointers passed into the function that are checked in this fragment. V560 A part of conditional expression is always true: 0xFFFF. engine-dedicated%engine- headless%engine-legacy%unitsync cpuid.cpp 144
  • 3. void CpuId::getMasksIntelLeaf11Enumerate() { .... if ((ebx && 0xFFFF) == 0) //<== return; if (((ecx >> 8) & 0xFF) == 1) { LOG_L(L_DEBUG,"[CpuId] SMT level found"); shiftCore = eax & 0xf; } else { LOG_L(L_DEBUG,"[CpuId] No SMT level supported"); } .... } The '&' operator should be used instead of '&&'. V530 The return value of function 'size' is required to be utilized. assimp b3dimporter.cpp 536 void B3DImporter::ReadBB3D( aiScene *scene ){ _textures.clear(); _materials.size(); //<== _vertices.clear(); _meshes.clear(); .... } Calling the size() function without using its return value doesn't make any sense. Most likely, it is necessary to call the clear() function here, like in the other lines. V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present. engineSim weapon.cpp 597 bool CWeapon::AttackUnit(CUnit* newTargetUnit, bool isUserTarget) { if ((!isUserTarget && weaponDef->noAutoTarget)) { return false; } .... } The entire conditional expression is embraced in double parentheses. But it is probably the whole expression that the complementary operator should actually be applied to, not just the 'isUserTarget' variable. For example: if (!(isUserTarget && weaponDef->noAutoTarget)) { return false; } V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the value does not correspond with the length of a string which was passed with the second argument. assimp plyparser.cpp 185 PLY::ESemantic PLY::Property::ParseSemantic(....) { .... else if (TokenMatch(pCur,"specular_alpha",14))
  • 4. { eOut = PLY::EST_SpecularAlpha; } else if (TokenMatch(pCur,"opacity",7)) { eOut = PLY::EST_Opacity; } else if (TokenMatch(pCur,"specular_power",6)) { eOut = PLY::EST_PhongPower; } .... } A string and its length, which is obviously different in one place, are passed into the 'TokenMatch' function. Other two places:  V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the value does not correspond with the length of a string which was passed with the second argument. assimp aseparser.cpp 1561  V666 Consider inspecting third argument of the function 'TokenMatch'. It is possible that the value does not correspond with the length of a string which was passed with the second argument. assimp aseparser.cpp 1527 Copy-Paste Apart from plain typos that occur when typing text, I singled out certain suspicious fragments cited below. The following examples show "successfully" edited code written through the copy-paste technique. V519 The 'pTexture->achFormatHint[2]' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 663, 664. assimp q3bspfileimporter.cpp 664 bool Q3BSPFileImporter::importTextureFromArchive(....) { .... pTexture->achFormatHint[ 0 ] = ext[ 0 ]; pTexture->achFormatHint[ 1 ] = ext[ 1 ]; pTexture->achFormatHint[ 2 ] = ext[ 2 ]; pTexture->achFormatHint[ 2 ] = '0'; .... } The last significant character was accidentally zeroed. We even have a special article on such bugs: The Last Line Effect. V583 The '?:' operator, regardless of its conditional expression, always returns one and the same value: player.cpuUsage. engine-dedicated%engine-headless%engine-legacy gameserver.cpp 902 void CGameServer::LagProtection() { .... const float playerCpuUsage = player.isLocal ? player.cpuUsage : player.cpuUsage; //<==
  • 5. .... } I don't think anyone uses conditional constructs when there is no choice. Looks like the programmer forgot to fix one variable here. V524 It is odd that the body of '-' function is fully equivalent to the body of '+' function. assimp%engine- headless%engine-legacy types.h 183 /** Component-wise addition */ aiColor3D operator+(const aiColor3D& c) const { return aiColor3D(r+c.r,g+c.g,b+c.b); } /** Component-wise subtraction */ aiColor3D operator-(const aiColor3D& c) const { return aiColor3D(r+c.r,g+c.g,b+c.b); } Addition and subtraction functions are implemented in a suspiciously similar fashion. It must be that the programmer forgot to change the sign in the subtraction function. V524 It is odd that the body of '>' function is fully equivalent to the body of '<' function. assimp 3dshelper.h 470 bool operator < (const aiFloatKey& o) const {return mTime < o.mTime;} bool operator > (const aiFloatKey& o) const {return mTime < o.mTime;} Comparison operators opposed in their meaning look even stranger when implemented in the same way. Formatting In this section, we are going to discuss suspicious fragments related to code formatting. If the issues described here are genuine errors or not is up to the authors to decide, but the programming style in these fragments is obviously far from perfect. V628 It's possible that the line was commented out improperly, thus altering the program's operation logics. assimp colladaparser.cpp 2281 void ColladaParser::ReadSceneLibrary() { .... else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if( strcmp( mReader->getNodeName(), "....") == 0) //ThrowException( "Expected end of "...." element."); break; } .... } It was 'break' that used to be called all the time in this code originally, but now the loop is terminated only by condition. Perhaps the condition itself should have been commented out too.
  • 6. V640 The code's operational logic does not correspond with its formatting. The second statement will always be executed. It is possible that curly brackets are missing. sound oggstream.cpp 256 bool COggStream::UpdateBuffers() { .... active = DecodeStream(buffer); if (active) alSourceQueueBuffers(source, 1, &buffer); CheckError("...."); .... } The CheckError() function is not part of the condition although it is written as if it were. V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. streflop s_atanf.cpp 90 Simple __atanf(Simple x) { .... ix = hx&0x7fffffff; if(ix>=0x50800000) { /* if |x| >= 2^34 */ if(ix>0x7f800000) return x+x; /* NaN */ if(hx>0) return atanhi[3]+atanlo[3]; else return -atanhi[3]-atanlo[3]; } if (ix < 0x3ee00000) { /* |x| < 0.4375f */ //<== if (ix < 0x31000000) { /* |x| < 2^-29 */ if(huge+x>one) return x; /* raise inexact */ } id = -1; } else { .... } .... } The if operator is in the same line as the closing brace of the previous if. There may be the keyword 'else' missing in this place and then the program works quite differently than the programmer expected. V640 The code's operational logic does not correspond with its formatting. The statement is indented to the right, but it is always executed. It is possible that curly brackets are missing. AAI aaibrain.cpp 1138 void AAIBrain::BuildUnitOfMovementType(....) { .... if(ai->Getbt()->units_static[unit].cost < ....) { if(ai->Getexecute()->AddUnitToBuildqueue(unit, 3, urgent)) { ai->Getbt()->units_dynamic[unit].requested += 3; ai->Getut()->UnitRequested(....); } } else if(ai->Getbt()->units_static[unit].cost < ....) {
  • 7. if(ai->Getexecute()->AddUnitToBuildqueue(unit, 2, urgent)) ai->Getbt()->units_dynamic[unit].requested += 2; ai->Getut()->UnitRequested(....); } else { if(ai->Getexecute()->AddUnitToBuildqueue(unit, 1, urgent)) ai->Getbt()->units_dynamic[unit].requested += 1; ai->Getut()->UnitRequested(....); } .... } Two operators in conditions are shifted here at once. It wouldn't look that strange but for another similar condition with correctly arranged braces earlier in the code. Pointers V571 Recurring check. The 'if (0 == MatFilePtr)' condition was already verified in line 140. assimp ogrematerial.cpp 143 aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const { .... MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName); if(NULL==MatFilePtr) { //try the default mat Library if(NULL==MatFilePtr) { MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename); .... } } .... } Repeating checks are not errors, but there are a lot of fragments in the project where checks are really missing. V595 The 'model->GetRootPiece()' pointer was utilized before it was verified against nullptr. Check lines: 236, 238. engine-headless%engine-legacy imodelparser.cpp 236 S3DModel* C3DModelLoader::Load3DModel(std::string modelName) { .... model->GetRootPiece()->SetCollisionVolume( //<== new CollisionVolume("box", -UpVector, ZeroVector)); if (model->GetRootPiece() != NULL) { //<== CreateLists(model->GetRootPiece()); } .... }
  • 8. In this code fragment, for instance, the programmer should have checked the pointer before dereferencing it. Other similar fragments:  V595 The 'szComment' pointer was utilized before it was verified against nullptr. Check lines: 1559, 1564. assimp unzip.c 1559  V595 The 'facCAI' pointer was utilized before it was verified against nullptr. Check lines: 1059, 1064. engineSim commandai.cpp 1059  V595 The 'projectileDrawer' pointer was utilized before it was verified against nullptr. Check lines: 170, 176. engineSim shieldprojectile.cpp 170  V595 The 'szComment' pointer was utilized before it was verified against nullptr. Check lines: 2068, 2073. minizip unzip.c 2068 V576 Incorrect format. Consider checking the fifth actual argument of the 'sprintf' function. To print the value of pointer the '%p' should be used. engine-dedicated%engine-headless%engine-legacy seh.cpp 45 void __cdecl se_translator_function(unsigned int err, struct _EXCEPTION_POINTERS* ep) { char buf[128]; sprintf(buf,"%s(0x%08x) at 0x%08x",ExceptionName(err), //<== errep->ExceptionRecord->ExceptionAddress); //<== CrashHandler::ExceptionHandler(ep); throw std::exception(buf); } To print a pointer, the %p specifier should be used. The current code will work correctly as long as the pointer size coincides with that of the 'int' type. V643 Unusual pointer arithmetic: ".." + io->getOsSeparator(). The value of the 'char' type is being added to the string pointer. assimp lwsloader.cpp 467 std::string LWSImporter::FindLWOFile(const std::string& in) { .... std::string test = ".." + io->getOsSeparator() + tmp; //<== if (io->Exists(test)) return test; test = ".." + io->getOsSeparator() + test; //<== if (io->Exists(test)) { return test; } .... } The programmer expected that the "..tmp" string would be received, but in this case an integer value will be added to the pointer to the ".." string instead. It will surely cause a string literal overflow. To prevent issues like that, one should avoid using such arithmetic operations over string and character variables. The correct code: std::string test = std::string("..") + io->getOsSeparator() + tmp;
  • 9. Memory handling V512 A call of the 'memset' function will lead to underflow of the buffer 'area'. RAI gterrainmap.h 84 #define MAP_AREA_LIST_SIZE 50 struct TerrainMapMobileType { TerrainMapMobileType() { .... memset(area,0,MAP_AREA_LIST_SIZE); //<== }; TerrainMapArea *area[MAP_AREA_LIST_SIZE]; //<== .... }; Incomplete memory zeroing. An array of 50 pointers is declared but only 50 bytes are zeroed, the size of the array being 50*sizeof(pointer) bytes. Other similar issues:  V512 A call of the 'memset' function will lead to underflow of the buffer 'BQ'. RAI builder.cpp 67  V512 A call of the 'memset' function will lead to underflow of the buffer 'SL'. RAI unitmanager.cpp 28  V512 A call of the 'memset' function will lead to underflow of the buffer 'Group'. RAI unitmanager.cpp 29  V512 A call of the 'memset' function will lead to underflow of the buffer 'eventList'. RAI rai.cpp 77 V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'dest' is lost. Consider assigning realloc() to a temporary pointer. assimp blenderloader.cpp 217 void BlenderImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { .... dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); memcpy(dest + total - have,block,have); .... } If the size of a memory block can't be changed, the realloc() function will return a null pointer, while the pointer to the previous memory area will be lost. It is necessary to save the pointer into a buffer variable and make corresponding checks. Another issue of that kind:  V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'dest' is lost. Consider assigning realloc() to a temporary pointer. assimp xglloader.cpp 181 Undefined behavior V610 Undefined behavior. Check the shift operator '<<. The left operand '(- 1)' is negative. engine- dedicated%engine-headless%engine-legacy%unitsync cpuid.cpp 176 void CpuId::getMasksIntelLeaf11()
  • 10. { getMasksIntelLeaf11Enumerate(); // We determined the shifts now compute the masks maskVirtual = ~((-1) << shiftCore); maskCore = (~((-1) << shiftPackage)) ^ maskVirtual; maskPackage = (-1) << shiftPackage; } Under the C++11 language standard, shifting a negative number causes undefined behavior. Conclusion I hope improving this project's quality will also stimulate improvement of all the products based on it. It's quite a nice project for beginner game developers and ordinary gamers, followers of the RTS genre. Using static analysis regularly will help you save plenty of time to solve more serious tasks.