Fuzz testing debug tool

Add code to run a fuzz tester, simulating (more-or-less) random
keyboard mashing. There's no option to turn it on, you need to
set iflags.debug_fuzzer on via a debugger or something along
those lines.
This commit is contained in:
Pasi Kallinen
2018-11-08 15:55:49 +02:00
parent 4f541fe216
commit 0bb6754998
14 changed files with 76 additions and 3 deletions
+1
View File
@@ -172,6 +172,7 @@ E boolean NDECL(status_hilite_menu);
/* ### cmd.c ### */ /* ### cmd.c ### */
E char NDECL(randomkey);
E int NDECL(doconduct); E int NDECL(doconduct);
E int NDECL(domonability); E int NDECL(domonability);
E char FDECL(cmd_from_func, (int NDECL((*)))); E char FDECL(cmd_from_func, (int NDECL((*))));
+1
View File
@@ -237,6 +237,7 @@ struct instance_flags {
* behaviour of various NetHack functions and probably warrant * behaviour of various NetHack functions and probably warrant
* a structure of their own elsewhere some day. * a structure of their own elsewhere some day.
*/ */
boolean debug_fuzzer; /* fuzz testing */
boolean defer_plname; /* X11 hack: askname() might not set plname */ boolean defer_plname; /* X11 hack: askname() might not set plname */
boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean herecmd_menu; /* use menu when mouseclick on yourself */
boolean invis_goldsym; /* gold symbol is ' '? */ boolean invis_goldsym; /* gold symbol is ' '? */
+1 -1
View File
@@ -389,7 +389,7 @@ boolean resuming;
continue; continue;
} }
if (iflags.sanity_check) if (iflags.sanity_check || iflags.debug_fuzzer)
sanity_check(); sanity_check();
#ifdef CLIPPING #ifdef CLIPPING
+32
View File
@@ -298,6 +298,8 @@ pgetchar() /* courtesy of aeb@cwi.nl */
{ {
register int ch; register int ch;
if (iflags.debug_fuzzer)
return randomkey();
if (!(ch = popch())) if (!(ch = popch()))
ch = nhgetch(); ch = nhgetch();
return (char) ch; return (char) ch;
@@ -942,6 +944,11 @@ wiz_level_change(VOID_ARGS)
STATIC_PTR int STATIC_PTR int
wiz_panic(VOID_ARGS) wiz_panic(VOID_ARGS)
{ {
if (iflags.debug_fuzzer) {
u.uhp = u.uhpmax = 1000;
u.uen = u.uenmax = 1000;
return 0;
}
if (yn("Do you want to call panic() and end your game?") == 'y') if (yn("Do you want to call panic() and end your game?") == 'y')
panic("Crash test."); panic("Crash test.");
return 0; return 0;
@@ -4354,6 +4361,29 @@ int NDECL((*cmd_func));
return FALSE; return FALSE;
} }
char
randomkey()
{
static int i = 0;
char c;
switch (rn2(12)) {
default: c = '\033'; break;
case 0: c = '\n'; break;
case 1:
case 2:
case 3:
case 4: c = (char)(' ' + rn2((int)('~' - ' '))); break;
case 5: c = '\t'; break;
case 6: c = (char)('a' + rn2((int)('z' - 'a'))); break;
case 7: c = (char)('A' + rn2((int)('Z' - 'A'))); break;
case 8: c = extcmdlist[(i++) % SIZE(extcmdlist)].key; break;
case 9: c = '#'; break;
}
return c;
}
int int
ch2spkeys(c, start, end) ch2spkeys(c, start, end)
char c; char c;
@@ -5563,6 +5593,8 @@ readchar()
register int sym; register int sym;
int x = u.ux, y = u.uy, mod = 0; int x = u.ux, y = u.uy, mod = 0;
if (iflags.debug_fuzzer)
return randomkey();
if (*readchar_queue) if (*readchar_queue)
sym = *readchar_queue++; sym = *readchar_queue++;
else else
+2
View File
@@ -1061,6 +1061,8 @@ doup()
return 1; return 1;
} }
if (ledger_no(&u.uz) == 1) { if (ledger_no(&u.uz) == 1) {
if (iflags.debug_fuzzer)
return 0;
if (yn("Beware, there will be no return! Still climb?") != 'y') if (yn("Beware, there will be no return! Still climb?") != 'y')
return 0; return 0;
} }
+11 -1
View File
@@ -330,6 +330,8 @@ int sig_unused UNUSED;
int int
done2() done2()
{ {
if (iflags.debug_fuzzer)
return 0;
if (!paranoid_query(ParanoidQuit, "Really quit?")) { if (!paranoid_query(ParanoidQuit, "Really quit?")) {
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
(void) signal(SIGINT, (SIG_RET_TYPE) done1); (void) signal(SIGINT, (SIG_RET_TYPE) done1);
@@ -602,7 +604,7 @@ VA_DECL(const char *, str)
/* XXX can we move this above the prints? Then we'd be able to /* XXX can we move this above the prints? Then we'd be able to
* suppress "it may be possible to rebuild" based on dosave0() * suppress "it may be possible to rebuild" based on dosave0()
* or say it's NOT possible to rebuild. */ * or say it's NOT possible to rebuild. */
if (program_state.something_worth_saving) { if (program_state.something_worth_saving && !iflags.debug_fuzzer) {
set_error_savefile(); set_error_savefile();
if (dosave0()) { if (dosave0()) {
/* os/win port specific recover instructions */ /* os/win port specific recover instructions */
@@ -1043,6 +1045,14 @@ int how;
bot(); bot();
} }
if (iflags.debug_fuzzer) {
if (!(program_state.panicking || how == PANICKED)) {
savelife(how);
killer.name[0] = 0;
killer.format = 0;
return;
}
} else
if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED)) if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
killer.format = NO_KILLER_PREFIX; killer.format = NO_KILLER_PREFIX;
/* Avoid killed by "a" burning or "a" starvation */ /* Avoid killed by "a" burning or "a" starvation */
+4
View File
@@ -642,6 +642,8 @@ struct obj *otmp UNUSED;
return; return;
#endif /* SIMPLE_MAIL */ #endif /* SIMPLE_MAIL */
#ifdef DEF_MAILREADER /* This implies that UNIX is defined */ #ifdef DEF_MAILREADER /* This implies that UNIX is defined */
if (iflags.debug_fuzzer)
return;
display_nhwindow(WIN_MESSAGE, FALSE); display_nhwindow(WIN_MESSAGE, FALSE);
if (!(mr = nh_getenv("MAILREADER"))) if (!(mr = nh_getenv("MAILREADER")))
mr = DEF_MAILREADER; mr = DEF_MAILREADER;
@@ -674,6 +676,8 @@ ckmailstatus()
{ {
struct mail_info *brdcst; struct mail_info *brdcst;
if (iflags.debug_fuzzer)
return;
if (u.uswallow || !flags.biff) if (u.uswallow || !flags.biff)
return; return;
+2
View File
@@ -453,6 +453,8 @@ VA_DECL(const char *, s)
Vsprintf(pbuf, s, VA_ARGS); Vsprintf(pbuf, s, VA_ARGS);
pbuf[BUFSZ - 1] = '\0'; /* sanity */ pbuf[BUFSZ - 1] = '\0'; /* sanity */
paniclog("impossible", pbuf); paniclog("impossible", pbuf);
if (iflags.debug_fuzzer)
panic(pbuf);
pline("%s", VA_PASS1(pbuf)); pline("%s", VA_PASS1(pbuf));
pline(VA_PASS1( pline(VA_PASS1(
"Program in disorder! (Saving and reloading may fix this problem.)")); "Program in disorder! (Saving and reloading may fix this problem.)"));
+2
View File
@@ -77,6 +77,8 @@ static unsigned ustuck_id = 0, usteed_id = 0;
int int
dosave() dosave()
{ {
if (iflags.debug_fuzzer)
return 0;
clear_nhwindow(WIN_MESSAGE); clear_nhwindow(WIN_MESSAGE);
if (yn("Really save?") == 'n') { if (yn("Really save?") == 'n') {
clear_nhwindow(WIN_MESSAGE); clear_nhwindow(WIN_MESSAGE);
+4
View File
@@ -608,6 +608,8 @@ level_tele()
char buf[BUFSZ]; char buf[BUFSZ];
boolean force_dest = FALSE; boolean force_dest = FALSE;
if (iflags.debug_fuzzer)
goto random_levtport;
if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz)) if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
&& !wizard) { && !wizard) {
You_feel("very disoriented for a moment."); You_feel("very disoriented for a moment.");
@@ -750,6 +752,8 @@ level_tele()
killer.name[0] = 0; /* still alive, so far... */ killer.name[0] = 0; /* still alive, so far... */
if (iflags.debug_fuzzer && newlev < 0)
goto random_levtport;
if (newlev < 0 && !force_dest) { if (newlev < 0 && !force_dest) {
if (*u.ushops0) { if (*u.ushops0) {
/* take unpaid inventory items off of shop bills */ /* take unpaid inventory items off of shop bills */
+8 -1
View File
@@ -433,6 +433,8 @@ tgetch()
coord cc; coord cc;
DWORD count; DWORD count;
really_move_cursor(); really_move_cursor();
if (iflags.debug_fuzzer)
return randomkey();
return (program_state.done_hup) return (program_state.done_hup)
? '\033' ? '\033'
: keyboard_handler.pCheckInput( : keyboard_handler.pCheckInput(
@@ -447,6 +449,8 @@ int *x, *y, *mod;
coord cc; coord cc;
DWORD count; DWORD count;
really_move_cursor(); really_move_cursor();
if (iflags.debug_fuzzer)
return randomkey();
ch = (program_state.done_hup) ch = (program_state.done_hup)
? '\033' ? '\033'
: keyboard_handler.pCheckInput( : keyboard_handler.pCheckInput(
@@ -704,7 +708,7 @@ cl_eos()
void void
tty_nhbell() tty_nhbell()
{ {
if (flags.silent) if (flags.silent || iflags.debug_fuzzer)
return; return;
Beep(8000, 500); Beep(8000, 500);
} }
@@ -718,6 +722,9 @@ tty_delay_output()
clock_t goal; clock_t goal;
int k; int k;
if (iflags.debug_fuzzer)
return;
goal = 50 + clock(); goal = 50 + clock();
back_buffer_flip(); back_buffer_flip();
while (goal > clock()) { while (goal > clock()) {
+2
View File
@@ -748,6 +748,8 @@ tty_delay_output()
#if defined(MICRO) #if defined(MICRO)
register int i; register int i;
#endif #endif
if (iflags.debug_fuzzer)
return;
#ifdef TIMED_DELAY #ifdef TIMED_DELAY
if (flags.nap) { if (flags.nap) {
(void) fflush(stdout); (void) fflush(stdout);
+2
View File
@@ -186,6 +186,8 @@ more()
/* avoid recursion -- only happens from interrupts */ /* avoid recursion -- only happens from interrupts */
if (ttyDisplay->inmore++) if (ttyDisplay->inmore++)
return; return;
if (iflags.debug_fuzzer)
return;
if (ttyDisplay->toplin) { if (ttyDisplay->toplin) {
tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury);
+4
View File
@@ -3344,6 +3344,9 @@ tty_nhgetch()
*/ */
if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
wins[WIN_MESSAGE]->flags &= ~WIN_STOP; wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
if (iflags.debug_fuzzer) {
i = randomkey();
} else {
#ifdef UNIX #ifdef UNIX
i = (++nesting == 1) ? tgetch() i = (++nesting == 1) ? tgetch()
: (read(fileno(stdin), (genericptr_t) &nestbuf, 1) : (read(fileno(stdin), (genericptr_t) &nestbuf, 1)
@@ -3352,6 +3355,7 @@ tty_nhgetch()
#else #else
i = tgetch(); i = tgetch();
#endif #endif
}
if (!i) if (!i)
i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
else if (i == EOF) else if (i == EOF)