Skip to content

Commit c56fa9e

Browse files
authored
Merge pull request teeworlds#3155 from Robyt3/Clang-Tidy
Add clang-tidy to CI and enable clang-analyzer checks
2 parents 5b30ead + 1e8a69e commit c56fa9e

18 files changed

+139
-45
lines changed

.clang-tidy

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Why we disabled individual checks:
2+
#
3+
# clang-analyzer-optin.cplusplus.UninitializedObject
4+
# TODO: Occurs commonly in graphics_threaded.h
5+
# clang-analyzer-optin.cplusplus.VirtualCall
6+
# Occurs very commonly all over
7+
# clang-analyzer-optin.performance.Padding
8+
# Too annoying to always align for perfect padding
9+
# clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
10+
# TODO: Requires C11 to fix
11+
# misc-unused-parameters
12+
# TODO: Many changes
13+
14+
Checks: >
15+
-*,
16+
bugprone-*,
17+
-bugprone-assignment-in-if-condition,
18+
-bugprone-branch-clone,
19+
-bugprone-easily-swappable-parameters,
20+
-bugprone-implicit-widening-of-multiplication-result,
21+
-bugprone-incorrect-roundings,
22+
-bugprone-integer-division,
23+
-bugprone-macro-parentheses,
24+
-bugprone-narrowing-conversions,
25+
-bugprone-parent-virtual-call,
26+
-bugprone-reserved-identifier,
27+
-bugprone-suspicious-include,
28+
-bugprone-unhandled-self-assignment,
29+
clang-analyzer-*,
30+
-clang-analyzer-optin.cplusplus.UninitializedObject,
31+
-clang-analyzer-optin.cplusplus.VirtualCall,
32+
-clang-analyzer-optin.performance.Padding,
33+
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
34+
cppcoreguidelines-avoid-goto,
35+
cppcoreguidelines-interfaces-global-init,
36+
cppcoreguidelines-slicing,
37+
cppcoreguidelines-virtual-class-destructor,
38+
misc-*,
39+
-misc-const-correctness,
40+
-misc-no-recursion,
41+
-misc-non-private-member-variables-in-classes,
42+
-misc-static-assert,
43+
-misc-unused-parameters,
44+
performance-*,
45+
-performance-no-int-to-ptr,
46+
portability-*,

.github/workflows/clang-tidy.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Check clang-tidy
2+
3+
on:
4+
push:
5+
branches-ignore:
6+
- master
7+
- staging.tmp
8+
- trying.tmp
9+
- staging-squash-merge.tmp
10+
pull_request:
11+
12+
jobs:
13+
check-clang-tidy:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v2
17+
with:
18+
submodules: true
19+
20+
- name: Install clang-tidy
21+
run: |
22+
sudo apt-get update -y
23+
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libsdl2-dev clang-tidy -y
24+
- name: Build with clang-tidy
25+
run: |
26+
mkdir clang-tidy
27+
cd clang-tidy
28+
cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-warnings-as-errors=*" -DCMAKE_C_CLANG_TIDY="clang-tidy;-warnings-as-errors=*" -DCMAKE_BUILD_TYPE=Debug -Werror=dev ..
29+
cmake --build . --config Debug --target everything -- -k 0

CMakeLists.txt

-3
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,6 @@ if(NOT MSVC)
137137
# Protect the stack pointer.
138138
add_c_compiler_flag_if_supported(OUR_FLAGS -fstack-protector-all)
139139

140-
# Protect the stack from clashing.
141-
add_c_compiler_flag_if_supported(OUR_FLAGS -fstack-clash-protection)
142-
143140
# Control-flow protection. Should protect against ROP.
144141
add_c_compiler_flag_if_supported(OUR_FLAGS -fcf-protection)
145142

src/base/system.c

+17-13
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ void dbg_assert_imp(const char *filename, int line, int test, const char *msg)
115115

116116
void dbg_break()
117117
{
118-
*((volatile unsigned*)0) = 0x0;
118+
#ifdef __GNUC__
119+
__builtin_trap();
120+
#else
121+
abort();
122+
#endif
119123
}
120124

121125
void dbg_msg(const char *sys, const char *fmt, ...)
@@ -148,20 +152,20 @@ void dbg_msg(const char *sys, const char *fmt, ...)
148152
#if defined(CONF_FAMILY_WINDOWS)
149153
static void logger_win_console(const char *line, void *user)
150154
{
151-
#define _MAX_LENGTH 1024
152-
#define _MAX_LENGTH_ERROR (_MAX_LENGTH+32)
155+
#define MAX_LENGTH 1024
156+
#define MAX_LENGTH_ERROR (MAX_LENGTH+32)
153157

154158
static const int UNICODE_REPLACEMENT_CHAR = 0xfffd;
155159

156160
static const char *STR_TOO_LONG = "(str too long)";
157161
static const char *INVALID_UTF8 = "(invalid utf8)";
158162

159-
wchar_t wline[_MAX_LENGTH_ERROR];
163+
wchar_t wline[MAX_LENGTH_ERROR];
160164
size_t len = 0;
161165

162166
const char *read = line;
163167
const char *error = STR_TOO_LONG;
164-
while(len < _MAX_LENGTH)
168+
while(len < MAX_LENGTH)
165169
{
166170
// Read a character. This also advances the read pointer
167171
int glyph = str_utf8_decode(&read);
@@ -213,23 +217,23 @@ static void logger_win_console(const char *line, void *user)
213217
if(character == 0)
214218
break;
215219

216-
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for error");
217-
wline[len++] = character;
220+
dbg_assert(len < MAX_LENGTH_ERROR, "str too short for error");
221+
wline[len++] = (unsigned char)character;
218222
read++;
219223
}
220224
}
221225

222226
// Terminate the line
223-
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\r");
227+
dbg_assert(len < MAX_LENGTH_ERROR, "str too short for \\r");
224228
wline[len++] = '\r';
225-
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\n");
229+
dbg_assert(len < MAX_LENGTH_ERROR, "str too short for \\n");
226230
wline[len++] = '\n';
227231

228232
// Ignore any error that might occur
229233
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wline, len, 0, 0);
230234

231-
#undef _MAX_LENGTH
232-
#undef _MAX_LENGTH_ERROR
235+
#undef MAX_LENGTH
236+
#undef MAX_LENGTH_ERROR
233237
}
234238
#endif
235239

@@ -2638,7 +2642,7 @@ char* str_sanitize_filename(char* aName)
26382642
{
26392643
// replace forbidden characters with a whispace
26402644
if(*str == '/' || *str == '<' || *str == '>' || *str == ':' || *str == '"'
2641-
|| *str == '/' || *str == '\\' || *str == '|' || *str == '?' || *str == '*')
2645+
|| *str == '\\' || *str == '|' || *str == '?' || *str == '*')
26422646
*str = ' ';
26432647
str++;
26442648
}
@@ -3136,7 +3140,7 @@ int str_utf8_decode(const char **ptr)
31363140
{
31373141
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
31383142
{
3139-
ch = *buf;
3143+
ch = (unsigned char)*buf;
31403144
buf++;
31413145
}
31423146
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */

src/engine/client/graphics_threaded.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,18 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto
418418
return 0;
419419
}
420420

421-
if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA) || Png.width > (2<<12) || Png.height > (2<<12))
421+
if(Png.depth != 8 || Png.width > (2<<12) || Png.height > (2<<12))
422+
{
423+
dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename);
424+
io_close(File);
425+
return 0;
426+
}
427+
428+
if(Png.color_type == PNG_TRUECOLOR)
429+
pImg->m_Format = CImageInfo::FORMAT_RGB;
430+
else if(Png.color_type == PNG_TRUECOLOR_ALPHA)
431+
pImg->m_Format = CImageInfo::FORMAT_RGBA;
432+
else
422433
{
423434
dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename);
424435
io_close(File);
@@ -431,10 +442,6 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto
431442

432443
pImg->m_Width = Png.width;
433444
pImg->m_Height = Png.height;
434-
if(Png.color_type == PNG_TRUECOLOR)
435-
pImg->m_Format = CImageInfo::FORMAT_RGB;
436-
else if(Png.color_type == PNG_TRUECOLOR_ALPHA)
437-
pImg->m_Format = CImageInfo::FORMAT_RGBA;
438445
pImg->m_pData = pBuffer;
439446
return 1;
440447
}

src/engine/client/serverbrowser.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -466,14 +466,14 @@ CServerEntry *CServerBrowser::Add(int ServerlistType, const NETADDR &Addr)
466466
{
467467
// alloc start size
468468
m_aServerlist[ServerlistType].m_NumServerCapacity = 1000;
469-
m_aServerlist[ServerlistType].m_ppServerlist = (CServerEntry **)mem_alloc(m_aServerlist[ServerlistType].m_NumServerCapacity*sizeof(CServerEntry*));
469+
m_aServerlist[ServerlistType].m_ppServerlist = (CServerEntry **)mem_alloc(m_aServerlist[ServerlistType].m_NumServerCapacity*sizeof(CServerEntry*)); // NOLINT(bugprone-sizeof-expression)
470470
}
471471
else
472472
{
473473
// increase size
474474
m_aServerlist[ServerlistType].m_NumServerCapacity += 100;
475-
CServerEntry **ppNewlist = (CServerEntry **)mem_alloc(m_aServerlist[ServerlistType].m_NumServerCapacity*sizeof(CServerEntry*));
476-
mem_copy(ppNewlist, m_aServerlist[ServerlistType].m_ppServerlist, m_aServerlist[ServerlistType].m_NumServers*sizeof(CServerEntry*));
475+
CServerEntry **ppNewlist = (CServerEntry **)mem_alloc(m_aServerlist[ServerlistType].m_NumServerCapacity*sizeof(CServerEntry*)); // NOLINT(bugprone-sizeof-expression)
476+
mem_copy(ppNewlist, m_aServerlist[ServerlistType].m_ppServerlist, m_aServerlist[ServerlistType].m_NumServers*sizeof(CServerEntry*)); // NOLINT(bugprone-sizeof-expression)
477477
mem_free(m_aServerlist[ServerlistType].m_ppServerlist);
478478
m_aServerlist[ServerlistType].m_ppServerlist = ppNewlist;
479479
}

src/engine/client/textrender.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ CGlyph *CGlyphMap::GetGlyph(int Chr, int FontSizeIndex, bool Render)
482482
m_Glyphs.add(Index);
483483
return Index.m_pGlyph;
484484
}
485+
delete Index.m_pGlyph;
485486
return NULL;
486487
}
487488

@@ -1032,10 +1033,6 @@ void CTextRender::TextNewline(CTextCursor *pCursor)
10321033
}
10331034

10341035
vec2 ScreenScale = vec2(ScreenWidth/(ScreenX1-ScreenX0), ScreenHeight/(ScreenY1-ScreenY0));
1035-
float Size = pCursor->m_FontSize;
1036-
int PixelSize = (int)(Size * ScreenScale.y);
1037-
Size = PixelSize / ScreenScale.y;
1038-
10391036
pCursor->m_LineCount++;
10401037
pCursor->m_Advance.y = pCursor->m_LineSpacing + pCursor->m_NextLineAdvanceY;
10411038
pCursor->m_Advance.x = 0;

src/engine/external/.clang-tidy

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Need at least one check, otherwise clang-tidy fails, use one that can't
2+
# happen in our code since we don't use OpenMP API.
3+
Checks: '-*,openmp-exception-escape'

src/game/client/animstate.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ static void AnimSeqEval(CAnimSequence *pSeq, float Time, CAnimKeyframe *pFrame)
5151

5252
static void AnimAddKeyframe(CAnimKeyframe *pSeq, CAnimKeyframe *pAdded, float Amount)
5353
{
54-
pSeq->m_X += pAdded->m_X*Amount;
54+
// AnimSeqEval fills m_X for any case, clang-analyzer assumes going into the
55+
// final else branch with pSeq->m_NumFrames < 2, which is impossible.
56+
pSeq->m_X += pAdded->m_X*Amount; // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
5557
pSeq->m_Y += pAdded->m_Y*Amount;
5658
pSeq->m_Angle += pAdded->m_Angle*Amount;
5759
}

src/game/client/components/broadcast.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ void CBroadcast::OnBroadcastMessage(const CNetMsg_Sv_Broadcast *pMsg)
143143
return;
144144

145145
// new broadcast message
146-
int MsgLength = str_length(pMsg->m_pMessage);
146+
const int MsgLength = str_length(pMsg->m_pMessage);
147147
m_ServerBroadcastReceivedTime = Client()->LocalTime();
148+
if(!MsgLength)
149+
{
150+
m_ServerBroadcastCursor.Reset();
151+
return;
152+
}
148153

149154
char aBuf[MAX_BROADCAST_MSG_SIZE];
150155
vec4 SegmentColors[MAX_BROADCAST_MSG_SIZE];
@@ -154,7 +159,7 @@ void CBroadcast::OnBroadcastMessage(const CNetMsg_Sv_Broadcast *pMsg)
154159
int UserLineCount = 1;
155160

156161
// parse colors and newline
157-
for(int i = 0; i < MsgLength && ServerMsgLen < MAX_BROADCAST_MSG_SIZE - 1; i++)
162+
for(int i = 0; i < MsgLength && ServerMsgLen < MAX_BROADCAST_MSG_SIZE - 1 && m_NumSegments < MAX_BROADCAST_MSG_SIZE - 1; i++)
158163
{
159164
const char *c = pMsg->m_pMessage + i;
160165

@@ -264,7 +269,8 @@ void CBroadcast::OnBroadcastMessage(const CNetMsg_Sv_Broadcast *pMsg)
264269
m_aServerBroadcastSegments[i].m_IsHighContrast = false;
265270
}
266271
m_aServerBroadcastSegments[i].m_GlyphPos = m_ServerBroadcastCursor.GlyphCount();
267-
TextRender()->TextDeferred(&m_ServerBroadcastCursor, aBuf + SegmentIndices[i], SegmentIndices[i+1] - SegmentIndices[i]);
272+
// The segment array always contains exactly m_NumSegments + 1 valid segments but clang-analyzer can't determine that.
273+
TextRender()->TextDeferred(&m_ServerBroadcastCursor, aBuf + SegmentIndices[i], SegmentIndices[i+1] - SegmentIndices[i]); // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
268274
}
269275
m_aServerBroadcastSegments[m_NumSegments].m_GlyphPos = m_ServerBroadcastCursor.GlyphCount();
270276
TextRender()->TextColor(OldColor);

src/game/client/components/menus.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -382,15 +382,15 @@ void CMenus::DoJoystickBar(const CUIRect *pRect, float Current, float Tolerance,
382382
int CMenus::DoKeyReader(CButtonContainer *pButtonContainer, const CUIRect *pRect, int Key, int Modifier, int* pNewModifier)
383383
{
384384
// process
385-
static const void *s_pGrabbedID = 0;
385+
static const void *s_pGrabbedID = 0x0;
386386
static bool s_MouseReleased = true;
387387
static int s_ButtonUsed = 0;
388388

389389
const bool Hovered = UI()->MouseHovered(pRect);
390390
int NewKey = Key;
391391
*pNewModifier = Modifier;
392392

393-
if(!UI()->MouseButton(0) && !UI()->MouseButton(1) && s_pGrabbedID == pButtonContainer)
393+
if(!UI()->MouseButton(0) && !UI()->MouseButton(1) && s_pGrabbedID != 0x0 && s_pGrabbedID == pButtonContainer)
394394
s_MouseReleased = true;
395395

396396
if(UI()->CheckActiveItem(pButtonContainer))

src/game/client/components/scoreboard.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ float CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const c
258258
// render title
259259
if(NoTitle)
260260
{
261-
if(m_pClient->m_Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
261+
if(Snap.m_pGameData && Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
262262
pTitle = Localize("Game over");
263-
else if(m_pClient->m_Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER)
263+
else if(Snap.m_pGameData && Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER)
264264
pTitle = Localize("Round over");
265265
else
266266
pTitle = Localize("Scoreboard");

src/game/client/components/stats.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ void CStats::OnRender()
375375
s_Cursor.MoveTo(x + 64, y + LineHeight / 2.0f);
376376
TextRender()->TextOutlined(&s_Cursor, "⋅⋅⋅ ", -1);
377377
TextRender()->TextOutlined(&s_Cursor, aBuf, -1);
378-
px += 100;
379378
break;
380379
}
381380

@@ -604,7 +603,6 @@ void CStats::OnRender()
604603
TextRender()->TextOutlined(&s_Cursor, aBuf, -1);
605604
}
606605
}
607-
px += 100;
608606
}
609607
y += LineHeight;
610608
}

src/game/client/gameclient.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker)
670670
if(GameMsgID < 0 || GameMsgID >= NUM_GAMEMSGS)
671671
return;
672672

673-
int aParaI[3];
673+
int aParaI[3] = {0, 0, 0};
674674
int NumParaI = 0;
675675

676676
// get paras

src/game/editor/editor.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -1265,9 +1265,9 @@ void CEditor::DoQuadEnvelopes(const array<CQuad> &lQuads, IGraphics::CTextureHan
12651265
{
12661266
int Num = lQuads.size();
12671267
CEnvelope **apEnvelope = new CEnvelope*[Num];
1268-
mem_zero(apEnvelope, sizeof(CEnvelope*)*Num);
12691268
for(int i = 0; i < Num; i++)
12701269
{
1270+
apEnvelope[i] = 0;
12711271
if((m_ShowEnvelopePreview == SHOWENV_SELECTED && lQuads[i].m_PosEnv == m_SelectedEnvelope) || m_ShowEnvelopePreview == SHOWENV_ALL)
12721272
if(lQuads[i].m_PosEnv >= 0 && lQuads[i].m_PosEnv < m_Map.m_lEnvelopes.size())
12731273
apEnvelope[i] = m_Map.m_lEnvelopes[lQuads[i].m_PosEnv];
@@ -2671,7 +2671,7 @@ void CEditor::RenderFileDialog()
26712671
// GUI coordsys
26722672
CUIRect View = *UI()->Screen();
26732673
Graphics()->MapScreen(View.x, View.y, View.w, View.h);
2674-
CUIRect Preview;
2674+
CUIRect Preview = {0, 0, 0, 0};
26752675
float Width = View.w, Height = View.h;
26762676

26772677
View.Draw(vec4(0,0,0,0.25f), 0.0f, CUIRect::CORNER_NONE);
@@ -2782,9 +2782,9 @@ void CEditor::RenderFileDialog()
27822782
}
27832783
}
27842784

2785-
if(m_FilesSelectedIndex >= 0 && m_FilesSelectedIndex < m_FilteredFileList.size())
2785+
if(m_FilesSelectedIndex >= 0 && m_FilesSelectedIndex < m_FilteredFileList.size() && m_FileDialogFileType == CEditor::FILETYPE_IMG)
27862786
{
2787-
if(m_FileDialogFileType == CEditor::FILETYPE_IMG && !m_PreviewImageIsLoaded)
2787+
if(!m_PreviewImageIsLoaded)
27882788
{
27892789
int Length = str_length(m_FilteredFileList[m_FilesSelectedIndex]->m_aFilename);
27902790
if(Length >= str_length(".png") && str_endswith_nocase(m_FilteredFileList[m_FilesSelectedIndex]->m_aFilename, ".png"))

0 commit comments

Comments
 (0)