From b8897db3088e807f0866fb9f3b3fbd194dcf7b89 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 21:55:14 -0500 Subject: [PATCH] Fix crash when page text is empty; add checks for MAX_PROMPTS and MAX_PAGES --- src/dehacked.c | 6 +++--- src/doomstat.h | 7 +++++-- src/f_finale.c | 17 ++++++++++------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index dcd61bd31..0802fc49d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1773,17 +1773,17 @@ static void readtextprompt(MYFILE *f, INT32 num) if (fastcmp(word, "NUMPAGES")) { - textprompts[num]->numpages = value; + textprompts[num]->numpages = min(max(value, 0), MAX_PAGES); } else if (fastcmp(word, "PAGE")) { - if (1 <= value && value <= 128) + if (1 <= value && value <= MAX_PAGES) { textprompts[num]->page[value - 1].backcolor = UINT8_MAX; // non-zero default readtextpromptpage(f, num, value - 1); } else - deh_warning("Page number %d out of range (1 - 128)", value); + deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES); } else diff --git a/src/doomstat.h b/src/doomstat.h index 7bcf59946..eb1726e54 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -166,6 +166,9 @@ typedef struct extern cutscene_t *cutscenes[128]; +#define MAX_PROMPTS 256 +#define MAX_PAGES 128 + typedef struct { char name[32]; // narrator name @@ -186,11 +189,11 @@ typedef struct typedef struct { - textpage_t page[128]; // 128 pages per prompt. + textpage_t page[MAX_PAGES]; INT32 numpages; // Number of pages in this prompt } textprompt_t; -extern textprompt_t *textprompts[256]; +extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. extern INT16 nextmapoverride; diff --git a/src/f_finale.c b/src/f_finale.c index 8a6a8ce0c..f32e44b57 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2065,7 +2065,7 @@ static void F_PreparePageText(char *pagetext) if (promptpagetext) Z_Free(promptpagetext); - promptpagetext = V_WordWrap(textx, textr, 0, pagetext); + promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : ""; F_NewCutscene(promptpagetext); cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5; @@ -2085,7 +2085,7 @@ static void F_AdvanceToNextPage(void) // determine next prompt if (nextprompt) { - if (textprompts[nextprompt-1]) + if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt-1]) cutnum = nextprompt-1; else cutnum = INT32_MAX; @@ -2095,14 +2095,14 @@ static void F_AdvanceToNextPage(void) if (nextpage) { scenenum = nextpage-1; - if (scenenum > textprompts[cutnum]->numpages-1) + if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1) scenenum = INT32_MAX; } else { if (cutnum != oldcutnum) scenenum = 0; - else if (scenenum < textprompts[cutnum]->numpages-1) + else if (scenenum + 1 < MAX_PAGES && scenenum < textprompts[cutnum]->numpages-1) scenenum++; else scenenum = INT32_MAX; @@ -2157,8 +2157,8 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers // Initialize current prompt and scene - cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; - scenenum = (cutnum != INT32_MAX && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; + cutnum = (promptnum < MAX_PROMPTS && textprompts[promptnum]) ? promptnum : INT32_MAX; + scenenum = (cutnum != INT32_MAX && pagenum < MAX_PAGES && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); if (promptactive) @@ -2320,7 +2320,10 @@ void F_TextPromptTicker(void) } // generate letter-by-letter text - if (!F_WriteText()) + if (scenenum >= MAX_PAGES || + !textprompts[cutnum]->page[scenenum].text || + !textprompts[cutnum]->page[scenenum].text[0] || + !F_WriteText()) timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages }