Skip to content

Commit 3a12ffa

Browse files
committed
games/NXDoom: Address review comments.
Shorten the comments added by this series to what the code needs, and use NuttX function comment blocks for the new interfaces. Drop references to the supervisor and the package manager, which are not part of this game. Report a failed signal handler installation through printf(), matching the rest of the application, rather than syslog(). Free the renderer scratch buffers through r_shutdown_planes() on the allocation failure path instead of repeating the frees, and make that function safe to call more than once. Assisted-by: OpenAI Codex:gpt-5.6-sol Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
1 parent 0899b14 commit 3a12ffa

7 files changed

Lines changed: 71 additions & 141 deletions

File tree

games/NXDoom/src/d_iwad.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,7 @@ static void buld_iwad_dir_list(void)
271271

272272
add_iwad_dir(m_dir_name(myargv[0]));
273273

274-
/* Add the board's configured DOOM data directory. Kconfig documents
275-
* CONFIG_GAMES_NXDOOM_PREFDIR as "Directory where DOOM WAD files are
276-
* stored", but until now it was only used for the config/save file
277-
* location -- nothing actually searched it for IWADs, forcing every
278-
* launch to rely on the current directory or DOOMWADDIR/DOOMWADPATH
279-
* being set by hand first.
280-
*/
274+
/* Add the configured DOOM data directory */
281275

282276
add_iwad_dir(CONFIG_GAMES_NXDOOM_PREFDIR);
283277

games/NXDoom/src/doom/d_main.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,11 +1294,6 @@ void d_doomloop(void)
12941294

12951295
while (1)
12961296
{
1297-
/* Safe point (outside any framebuffer/heap access) for nxstore's
1298-
* SIGTERM-driven close request to actually take effect - see
1299-
* i_install_quit_signal() in i_system.h.
1300-
*/
1301-
13021297
i_poll_quit_signal();
13031298
d_run_frame();
13041299
}

games/NXDoom/src/doom/r_plane.c

Lines changed: 29 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -119,31 +119,9 @@ static void r_map_plane(int y, int x1, int x2)
119119
fixed_t length;
120120
unsigned index;
121121

122-
/* y indexes cachedheight[]/cacheddistance[]/cachedxstep[]/cachedystep[]
123-
* below, all sized SCREENHEIGHT - a y outside that range (observed on
124-
* this port: y=255 against a 200-entry array, well past even
125-
* viewheight) is an out-of-bounds array write, not just a "debug
126-
* assertion". This used to be gated behind CONFIG_GAMES_NXDOOM_
127-
* RANGECHECK and fatal (i_error(), which tears down the whole process
128-
* on what vanilla Doom would just render as one glitched span) - both
129-
* wrong: the memory-safety check must not be optional, and killing the
130-
* entire game over one bad plane span is worse than just not drawing
131-
* it. Clamp y into range instead of touching memory outside the
132-
* buffers' real bounds - this still renders the span (as one glitched
133-
* row, the same "wrong but visible" failure mode vanilla DOOM has) so
134-
* a bad plane doesn't leave a blank gap on screen either.
135-
*
136-
* The clamp bound must be viewheight, not SCREENHEIGHT: this y is
137-
* stored into ds_y and later used by r_draw_span() to index
138-
* ylookup[] (r_draw.c), which r_init_buffer() only populates for
139-
* [0, viewheight) - viewheight can be smaller than SCREENHEIGHT (a
140-
* sub-window within the physical screen), so entries from viewheight
141-
* up to SCREENHEIGHT are zero-initialized (NULL) pointers. Clamping
142-
* to SCREENHEIGHT - 1 instead of viewheight - 1 traded the original
143-
* out-of-bounds write for a NULL-pointer-plus-offset framebuffer
144-
* write - confirmed on real hardware as a load/store exception at a
145-
* small virtual address. viewheight is always <= SCREENHEIGHT, so
146-
* this bound is safe for cachedheight[]/etc. too.
122+
/* Ensure array indices are in range before access. The bound is
123+
* viewheight rather than SCREENHEIGHT because r_init_buffer() only
124+
* populates ylookup[] for [0, viewheight).
147125
*/
148126

149127
if (x2 < x1 || x1 < 0 || x2 >= viewwidth)
@@ -199,34 +177,14 @@ static void r_map_plane(int y, int x1, int x2)
199177
spanfunc();
200178
}
201179

202-
/* Row indices into spanstart[] (sized SCREENHEIGHT) that are only ever
203-
* safe to use as an array index within that range - t1/b1/t2/b2 in
204-
* r_make_spans() below are also compared directly against each other to
205-
* drive the span-tracking state machine (including vanilla DOOM's 0xff
206-
* sentinel for "no span"/edge-of-plane), and that comparison logic must
207-
* see the real, un-clamped values or the sentinel handling breaks. Only
208-
* the array touches themselves need guarding.
209-
*/
210-
211180
static inline boolean r_row_in_range(int row)
212181
{
213182
return row >= 0 && row < SCREENHEIGHT;
214183
}
215184

216185
static void r_make_spans(int x, int t1, int b1, int t2, int b2)
217186
{
218-
/* t1/b1/t2/b2 come from a visplane's top[]/bottom[] arrays. In valid
219-
* play these are either a real screen row or vanilla DOOM's 0xff
220-
* (255) "no span here" sentinel; the loop conditions normally keep
221-
* that sentinel away from spanstart[]. A malformed renderer state
222-
* can violate that invariant, however: row 255 was observed reaching
223-
* r_map_plane() on real hardware, after spanstart[t1]/[b1] had already
224-
* been evaluated as the call argument. Guard every spanstart[] touch
225-
* directly instead of altering t1/b1/t2/b2, so the state-machine
226-
* comparisons and normal sentinel handling remain unchanged. An
227-
* invalid closing row uses column zero as its bounded fallback; an
228-
* invalid opening row is ignored.
229-
*/
187+
/* Check that row is in range before indexing arrays. */
230188

231189
while (t1 < t2 && t1 <= b1)
232190
{
@@ -270,13 +228,6 @@ static void r_make_spans(int x, int t1, int b1, int t2, int b2)
270228
void r_init_planes(void)
271229
{
272230
#ifdef CONFIG_GAMES_NXDOOM_HEAP_BUFFERS
273-
/* These renderer scratch buffers are sized for a comfortable margin
274-
* above vanilla DOOM's original limits and, on a DRAM-constrained
275-
* target, blow the internal DRAM budget as static arrays - opt-in
276-
* heap allocation instead (comes out of the PSRAM-backed user heap
277-
* on this target) via CONFIG_GAMES_NXDOOM_HEAP_BUFFERS.
278-
*/
279-
280231
visplanes = malloc(sizeof(visplane_t) * CONFIG_GAMES_NXDOOM_MAXVISPLANES);
281232
openings = malloc(sizeof(short) * MAXOPENINGS);
282233
drawsegs = malloc(sizeof(drawseg_t) * CONFIG_GAMES_NXDOOM_MAXDRAWSEGS);
@@ -286,29 +237,12 @@ void r_init_planes(void)
286237
if (visplanes == NULL || openings == NULL || drawsegs == NULL ||
287238
vissprites == NULL)
288239
{
289-
/* i_error() doesn't necessarily terminate the whole board on this
290-
* flat, single address-space build (see the comment below on
291-
* relaunch) - free whatever partially succeeded so a failed
292-
* allocation attempt doesn't leak across a subsequent relaunch.
293-
*/
294-
295-
free(visplanes);
296-
free(openings);
297-
free(drawsegs);
298-
free(vissprites);
299-
visplanes = NULL;
300-
openings = NULL;
301-
drawsegs = NULL;
302-
vissprites = NULL;
240+
r_shutdown_planes();
303241

304242
i_error("r_init_planes: failed to allocate renderer buffers");
305243
}
306244

307-
/* i_quit() can be followed by another r_init_planes() call within the
308-
* same boot (relaunching the game via nxpkg on this flat, single
309-
* address-space build), so these heap buffers must be freed on exit
310-
* or every relaunch leaks the previous allocation permanently.
311-
*/
245+
/* Free these on exit; the game can be started again in this process. */
312246

313247
i_at_exit(r_shutdown_planes, true);
314248
#endif
@@ -323,15 +257,29 @@ void r_init_planes(void)
323257
void r_shutdown_planes(void)
324258
{
325259
#ifdef CONFIG_GAMES_NXDOOM_HEAP_BUFFERS
326-
free(visplanes);
327-
free(openings);
328-
free(drawsegs);
329-
free(vissprites);
330-
331-
visplanes = NULL;
332-
openings = NULL;
333-
drawsegs = NULL;
334-
vissprites = NULL;
260+
if (visplanes != NULL)
261+
{
262+
free(visplanes);
263+
visplanes = NULL;
264+
}
265+
266+
if (openings != NULL)
267+
{
268+
free(openings);
269+
openings = NULL;
270+
}
271+
272+
if (drawsegs != NULL)
273+
{
274+
free(drawsegs);
275+
drawsegs = NULL;
276+
}
277+
278+
if (vissprites != NULL)
279+
{
280+
free(vissprites);
281+
vissprites = NULL;
282+
}
335283
#endif
336284
}
337285

games/NXDoom/src/i_main.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,6 @@ void d_doom_main(void);
5757

5858
int main(int argc, char **argv)
5959
{
60-
/* Lets nxstore (or any other supervisor) ask this process to exit
61-
* cleanly via SIGTERM instead of the only other option being a forced
62-
* task_delete() from outside - see i_system.h/i_system.c for why that
63-
* matters on this board (a forced kill mid framebuffer/heap access was
64-
* observed to hang the whole system, not just this task).
65-
*/
66-
6760
i_install_quit_signal();
6861

6962
/* save arguments */

games/NXDoom/src/i_system.c

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <stdio.h>
2929
#include <stdlib.h>
3030
#include <string.h>
31-
#include <syslog.h>
3231
#include <unistd.h>
3332

3433
#include "config.h"
@@ -332,41 +331,35 @@ void i_quit(void)
332331
exit(0);
333332
}
334333

335-
/* i_quit_signal_handler
334+
/****************************************************************************
335+
* Name: i_quit_signal_handler
336336
*
337-
* A supervisor process (nxstore) has no reachable in-game quit path to
338-
* drive (no keyboard/touch input is wired up here) - it can only ask
339-
* from the outside, via SIGTERM. This handler does the one thing a
340-
* signal handler is safe to do: set a flag. It must NOT call i_quit()
341-
* (or anything it does - munmap, fclose, exit()'s atexit chain) directly,
342-
* because a signal can land at literally any point in this process's own
343-
* execution, including mid-malloc()/mid-blit - exactly the same "unsafe
344-
* mid-operation teardown" risk as being force-killed from outside, just
345-
* moved from another task's context into this one. i_poll_quit_signal()
346-
* defers the real work to a known-safe boundary instead.
347-
*/
337+
* Description:
338+
* Records that a quit was requested. The work is deferred to
339+
* i_poll_quit_signal() so that no cleanup runs from signal context.
340+
*
341+
****************************************************************************/
348342

349343
static void i_quit_signal_handler(int signo)
350344
{
351345
(void)signo;
352346
quit_requested = 1;
353347
}
354348

349+
/****************************************************************************
350+
* Name: i_install_quit_signal
351+
*
352+
* Description:
353+
* Installs the SIGTERM handler used to request a clean exit.
354+
*
355+
****************************************************************************/
356+
355357
void i_install_quit_signal(void)
356358
{
357359
struct sigaction sa;
358360

359-
/* This board's flat, single address-space build can relaunch NXDoom
360-
* (via nxpkg) as a fresh loadable ELF module - a proper posix_spawn of
361-
* a new module load, which gets its own zeroed .bss/re-initialized
362-
* .data - but GAMES_NXDOOM is a tristate Kconfig symbol and can also
363-
* be built in as a true built-in (MODULE=n) sharing this process's
364-
* address space across "launches" with no fresh .bss at all. Reset
365-
* both pieces of state a stale second invocation could see: a leaked
366-
* quit_requested flag would call i_quit() again before the game even
367-
* starts, and a leaked exit_funcs chain would run every previous
368-
* invocation's exit handlers a second time (double free()s, etc.) in
369-
* addition to this invocation's own.
361+
/* Built in rather than loaded as a module, this state survives a
362+
* previous run and must be reset before the handler is armed.
370363
*/
371364

372365
quit_requested = 0;
@@ -377,22 +370,27 @@ void i_install_quit_signal(void)
377370

378371
if (sigaction(SIGTERM, &sa, NULL) < 0)
379372
{
380-
/* Not fatal - the game still runs, it just can't be asked to
381-
* close cleanly from the outside (nxstore's close button will
382-
* have nothing to signal into). Surface it rather than silently
383-
* leaving close non-functional with no trace of why.
384-
*/
373+
/* Not fatal: the game runs, it just cannot be asked to exit. */
385374

386-
syslog(LOG_WARNING,
387-
"nxdoom: failed to install SIGTERM handler: %d\n", errno);
375+
printf("nxdoom: failed to install SIGTERM handler: %d\n",
376+
errno);
388377
}
389378
}
390379

380+
/****************************************************************************
381+
* Name: i_poll_quit_signal
382+
*
383+
* Description:
384+
* Exits if a quit was requested. Called from the main loop, where the
385+
* cleanup i_quit() performs is safe to run.
386+
*
387+
****************************************************************************/
388+
391389
void i_poll_quit_signal(void)
392390
{
393391
if (quit_requested)
394392
{
395-
syslog(LOG_WARNING, "nxdoom: quit signal seen, calling i_quit\n");
393+
printf("nxdoom: quit signal seen, calling i_quit\n");
396394
i_quit();
397395
}
398396
}

games/NXDoom/src/i_system.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,14 @@ ticcmd_t *i_base_ticcmd(void);
7373

7474
void i_quit(void) NORETURN;
7575

76-
/* Installs a SIGTERM handler that only sets a flag (async-signal-safe) -
77-
* the actual i_quit() cleanup (unmapping the framebuffer, closing fds)
78-
* runs later from i_poll_quit_signal(), called once per tic from a known
79-
* safe point in the main loop rather than from the signal handler itself,
80-
* so a supervisor process (nxstore) requesting an exit can never land in
81-
* the middle of a frame's worth of direct framebuffer/heap access.
76+
/* Installs the SIGTERM handler used to request a clean exit. The handler
77+
* only records the request; i_poll_quit_signal() performs the exit.
8278
*/
8379

8480
void i_install_quit_signal(void);
8581

86-
/* Checks the flag set by the SIGTERM handler and calls i_quit() if it's
87-
* set. Must only be called from a safe point in the main loop - see
88-
* i_install_quit_signal().
82+
/* Exits if a quit was requested. Call only from the main loop, where the
83+
* cleanup i_quit() performs is safe to run.
8984
*/
9085

9186
void i_poll_quit_signal(void);

games/NXDoom/src/m_config.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,9 @@ static void load_default_collection(default_collection_t *collection)
21092109

21102110
/* Parse one physical line at a time. fscanf() with whitespace in
21112111
* its format can consume the next line as a missing value.
2112+
*
2113+
* A line too long for the buffer cannot be a valid setting, so
2114+
* discard the remainder of it and move on.
21122115
*/
21132116

21142117
if (strchr(line, '\n') == NULL &&
@@ -2159,6 +2162,10 @@ static void load_default_collection(default_collection_t *collection)
21592162
memmove(strparm, strparm + 1, sizeof(strparm) - 1);
21602163
}
21612164

2165+
/* Stripping above removes everything when the value held only
2166+
* non-printable characters.
2167+
*/
2168+
21622169
if (strparm[0] == '\0')
21632170
{
21642171
continue;

0 commit comments

Comments
 (0)