Introduction
C(ontinued)MaNGOS is an actively developing offshoot of an old project: MaNGOS (Massive Network Game Object Server), which was made in order to create an alternative server for the World of Warcraft game. The majority of MaNGOS developers continue working in CMaNGOS.
According to the developers themselves, their goal is to create a "well written server in C++" for one of the best MMORPGs. I'll try to help them with this, by checking CMaNGOS using the static analyzer, PVS-Studio.
Note: To do the analysis we used CMaNGOS-Classic server, available in the project repository on GitHub.
The analysis results
An error in the operation precedence
PVS-Studio warning: V593 Consider reviewing the expression of the 'A = B < C' kind. The expression is calculated as following: 'A = (B < C)'. SpellEffects.cpp 473
void Spell::EffectDummy(SpellEffectIndex eff_idx)
{
....
if (uint32 roll = urand(0, 99) < 3) // getRace()) == ALLIANCE)
modelid = 2428; // Id == 28891 &&
m_spellInfo->Id == 28898) // Id is verified against two different values at the same time. The result of this check is always false, of course. The author most likely made a mistake and instead of '||' operator used '&&'.
It should be noted that the program commented on strange code behavior, and perhaps, it was caused by this error exactly.
There were several errors like this, here is the full list:
V547 Expression is always false. Probably the '||' operator should be used here. SpellEffects.cpp 2872
V547 Expression is always true. Probably the '&&' operator should be used here. genrevision.cpp 261
V547 Expression is always true. Probably the '&&' operator should be used here. vmapexport.cpp 361
V547 Expression is always true. Probably the '&&' operator should be used here. MapTree.cpp 125
V547 Expression is always true. Probably the '&&' operator should be used here. MapTree.cpp 234
Suspicious formatting
PVS-Studio warning: 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. instance_blackrock_depths.cpp 111
void instance_blackrock_depths::OnCreatureCreate(Creature* pCreature)
{
switch (pCreature->GetEntry())
{
....
case NPC_HAMMERED_PATRON:
....
if (m_auiEncounter[11] == DONE)
pCreature->SetFactionTemporary(....);
pCreature->SetStandState(UNIT_STAND_STATE_STAND); // SetStandState(UNIT_STAND_STATE_STAND) to be executed regardless of the if condition.
If this behavior was meant intentionally, then the formatting should be corrected: if (m_auiEncounter[11] == DONE)
pCreature->SetFactionTemporary(....);
pCreature->SetStandState(UNIT_STAND_STATE_STAND);
Similar operands in the ternary operator
PVS-Studio warning: V583 The '?:' operator, regardless of its conditional expression, always returns one and the same value: SAY_BELNISTRASZ_AGGRO_1. razorfen_downs.cpp 104
void AttackedBy(Unit* pAttacker) override
{
....
if (!m_bAggro)
{
DoScriptText(urand(0, 1) ?
SAY_BELNISTRASZ_AGGRO_1 : // GetHealth() /
pEmberstrife->GetMaxHealth() > 0.1f) // UpdateDuration(this, time);
....
}
Testing this for null
PVS-Studio warning: V704 '!this ||!pVictim' expression should be avoided: 'this' pointer can never be NULL on newer compilers. Unit.cpp 1417
void Unit::CalculateSpellDamage(....)
{
....
if (!this || !pVictim) // GetEntry() == NPC_VEKLOR ?
NPC_VEKNILASH :
NPC_VEKLOR))
{
float fHealPercent = ((float)uiHealedAmount) /
((float)m_creature->GetMaxHealth());
uint32 uiTwinHeal =
(uint32)(fHealPercent * ((float)pTwin->GetMaxHealth()));
uint32 uiTwinHealth = pTwin->GetHealth() + uiTwinHeal;
pTwin->SetHealth(uiTwinHealth < pTwin->GetMaxHealth() ?
uiTwinHealth :
pTwin->GetMaxHealth());
}
}
The variable uiHealedAmount is passed by reference, but is not changed in the body of the function. This can be misleading, because we get the impression that the HealedBy() function writes something to the uiHealedAmount. It would be better to pass the variable by a constant reference or by value.
Repeated assignment
PVS-Studio warning: V519 The 'stat' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1776, 1781. DetourNavMeshQuery.cpp 1781
dtStatus dtNavMeshQuery::findStraightPath(....) const
{
....
if (....)
{
stat = appendPortals(apexIndex, i, closestEndPos, // loadMap(mapID,
tileX, tileY,
meshData);
// get model data
m_terrainBuilder->loadVMap(mapID,
tileY, tileX, //
↧