From 0bb67549981d03423ea736d139f828f71359e487 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 8 Nov 2018 15:50:53 +0200 Subject: [PATCH] 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. --- include/extern.h | 1 + include/flag.h | 1 + src/allmain.c | 2 +- src/cmd.c | 32 ++++++++++++++++++++++++++++++++ src/do.c | 2 ++ src/end.c | 12 +++++++++++- src/mail.c | 4 ++++ src/pline.c | 2 ++ src/save.c | 2 ++ src/teleport.c | 4 ++++ sys/winnt/nttty.c | 9 ++++++++- win/tty/termcap.c | 2 ++ win/tty/topl.c | 2 ++ win/tty/wintty.c | 4 ++++ 14 files changed, 76 insertions(+), 3 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8887994bb..5d82cf324 100644 --- a/include/extern.h +++ b/include/extern.h @@ -172,6 +172,7 @@ E boolean NDECL(status_hilite_menu); /* ### cmd.c ### */ +E char NDECL(randomkey); E int NDECL(doconduct); E int NDECL(domonability); E char FDECL(cmd_from_func, (int NDECL((*)))); diff --git a/include/flag.h b/include/flag.h index 58cda7838..b8c6a5993 100644 --- a/include/flag.h +++ b/include/flag.h @@ -237,6 +237,7 @@ struct instance_flags { * behaviour of various NetHack functions and probably warrant * a structure of their own elsewhere some day. */ + boolean debug_fuzzer; /* fuzz testing */ boolean defer_plname; /* X11 hack: askname() might not set plname */ boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean invis_goldsym; /* gold symbol is ' '? */ diff --git a/src/allmain.c b/src/allmain.c index 39f38e1f7..9c76b2c00 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -389,7 +389,7 @@ boolean resuming; continue; } - if (iflags.sanity_check) + if (iflags.sanity_check || iflags.debug_fuzzer) sanity_check(); #ifdef CLIPPING diff --git a/src/cmd.c b/src/cmd.c index 52766a773..c783a5b2e 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -298,6 +298,8 @@ pgetchar() /* courtesy of aeb@cwi.nl */ { register int ch; + if (iflags.debug_fuzzer) + return randomkey(); if (!(ch = popch())) ch = nhgetch(); return (char) ch; @@ -942,6 +944,11 @@ wiz_level_change(VOID_ARGS) STATIC_PTR int 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') panic("Crash test."); return 0; @@ -4354,6 +4361,29 @@ int NDECL((*cmd_func)); 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 ch2spkeys(c, start, end) char c; @@ -5563,6 +5593,8 @@ readchar() register int sym; int x = u.ux, y = u.uy, mod = 0; + if (iflags.debug_fuzzer) + return randomkey(); if (*readchar_queue) sym = *readchar_queue++; else diff --git a/src/do.c b/src/do.c index a403376b7..bcae4ca43 100644 --- a/src/do.c +++ b/src/do.c @@ -1061,6 +1061,8 @@ doup() return 1; } if (ledger_no(&u.uz) == 1) { + if (iflags.debug_fuzzer) + return 0; if (yn("Beware, there will be no return! Still climb?") != 'y') return 0; } diff --git a/src/end.c b/src/end.c index c423fbcde..9cd4d40a0 100644 --- a/src/end.c +++ b/src/end.c @@ -330,6 +330,8 @@ int sig_unused UNUSED; int done2() { + if (iflags.debug_fuzzer) + return 0; if (!paranoid_query(ParanoidQuit, "Really quit?")) { #ifndef NO_SIGNAL (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 * suppress "it may be possible to rebuild" based on dosave0() * 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(); if (dosave0()) { /* os/win port specific recover instructions */ @@ -1043,6 +1045,14 @@ int how; 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)) killer.format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ diff --git a/src/mail.c b/src/mail.c index 067dab09f..3f47e3a55 100644 --- a/src/mail.c +++ b/src/mail.c @@ -642,6 +642,8 @@ struct obj *otmp UNUSED; return; #endif /* SIMPLE_MAIL */ #ifdef DEF_MAILREADER /* This implies that UNIX is defined */ + if (iflags.debug_fuzzer) + return; display_nhwindow(WIN_MESSAGE, FALSE); if (!(mr = nh_getenv("MAILREADER"))) mr = DEF_MAILREADER; @@ -674,6 +676,8 @@ ckmailstatus() { struct mail_info *brdcst; + if (iflags.debug_fuzzer) + return; if (u.uswallow || !flags.biff) return; diff --git a/src/pline.c b/src/pline.c index 1f604e206..e88eea5cf 100644 --- a/src/pline.c +++ b/src/pline.c @@ -453,6 +453,8 @@ VA_DECL(const char *, s) Vsprintf(pbuf, s, VA_ARGS); pbuf[BUFSZ - 1] = '\0'; /* sanity */ paniclog("impossible", pbuf); + if (iflags.debug_fuzzer) + panic(pbuf); pline("%s", VA_PASS1(pbuf)); pline(VA_PASS1( "Program in disorder! (Saving and reloading may fix this problem.)")); diff --git a/src/save.c b/src/save.c index 927798cd9..d7827fcfd 100644 --- a/src/save.c +++ b/src/save.c @@ -77,6 +77,8 @@ static unsigned ustuck_id = 0, usteed_id = 0; int dosave() { + if (iflags.debug_fuzzer) + return 0; clear_nhwindow(WIN_MESSAGE); if (yn("Really save?") == 'n') { clear_nhwindow(WIN_MESSAGE); diff --git a/src/teleport.c b/src/teleport.c index a1adfd95d..9a6ff8f19 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -608,6 +608,8 @@ level_tele() char buf[BUFSZ]; boolean force_dest = FALSE; + if (iflags.debug_fuzzer) + goto random_levtport; if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz)) && !wizard) { You_feel("very disoriented for a moment."); @@ -750,6 +752,8 @@ level_tele() killer.name[0] = 0; /* still alive, so far... */ + if (iflags.debug_fuzzer && newlev < 0) + goto random_levtport; if (newlev < 0 && !force_dest) { if (*u.ushops0) { /* take unpaid inventory items off of shop bills */ diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index e983d36fb..0409d3336 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -433,6 +433,8 @@ tgetch() coord cc; DWORD count; really_move_cursor(); + if (iflags.debug_fuzzer) + return randomkey(); return (program_state.done_hup) ? '\033' : keyboard_handler.pCheckInput( @@ -447,6 +449,8 @@ int *x, *y, *mod; coord cc; DWORD count; really_move_cursor(); + if (iflags.debug_fuzzer) + return randomkey(); ch = (program_state.done_hup) ? '\033' : keyboard_handler.pCheckInput( @@ -704,7 +708,7 @@ cl_eos() void tty_nhbell() { - if (flags.silent) + if (flags.silent || iflags.debug_fuzzer) return; Beep(8000, 500); } @@ -718,6 +722,9 @@ tty_delay_output() clock_t goal; int k; + if (iflags.debug_fuzzer) + return; + goal = 50 + clock(); back_buffer_flip(); while (goal > clock()) { diff --git a/win/tty/termcap.c b/win/tty/termcap.c index 31203811a..5f344f04b 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -748,6 +748,8 @@ tty_delay_output() #if defined(MICRO) register int i; #endif + if (iflags.debug_fuzzer) + return; #ifdef TIMED_DELAY if (flags.nap) { (void) fflush(stdout); diff --git a/win/tty/topl.c b/win/tty/topl.c index 97919a3d9..5233e1525 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -186,6 +186,8 @@ more() /* avoid recursion -- only happens from interrupts */ if (ttyDisplay->inmore++) return; + if (iflags.debug_fuzzer) + return; if (ttyDisplay->toplin) { tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 2794331c8..8ebac1267 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3344,6 +3344,9 @@ tty_nhgetch() */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; + if (iflags.debug_fuzzer) { + i = randomkey(); + } else { #ifdef UNIX i = (++nesting == 1) ? tgetch() : (read(fileno(stdin), (genericptr_t) &nestbuf, 1) @@ -3352,6 +3355,7 @@ tty_nhgetch() #else i = tgetch(); #endif + } if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ else if (i == EOF)