PVS-Studio
:
: 22.05.2012
PVS-Studio PVS-Studio
(free, open source) Cppcheck.
id Software: Doom 3, Quake 3: Arena, Wolfenstein:
Enemy Territory. , .
" ", .
.
.
, , ,
( , ).
:
. "-"
, ,
. . -
command line , - (
). - , - .
(Windows, Linux) (x86, AMR) ...
, ,
,
(, AV-Comparatives). ,
, Gartner (Magic Quadrant for Static Application Security Testing),
. , .
Cppcheck
Cppcheck , , Daniel Marjamki ,
. , .
free, , ,
.
C/C++ PVS-Studio.
, ,
: " PVS-Studio Cppcheck?".
:
, , ... (
"");
;
"" "" . -.
, .
PVS-Studio Cppcheck, , ,
.
, ,
. ,
.
PVS-Studio 4.61 Cppcheck 1.54 id Software
GitHub: Doom 3, Quake 3: Arena, Wolfenstein: Enemy Territory. ,
. () . ,
. ,
.. .
:
1. . - ,
Cppcheck , PVS-Studio ,
.vcproj.
2. - , , ,
. ,
, , - .
, PVS-Studio Cppcheck,
, . Trial-
PVS-Studio , . Cppcheck
. ,
.
Doom 3 Cppcheck
1
..\..\[Build]\Doom3\id-Software-DOOM-3-a9c49da\neo\idlib\hashing\MD5.cpp(252):
Using size of pointer ctx instead of size of its data.
void MD5_Final( MD5_CTX *ctx, unsigned char digest[16] ) {
...
memset( ctx, 0, sizeof( ctx ) ); /* In case it's sensitive */
sizeof(*ctx).
.
2
..\..\[Build]\Doom3\id-Software-DOOM-3-a9c49da\neo\renderer\Image_init.cpp(2214)
Doom 3 PVS-Studio
1
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 524, 533. anim_blend.cpp(524)
const char *idAnim::AddFrameCommand(
const idDeclModelDef *modelDef,
int framenum, idLexer &src, const idDict *def ) {
...
} else if ( token == "muzzle_flash" ) {
if( !src.ReadTokenOnLine( &token ) ) {
return "Unexpected end of line";
}
...
} else if ( token == "muzzle_flash" ) {
fc.type = FC_MUZZLEFLASH;
fc.string = new idStr( "" );
...
if . ,
.
2
V556 The values of different enum types are compared. af.cpp 895
class idDeclAF_Constraint {
...
declAFConstraintType_t type;
...
};
if (
file->constraints[j]->name.Icmp(
constraint->GetName() ) == 0 &&
file->constraints[j]->type == constraint->GetType() )
{
...
, .. enum.
- , .
3
V528 It is odd that pointer to 'char' type is compared with the '\0' value.
Probably meant: *classname != '\0'. game_local.cpp 1250
const char *classname = mapEnt->epairs.GetString( "classname" );
if ( classname != '\0' ) {
FindEntityDef( classname, false );
}
classname, , .
, .
4
V528 It is odd that pointer to 'char' type is compared with the '\0' value.
Probably meant: *soundShaderName != '\0'. game_local.cpp 1619
soundShaderName = dict->GetString( "s_shader" );
if (soundShaderName != '\0' && dict->GetFloat("s_shakes") != 0.0f){
soundShader = declManager->FindSound( soundShaderName );
3 .
5
V514 Dividing sizeof a pointer 'sizeof (clientInPVS)' by another value. There is a probability of logical
error presence. game_network.cpp 686
void idGameLocal::ServerWriteSnapshot(
int clientNum, int sequence, idBitMsg &msg,
byte *clientInPVS, int numPVSClients ) {
...
BOBrick *paddle;
void idGameBustOutWindow::ReadFromSaveGame( idFile *savefile ) {
idWindow::ReadFromSaveGame( savefile );
// Clear out existing paddle and entities from GUI load
delete paddle;
,
. ,
, .
7
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 1931, 1933. gamessdwindow.cpp 1931
void idGameSSDWindow::FireWeapon(int key) {
...
} else
if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
HitAstronaut(static_cast<SSDAstronaut*>(
gameStats.levelStats.targetEnt), key);
} else
if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
.
.
8
V535 The variable 'i' is being used for this loop and for the outer loop. matrix.cpp 3128
bool idMatX::IsOrthonormal( const float epsilon ) const
{
for ( int i = 0; i < numRows; i++ ) {
...
for ( i = 1; i < numRows; i++ ) {
, i ,
.
9
V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake.
Inspect the third argument. md5.cpp 252
void MD5_Final( MD5_CTX *ctx, unsigned char digest[16] ) {
...
memset( ctx, 0, sizeof( ctx ) ); /* In case it's sensitive */
sizeof(*ctx),
.
10
V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake.
Inspect the third argument. model_ase.cpp 731
typedef struct {
...
} aseMesh_t;
aseMesh_t *currentMesh;
...
ase.currentMesh = &ase.currentObject->mesh;
memset( ase.currentMesh, 0, sizeof( ase.currentMesh ) );
, memset
, .
11
V532 Consider inspecting the statement of '*pointer++' pattern. Probably meant: '(*pointer)++'.
model_lwo.cpp 1251
int sgetI1( unsigned char **bp )
{
...
*bp++;
, . (*bp)++.
, .
12
V533 It is likely that a wrong variable is being incremented inside the 'for' operator. Consider reviewing
'j'. surface_polytope.cpp 65
void idSurface_Polytope::FromPlanes(
const idPlane *planes, const int numPlanes ) {
for ( j = 0; j < w.GetNumPoints(); j++ ) {
for ( k = 0; k < verts.Num(); j++ ) {
k, j.
.
13
V535 The variable 'i' is being used for this loop and for the outer loop. weapon.cpp 2533
const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum )
{
...
() Doom 3
Cppcheck: 4.
PVS-Studio: 17.
( Cppcheck, PVS-Studio): 3.
, .
{
...
memcpy( &g_arenaservers.favoriteaddresses[i],
&g_arenaservers.favoriteaddresses[i+1],
(g_arenaservers.numfavoriteaddresses - i 1)*
sizeof(MAX_ADDRESSLENGTH));
sizeof(MAX_ADDRESSLENGTH).
, . ,
MAX_ADDRESSLENGTH sizeof().
2
..\..\[Build]\Quake3\id-Software-Quake-III-Arena-dbe4ddb\code\qcommon\files.c 549
Memory leak: buf
static void FS_CopyFile( char *fromOSPath, char *toOSPath ) {
...
byte *buf;
...
buf = malloc( len );
if (fread( buf, 1, len, f ) != len)
Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" );
fclose( f );
}
printf , . ,
.
4
V557 Array overrun is possible. The 'sizeof (bs->teamleader)' index is pointing beyond array bound.
ai_cmd.c 1311
char teamleader[32];
void BotMatch_StartTeamLeaderShip(
bot_state_t *bs, bot_match_t *match)
{
...
bs->teamleader[sizeof(bs->teamleader)] = '\0';
sizeof() - 1.
5
V557 Array overrun is possible. The value of 'i' index could reach 3. g_main.c 776
int numteamVotingClients[2];// set by CalculateRanks
typedef enum {
TEAM_FREE,
TEAM_RED,
TEAM_BLUE,
TEAM_SPECTATOR,
TEAM_NUM_TEAMS
} team_t;
V579 The Com_Memset function receives the pointer and its size as arguments. It is possibly a mistake.
Inspect the third argument. cvar.c 763
void Cvar_Restart_f( void ) {
...
cvar_t
*var;
...
Com_Memset( var, 0, sizeof( var ) );
, . sizeof(*var).
7
V557 Array overrun is possible. The '3' index is pointing beyond array bound. tr_shade_calc.c 628
void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )
{
...
unsigned char invModulate[3];
...
invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3];
// this trashes alpha, but the AGEN block fixes it
- , 4, 3.
() Quake 3:
Arena
Cppcheck: 6.
PVS-Studio: 7.
( Cppcheck, PVS-Studio): 2.
, .
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\curl7.12.2\docs\examples\sepheaders.c 76
Resource leak: bodyfile
bodyfile = fopen( bodyfilename,"w" );
...
// no fclose for bodyfile
, . ,
examples, . .
2
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\curl-7.12.2\src\main.c 3765
Undefined behavior: variable is used as parameter and destination in s[n]printf().
sprintf( dirbuildup,"%s%s%s",dirbuildup, DIR_CHAR, tempdir );
. .
3
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\game\bg_animation.c 585
Using sizeof for array given as function argument returns the size of pointer.
void BG_ParseConditionBits( char **text_pp,
animStringItem_t *stringTable, int condIndex, int result[2] ) {
...
memset( result, 0, sizeof( result ) );
.
sizeof(), ( ),
"2 * sizeof(int)", .
4
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\game\bg_animation.c 776
Using size of pointer command instead of size of its data.
static void BG_ParseCommands( char **input,
animScriptItem_t *scriptItem, animModelInfo_t *animModelInfo,
animScriptData_t *scriptData )
{
...
*var;
...
memset( var, 0, sizeof( var ) );
.
6
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\splines\math_matrix.h 94
Using sizeof for array given as function argument returns the size of pointer.
ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
memcpy( mat, src, sizeof( src ) );
}
sizeof
.
7
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\game\bg_pmove.c 4097
Redundant assignment of "fwdmove_knockback" in switch
switch ( pm->ps->weapon ) {
case WP_MOBILE_MG42:
fwdmove_knockback = 4000.f;
fwdmove_knockback = 400.f;
break;
case WP_PANZERFAUST:
fwdmove_knockback = 32000.f;
bckmove_knockback = 1200.f;
break;
case WP_FLAMETHROWER:
fwdmove_knockback = 2000.f;
bckmove_knockback = 40.f;
break;
}
WP_MOBILE_MG42 .
8
..\..\[Build]\Enemy Territory\id-Software-Enemy-Territory-40342a9\src\game\q_math.c 422
Array 'pnt[3]' index 3 out of bounds
typedef vec_t vec3_t[3];
void RotatePointAroundVertex( vec3_t pnt,
float rot_x, float rot_y, float rot_z, const vec3_t origin )
{
...
// rotate point
pnt[0] = ( tmp[3] * ( tmp[8] - tmp[9] ) + pnt[3] * tmp[2] );
pnt[3] .
V523 The 'then' statement is equivalent to the 'else' statement. bg_pmove.c 4115
static void PM_Weapon( void ) {
...
if ( DotProduct( pml.forward, pm->ps->velocity ) > 0
{
VectorScale( pml.forward, -1.f * ( fwdmove_knockback / mass ),
kvel );
} else {
VectorScale( pml.forward, -1.f * ( fwdmove_knockback / mass ),
kvel );
}
. ,
.
6
V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake.
Inspect the third argument. cg_character.c 308
static qboolean CG_CheckForExistingAnimModelInfo(
const char *animationGroup, const char *animationScript,
animModelInfo_t **animModelInfo )
{
...
memset( *animModelInfo, 0, sizeof( *animModelInfo ) );
, ,
.
7
V519 The 'backColor[2]' variable is assigned values twice successively. Perhaps this is a mistake. Check
lines: 3180, 3181. cg_draw.c 3181
typedef vec_t vec4_t[4];
static void CG_DrawObjectiveInfo( void ) {
...
vec4_t backColor;
backColor[0] = 0.2f;
backColor[1] = 0.2f;
backColor[2] = 0.2f;
backColor[2] = 1.f;
.
8
V556 The values of different enum types are compared: switch(ENUM_TYPE_A) { case ENUM_TYPE_B: ...
}. cg_newdraw.c 720
typedef enum {qfalse, qtrue}
qboolean;
qboolean eventHandling;
void CG_MouseEvent( int x, int y ) {
switch ( cgs.eventHandling ) {
case CGAME_EVENT_SPEAKEREDITOR:
case CGAME_EVENT_GAMEVIEW:
case CGAME_EVENT_CAMPAIGNBREIFING:
case CGAME_EVENT_FIRETEAMMSG:
switch case enum.
9
V568 It's odd that the argument of sizeof() operator is the '& itemInfo' expression. cg_weapons.c 1631
void CG_RegisterItemVisuals( int itemNum ) {
itemInfo_t *itemInfo;
...
memset( itemInfo, 0, sizeof( &itemInfo ) );
memset , .
10
V557 Array overrun is possible. The '3' index is pointing beyond array bound. q_math.c
typedef vec_t vec3_t[3];
void RotatePointAroundVertex( vec3_t pnt, float rot_x,
float rot_y, float rot_z, const vec3_t origin )
{
...
// rotate point
pnt[0] = ( tmp[3] * ( tmp[8] - tmp[9] ) + pnt[3] * tmp[2] );
pnt[3] .
11
V557 Array overrun is possible. The 'sizeof (bs->teamleader)' index is pointing beyond array bound.
ai_cmd.c 1037
char teamleader[32]; //netname of the team leader
...
bs->teamleader[sizeof( bs->teamleader )] = '\0';
sizeof() - 1.
12
V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or
intended to use the '&&' operator. ai_dmq3.c
if ( !g_entities[client].r.svFlags & SVF_BOT ) {
return;
}
- ,
.
13
V562 It's odd to compare 0 or 1 with a value of 2. ai_main.c 2659
if ( !level.clients[0].pers.connected == CON_CONNECTED ) {
return;
}
.
14
V557 Array overrun is possible. The value of 'i' index could reach 4. g_systemmsg.c 157
#define NUM_PLAYER_CLASSES
...
for ( i = 0; i < NUM_PLAYER_CLASSES; i++ ) {
if ( !playerClasses[i][0] ) {
cnt++;
}
}
.
15
V557 Array overrun is possible. The '3' index is pointing beyond array bound. tr_shade_calc.c 679
void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) {
...
unsigned char invModulate[3];
...
invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3];
// this trashes alpha, but the AGEN block fixes it
.
16
V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake.
Inspect the third argument. cvar.c 905
void Cvar_Restart_f( void ) {
cvar_t
*var;
...
memset( var, 0, sizeof( var ) );
, . sizeof(*var).
17
V519 The 'fwdmove_knockback' variable is assigned values twice successively. Perhaps this is a mistake.
Check lines: 4097, 4098. bg_pmove.c 4098
switch ( pm->ps->weapon ) {
case WP_MOBILE_MG42:
fwdmove_knockback = 4000.f;
fwdmove_knockback = 400.f;
break;
case WP_PANZERFAUST:
fwdmove_knockback = 32000.f;
bckmove_knockback = 1200.f;
break;
case WP_FLAMETHROWER:
fwdmove_knockback = 2000.f;
bckmove_knockback = 40.f;
break;
}
WP_MOBILE_MG42 .
() Wolfenstein:
Enemy Territory
Cppcheck: 8.
PVS-Studio: 17.
( Cppcheck, PVS-Studio): 6.
, .
Doom 3
Cppcheck: 4.
PVS-Studio: 17.
( Cppcheck, PVS-Studio): 3.
Quake 3: Arena
Cppcheck: 6.
PVS-Studio: 7.
( Cppcheck, PVS-Studio): 2.
, .
" "
. ,
. , .
. . ,
- . ? ,
: " Cppcheck?".
1.
2.
3.
4.
Cppcheck.
. Cppcheck.
PVS-Studio.
id Software on GitHub.