Bug Summary

File:server/sv_mapcycle.cpp
Location:line 37, column 8
Description:Access to field 'map' results in a dereference of a null pointer (loaded from variable 'mapcycle')

Annotated Source Code

1#include "server.h"
2#include "../shared/parse.h"
3
4/**
5 * @brief map cycle list element
6*/
7typedef struct mapcycle_s {
8 char *map; /**< map name */
9 char *type; /**< gametype to play on this map */
10 bool day; /**< load the day version */
11 struct mapcycle_s* next; /**< pointer to the next map in cycle */
12} mapcycle_t;
13
14static mapcycle_t *mapcycleList; /**< map cycle linked list */
15static int mapcycleCount; /**< number of maps in the cycle */
16
17/**
18 * @brief Start the next map in the cycle
19 */
20void SV_NextMapcycle (void)
21{
22 const char *map = NULL__null, *gameType = NULL__null;
23 bool day = true;
24 char *base;
25 char assembly[MAX_QPATH64];
26 char expanded[MAX_QPATH64];
27 char cmd[MAX_QPATH64];
28 mapcycle_t *mapcycle;
29
30 mapcycle = mapcycleList;
31 if (sv->name[0]) {
3
Taking true branch
32 int i;
33 Com_Printf("current map: %s\n", sv->name);
34 for (i = 0; i < mapcycleCount; i++) {
4
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
35 /* random maps may have a theme - but that's not stored in sv->name
36 * but in sv->assembly */
37 if (mapcycle->map[0] == '+') {
5
Taking false branch
10
Access to field 'map' results in a dereference of a null pointer (loaded from variable 'mapcycle')
38 Q_strncpyz(expanded, mapcycle->map, sizeof(expanded))Q_strncpyzDebug( expanded, mapcycle->map, sizeof(expanded)
, "src/server/sv_mapcycle.cpp", 38 )
;
39 base = strstr(expanded, " ");
40 if (base) {
41 base[0] = '\0'; /* split the strings */
42 Q_strncpyz(assembly, base + 1, sizeof(assembly))Q_strncpyzDebug( assembly, base + 1, sizeof(assembly), "src/server/sv_mapcycle.cpp"
, 42 )
;
43 /* get current position */
44 if (Q_streq(sv->name, expanded)(strcmp(sv->name, expanded) == 0) && Q_streq(sv->assembly, assembly)(strcmp(sv->assembly, assembly) == 0)) {
45 /* next map in cycle */
46 if (mapcycle->next) {
47 map = mapcycle->next->map;
48 day = mapcycle->next->day;
49 gameType = mapcycle->next->type;
50 Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
51 /* switch back to first list on cycle - if there is one */
52 } else {
53 map = mapcycleList->map;
54 day = mapcycleList->day;
55 gameType = mapcycleList->type;
56 Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
57 }
58 break;
59 }
60 } else {
61 Com_Printf("ignore mapcycle entry for random map (%s) with"
62 " no assembly given\n", mapcycle->map);
63 }
64 } else {
65 /* get current position */
66 if (Q_streq(sv->name, mapcycle->map)(strcmp(sv->name, mapcycle->map) == 0)) {
6
Taking true branch
67 /* next map in cycle */
68 if (mapcycle->next) {
7
Taking false branch
69 map = mapcycle->next->map;
70 day = mapcycle->next->day;
71 gameType = mapcycle->next->type;
72 Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
73 /* switch back to first list on cycle - if there is one */
74 } else {
75 map = mapcycleList->map;
76 day = mapcycleList->day;
77 gameType = mapcycleList->type;
78 Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
79 }
80 Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
81
82 /* check for bsp file */
83 if (map[0] != '+' && FS_CheckFile("%s", expanded) < 0) {
8
Taking true branch
84 Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
85 "Use the 'maplist' command to get a list of valid maps\n", expanded);
86 map = NULL__null;
87 gameType = NULL__null;
88 } else
89 break;
90 }
91 }
92 mapcycle = mapcycle->next;
93 }
94 }
95
96 if (!map) {
97 if (mapcycleCount > 0) {
98 map = mapcycleList->map;
99 day = mapcycleList->day;
100 gameType = mapcycleList->type;
101 if (map[0] != '+') {
102 Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
103
104 /* check for bsp file */
105 if (FS_CheckFile("%s", expanded) < 0) {
106 Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
107 "Use the 'maplist' command to get a list of valid maps\n", expanded);
108 return;
109 }
110 }
111 } else if (sv->name[0]) {
112 Com_Printf("No mapcycle - restart the current map (%s)\n", sv->name);
113 map = sv->name;
114 gameType = NULL__null;
115 } else {
116 Com_Printf("No mapcycle and no running map\n");
117 return;
118 }
119 /* still not set? */
120 if (!map)
121 return;
122 }
123
124 /* check whether we want to change the gametype, too */
125 if (gameType && gameType[0] != '\0') {
126 Cvar_Set("sv_gametype", gameType);
127 Com_SetGameType();
128 sv_gametype->modified = false;
129 }
130
131 if (day)
132 Com_sprintf(cmd, sizeof(cmd), "map day %s", map);
133 else
134 Com_sprintf(cmd, sizeof(cmd), "map night %s", map);
135 Cbuf_AddText(cmd);
136}
137
138/**
139 * @brief Empty the mapcycle list
140 * @sa SV_MapcycleAdd
141 */
142void SV_MapcycleClear (void)
143{
144 int i;
145 mapcycle_t *mapcycle;
146
147 mapcycle = mapcycleList;
148 for (i = 0; i < mapcycleCount; i++) {
149 mapcycle_t *oldMapcycle = mapcycle;
150 mapcycle = mapcycle->next;
151 Mem_Free(oldMapcycle->type)_Mem_Free((oldMapcycle->type),"src/server/sv_mapcycle.cpp"
,151)
;
152 Mem_Free(oldMapcycle->map)_Mem_Free((oldMapcycle->map),"src/server/sv_mapcycle.cpp",
152)
;
153 Mem_Free(oldMapcycle)_Mem_Free((oldMapcycle),"src/server/sv_mapcycle.cpp",153);
154 }
155
156 /* reset the mapcycle data */
157 mapcycleList = NULL__null;
158 mapcycleCount = 0;
159}
160
161/**
162 * @brief Append a new mapname to the list of maps for the cycle
163 * @todo check for maps and valid gametypes here
164 * @sa SV_MapcycleClear
165 */
166static void SV_MapcycleAdd (const char* mapName, bool day, const char* gameType)
167{
168 mapcycle_t* const mapcycle = Mem_PoolAllocType(mapcycle_t, sv_genericPool)static_cast<mapcycle_t*>(static_cast<mapcycle_t*>
(_Mem_Alloc((sizeof(mapcycle_t) * (1)),true,(((sv_genericPool
))),(0),"src/server/sv_mapcycle.cpp",168)))
;
169 mapcycle->map = Mem_PoolStrDup(mapName, sv_genericPool, 0)_Mem_PoolStrDup((mapName),(sv_genericPool),(0),"src/server/sv_mapcycle.cpp"
,169)
;
170 mapcycle->day = day;
171 mapcycle->type = Mem_PoolStrDup(gameType, sv_genericPool, 0)_Mem_PoolStrDup((gameType),(sv_genericPool),(0),"src/server/sv_mapcycle.cpp"
,171)
;
172 mapcycle->next = 0;
173 Com_DPrintf(DEBUG_SERVER0x40, "mapcycle add: '%s' type '%s'\n", mapcycle->map, mapcycle->type);
174
175 /* Append to end of list. */
176 mapcycle_t** anchor = &mapcycleList;
177 while (*anchor) anchor = &(*anchor)->next;
178 *anchor = mapcycle;
179
180 ++mapcycleCount;
181}
182
183/**
184 * @brief Parses the server mapcycle
185 * @sa SV_MapcycleAdd
186 * @sa SV_MapcycleClear
187 */
188static void SV_ParseMapcycle (void)
189{
190 int length = 0;
191 byte *buffer = NULL__null;
192 const char *token;
193 const char *buf;
194 char map[MAX_VAR64], gameType[MAX_VAR64];
195
196 mapcycleCount = 0;
197 mapcycleList = NULL__null;
198
199 length = FS_LoadFile("mapcycle.txt", &buffer);
200 if (length == -1 || !buffer)
201 return;
202
203 if (length != -1) {
204 buf = (const char*)buffer;
205 do {
206 bool day = false;
207 /* parse map name */
208 token = Com_Parse(&buf);
209 if (!buf)
210 break;
211 Q_strncpyz(map, token, sizeof(map))Q_strncpyzDebug( map, token, sizeof(map), "src/server/sv_mapcycle.cpp"
, 211 )
;
212 /* parse day or night */
213 token = Com_Parse(&buf);
214 if (!buf)
215 break;
216 if (Q_streq(token, "day")(strcmp(token, "day") == 0))
217 day = true;
218 else if (!Q_streq(token, "night")(strcmp(token, "night") == 0)) {
219 Com_Printf("Skip mapcycle parsing, expected day or night.");
220 break;
221 }
222 /* parse gametype */
223 token = Com_Parse(&buf);
224 if (!buf)
225 break;
226 Q_strncpyz(gameType, token, sizeof(gameType))Q_strncpyzDebug( gameType, token, sizeof(gameType), "src/server/sv_mapcycle.cpp"
, 226 )
;
227 SV_MapcycleAdd(map, day, gameType);
228 } while (buf);
229
230 Com_Printf("added %i maps to the mapcycle\n", mapcycleCount);
231 }
232 FS_FreeFile(buffer);
233}
234
235static void SV_MapcycleList_f (void)
236{
237 int i;
238 const mapcycle_t* mapcycle;
239
240 mapcycle = mapcycleList;
241 Com_Printf("current mapcycle has %i entries\n", mapcycleCount);
242 for (i = 0; i < mapcycleCount; i++) {
243 Com_Printf(" %s (%s)\n", mapcycle->map, mapcycle->type);
244 mapcycle = mapcycle->next;
245 }
246}
247
248static void SV_MapcycleAdd_f (void)
249{
250 if (Cmd_Argc() == 4) {
251 const char *map = Cmd_Argv(1);
252 const char *day = Cmd_Argv(2);
253 const char *gametype = Cmd_Argv(3);
254 if (!SV_CheckMap(map, NULL__null)) {
255 Com_Printf("map '%s' isn't a valid map\n", map);
256 return;
257 }
258 Com_Printf("adding map '%s' with gametype '%s' to mapcycle (to add this permanently edit your mapcycle.txt)\n", map, gametype);
259 if (Q_streq(day, "day")(strcmp(day, "day") == 0))
260 SV_MapcycleAdd(map, true, gametype);
261 else
262 SV_MapcycleAdd(map, false, gametype);
263 } else {
264 Com_Printf("Usage: %s <mapname> <day|night> <gametype>\n", Cmd_Argv(0));
265 Com_Printf(" ...to get a list of valid maps type 'maplist'\n"
266 " ...to get a list of valid gametypes 'gametypelist'\n");
267 }
268}
269
270static void SV_MapcycleNext_f (void)
271{
272 if (mapcycleCount > 0)
1
Taking true branch
273 SV_NextMapcycle();
2
Calling 'SV_NextMapcycle'
274 else
275 Com_Printf("no mapcycle.txt\n");
276}
277
278void SV_MapcycleInit (void)
279{
280 SV_ParseMapcycle();
281
282 Cmd_AddCommand("mapcyclelist", SV_MapcycleList_f, "Print the current mapcycle");
283 Cmd_AddCommand("mapcyclenext", SV_MapcycleNext_f, "Start the next map from the cycle");
284 Cmd_AddCommand("mapcycleclear", SV_MapcycleClear, "Delete the current mapcycle");
285 Cmd_AddCommand("mapcycleadd", SV_MapcycleAdd_f, "Add new maps to the mapcycle");
286}