Skip to content

Commit a8782c9

Browse files
committed
Fix: curses popup-dialog getline bypassed debug_fuzzer hook.
Fuzzing in curses mode runs pretty slowly, but I was consistently watching the fuzzer stall after only a few turns. This commit addresses that issue. * win/curses/cursdial.c: the popup_dialog branch of curses_line_input_dialog() called wgetnstr() to read the answer, but wgetnstr() reads real PTY stdin and bypasses the curses_getch() -> randomkey() fuzz hook used by every other curses input path. So once popup_dialog was toggled on, any getlin() prompt (e.g. setting compound options like packorder or fruit name from the in-game options menu) hung the fuzzer indefinitely. Replace wgetnstr() with a hand-rolled curses_getch() loop that mirrors the special-key handling in curses_message_win_getline(): ENTER/RETURN accept, ESC returns "\033", backspace / erase_char / KEY_BACKSPACE / KEY_DC erase the previous char, kill_char (when a control char) clears the line, ERR returns empty. Drop the echo() / noecho() toggle since each char is now drawn manually via mvwaddch(). Real users with popup_dialog on see no functional change beyond ESC reliably cancelling the prompt and ^U being honored uniformly with the non-popup path.
1 parent b1c0a16 commit a8782c9

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

‎doc/evilhack-changelog.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5450,4 +5450,5 @@ The following changes to date are:
54505450
- Fix: curses convert-glyph fallback indexed defsyms[] out of bounds
54515451
- Fix: three correctness issues in the curses windowport
54525452
- Fix: nine correctness issues in the curses windowport (pass two)
5453+
- Fix: curses popup-dialog getline bypassed debug_fuzzer hook
54535454

‎win/curses/cursdial.c‎

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,66 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer)
186186
free(tmpstr);
187187
}
188188

189-
echo();
190-
curs_set(1);
191-
wgetnstr(askwin, input, buffer - 1);
192-
curs_set(0);
189+
{
190+
/* Hand-rolled line input so debug_fuzzer mode can drive this
191+
prompt. wgetnstr() would block on real stdin and bypass the
192+
curses_getch() -> randomkey() hook used by every other curses
193+
input path */
194+
int x_in, y_in, ch, len = 0;
195+
int max_in = buffer - 1;
196+
197+
getyx(askwin, y_in, x_in);
198+
input[0] = '\0';
199+
curs_set(1);
200+
while (1) {
201+
wmove(askwin, y_in, x_in + len);
202+
wrefresh(askwin);
203+
ch = curses_getch();
204+
if (ch == ERR) {
205+
input[0] = '\0';
206+
break;
207+
}
208+
if (ch == '\033') {
209+
input[0] = '\033';
210+
input[1] = '\0';
211+
break;
212+
}
213+
if (ch == '\r' || ch == '\n') {
214+
input[len] = '\0';
215+
break;
216+
}
217+
if (ch == '\b' || ch == '\177'
218+
|| ch == KEY_BACKSPACE || ch == KEY_DC
219+
|| (erase_char && ch == (int) (uchar) erase_char)) {
220+
if (len > 0) {
221+
len--;
222+
input[len] = '\0';
223+
mvwaddch(askwin, y_in, x_in + len, ' ');
224+
}
225+
continue;
226+
}
227+
/* honor kill_char if it's a control char, not if it's '@' */
228+
if (kill_char && ch == (int) (uchar) kill_char
229+
&& (ch < ' ' || ch >= '\177')) {
230+
while (len > 0) {
231+
len--;
232+
mvwaddch(askwin, y_in, x_in + len, ' ');
233+
}
234+
input[0] = '\0';
235+
continue;
236+
}
237+
if (len < max_in) {
238+
input[len++] = (char) ch;
239+
input[len] = '\0';
240+
mvwaddch(askwin, y_in, x_in + len - 1, ch);
241+
}
242+
}
243+
curs_set(0);
244+
}
193245
Strcpy(answer, input);
194246
werase(bwin);
195247
delwin(bwin);
196248
curses_destroy_win(askwin);
197-
noecho();
198249
}
199250

200251
/* Get a single character response from the player, such as a y/n prompt */

0 commit comments

Comments
 (0)