Best Bugs from Games: Fellow Programmers' Mistakes
1. Best Bugs from Games: Fellow
Programmers' Mistakes
Speaker:
George Gribkov
2. George Gribkov
C++ programmer, a developer of the
static code analysis tool (PVS-Studio)
Writes articles and speaks at
conferences about errors found in
games (Vangers: One For The Road;
VVVVVV) and other projects with open-
source code
gribkov@viva64.com
About the Speaker
2
3. 1. How we search for code errors
2. Examples and an overview of bugs found
3. In conclusion
Content
3
9. fix Terrain( fix X, fix Y, int deriv ) {
if( deriv == 0 )
return fix_mul( fix_make(0,0x2000), (X - fix_make(20,0) ) );
if( deriv == 1 )
return fix_mul( fix_make(0,0x2000), (X - fix_make(20,0) ) );
if( deriv == 2 )
return 0;
return 0;
}
Example №1
9
V751 Parameter 'Y' is not used
inside function body. BTEST.C 67
10. fix Terrain( fix X, fix Y, int deriv ) {
if( deriv == 0 )
return fix_mul( fix_make(0,0x2000), (X - fix_make(20,0) ) );
if( deriv == 1 )
return fix_mul( fix_make(0,0x2000), (Y - fix_make(20,0) ) );
if( deriv == 2 )
return 0;
return 0;
}
Example №1
10
V751 Parameter 'Y' is not used
inside function body. BTEST.C 67
11. // And here, ladies and gentlemen,
// is a celebration of C and C++ and their untamed
passion...
// ==================
TerrainData terrain_info;
// Now the actual stuff...
// =======================
Funny Comments
11
12. // it's a wonderful world, with a lot of strange men
// who are standing around, and they all wearing towels
// Returns whether or not in the humble opinion of the
// sound system, the sample should be politely
// obliterated out of existence
Funny Comments
12
14. if (....)
MySandboxGame.Log.WriteLine(string.Format(
"Could not find any sound for '{0}'", cueName));
else
{
if (....)
string.Format(
"Could not find arcade sound for '{0}'", cueName);
if (....)
string.Format(
"Could not find realistic sound for '{0}'", cueName);
}
Example №1
14
15. if (....)
MySandboxGame.Log.WriteLine(string.Format(
"Could not find any sound for '{0}'", cueName));
else
{
if (....)
string.Format(
"Could not find arcade sound for '{0}'", cueName);
if (....)
string.Format(
"Could not find realistic sound for '{0}'", cueName);
}
Example №1
15
V3010 The return value of function 'Format' is required to
be utilized. Sandbox.Game MyEntity3DSoundEmitter.cs
16. if (....)
MySandboxGame.Log.WriteLine(string.Format(
"Could not find any sound for '{0}'", cueName));
else
{
if (....)
MySandboxGame.Log.WriteLine(string.Format(
"Could not find arcade sound for '{0}'", cueName));
if (....)
MySandboxGame.Log.WriteLine(string.Format(
"Could not find realistic sound for '{0}'", cueName));
}
Example №1
16
V3010 The return value of function 'Format' is required to
be utilized. Sandbox.Game MyEntity3DSoundEmitter.cs
17. var actionsItem = item as MyToolbarItemActions;
if (item != null)
{
if (idx < 0 || idx >= actionsItem
.PossibleActions(....)
.Count)
RemoveToolbarItem(slot);
....
}
Example №2
17
18. var actionsItem = item as MyToolbarItemActions;
if (item != null)
{
if (idx < 0 || idx >= actionsItem
.PossibleActions(....)
.Count)
RemoveToolbarItem(slot);
....
}
Example №2
18
V3019 Possibly an incorrect variable is compared to null after type
conversion using 'as' keyword. Check variables 'item', 'actionsItem'.
Sandbox.Game MyGuiControlToolbar.cs 511
19. var actionsItem = item as MyToolbarItemActions;
if (item != null)
{
if (idx < 0 || idx >= actionsItem
.PossibleActions(....)
.Count)
RemoveToolbarItem(slot);
....
}
Example №2
19
V3019 Possibly an incorrect variable is compared to null after type
conversion using 'as' keyword. Check variables 'item', 'actionsItem'.
Sandbox.Game MyGuiControlToolbar.cs 511
20. var actionsItem = item as MyToolbarItemActions;
if (actionsItem != null)
{
if (idx < 0 || idx >= actionsItem
.PossibleActions(....)
.Count)
RemoveToolbarItem(slot);
....
}
Example №2
20
V3019 Possibly an incorrect variable is compared to null after type
conversion using 'as' keyword. Check variables 'item', 'actionsItem'.
Sandbox.Game MyGuiControlToolbar.cs 511
22. // Maximum number of multi players possible.
#define MAX_PLAYERS 8 // max # of players we can have
for (int i = 0; i < MAX_PLAYERS && i < 4; i++) {
if (GlyphxPlayerIDs[i] == player_id) {
MultiplayerStartPositions[i] = XY_Cell(x, y);
}
}
Example №1
22
23. // Maximum number of multi players possible.
#define MAX_PLAYERS 8 // max # of players we can have
for (int i = 0; i < MAX_PLAYERS && i < 4; i++) {
if (GlyphxPlayerIDs[i] == player_id) {
MultiplayerStartPositions[i] = XY_Cell(x, y);
}
}
Example №1
23
V590 Consider inspecting the 'i < 8 && i < 4' expression.
The expression is excessive or contains a misprint.
DLLInterface.cpp 2238
24. // Maximum number of multi players possible.
#define MAX_PLAYERS 8 // max # of players we can have
for (int i = 0; i < MAX_PLAYERS || i < 4; i++) {
if (GlyphxPlayerIDs[i] == player_id) {
MultiplayerStartPositions[i] = XY_Cell(x, y);
}
}
Example №1
24
V590 Consider inspecting the 'i < 8 && i < 4' expression.
The expression is excessive or contains a misprint.
DLLInterface.cpp 2238
25. void * ptr = new char [sizeof(100)];
if (ptr) {
sprintf((char *)ptr,
"%cTrack %dt%d:%02dt%s",
....);
listbox.Add_Item((char const *)ptr);
}
Example №2
25
26. void * ptr = new char [sizeof(100)];
if (ptr) {
sprintf((char *)ptr,
"%cTrack %dt%d:%02dt%s",
....);
listbox.Add_Item((char const *)ptr);
}
Example №2
26
V512 A call of the 'sprintf' function will lead to overflow of
the buffer '(char *) ptr'. SOUNDDLG.CPP 250
27. void * ptr = new char [100];
if (ptr) {
sprintf((char *)ptr,
"%cTrack %dt%d:%02dt%s",
....);
listbox.Add_Item((char const *)ptr);
}
Example №2
27
V512 A call of the 'sprintf' function will lead to overflow of
the buffer '(char *) ptr'. SOUNDDLG.CPP 250
30. for ( j = 0; j < w.GetNumPoints(); j++ ) {
for ( k = 0; k < verts.Num(); j++ ) {
if ( verts[k].xyz.Compare(w[j].ToVec3(),
POLYTOPE_VERTEX_EPSILON))
{
break;
}
}
...
}
Example №1
30
31. for ( j = 0; j < w.GetNumPoints(); j++ ) {
for ( k = 0; k < verts.Num(); j++ ) {
if ( verts[k].xyz.Compare(w[j].ToVec3(),
POLYTOPE_VERTEX_EPSILON))
{
break;
}
}
...
}
Example №1
31
V533 It is likely that a wrong variable is being
incremented inside the 'for' operator. Consider
reviewing 'j'. idLib surface_polytope.cpp 65
32. for ( j = 0; j < w.GetNumPoints(); j++ ) {
for ( k = 0; k < verts.Num(); k++ ) {
if ( verts[k].xyz.Compare(w[j].ToVec3(),
POLYTOPE_VERTEX_EPSILON))
{
break;
}
}
...
}
Example №1
32
V533 It is likely that a wrong variable is being
incremented inside the 'for' operator. Consider
reviewing 'j'. idLib surface_polytope.cpp 65
43. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
43
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
44. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
44
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
45. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
45
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
46. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
46
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = (c * a) ?? b;
48. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
48
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = (c * a) ?? b;
49. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
(null)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
49
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = (c * a) ?? b;
50. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
null ?? 1.0f;
}
Example №2
50
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = (c * null) ?? b;
51. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
null
?? 1.0f;
}
Example №2
51
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = null ?? b;
52. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount = 1.0f;
}
Example №2
52
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = b;
54. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f;
}
Example №2
54
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
55. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
(((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f);
}
Example №2
55
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = c * (a ?? b);
56. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
(null?.BackgroundParallaxAmount ?? 1.0f);
}
Example №2
56
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = c * (a ?? b);
57. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT *
(null ?? 1.0f);
}
Example №2
57
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = c * (null ?? b);
58. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * 1.0f;
}
Example №2
58
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = c * b;
59. private void onScreenChange(IScreen prev, IScreen next)
{
parallaxContainer.ParallaxAmount =
ParallaxContainer.DEFAULT_PARALLAX_AMOUNT;
}
Example №2
59
V3123 Perhaps the '??' operator works in a different way than it
was expected. Its priority is lower than priority of other operators
in its left part. OsuScreenStack.cs 45
x = c * b;
62. TiXmlElement *pElem;
....
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
{
printf("No valid root! Corrupt level file?n");
}
pElem->QueryIntAttribute("version", &version);
Example №1
62
V1004 The 'pElem' pointer was used unsafely after it was
verified against nullptr. Check lines: 1739, 1744. editor.cpp 1744
63. TiXmlElement *pElem;
....
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
{
printf("No valid root! Corrupt level file?n");
return;
}
pElem->QueryIntAttribute("version", &version);
Example №1
63
V1004 The 'pElem' pointer was used unsafely after it was
verified against nullptr. Check lines: 1739, 1744. editor.cpp 1744
64. TiXmlElement *pElem;
....
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
{
printf("No valid root! Corrupt level file?n");
return; // You could also use throw
}
pElem->QueryIntAttribute("version", &version);
Example №1
64
V1004 The 'pElem' pointer was used unsafely after it was
verified against nullptr. Check lines: 1739, 1744. editor.cpp 1744