fix #H7352 - panic when floodfilling large areas

Special levels with FLAGS:inaccessibles could trigger a panic if
a large enough area was subjected to floodfill handling.  The buffer
intended to be enough to hold an entire level wasn't big enough when
individual coordinates were being added multiple times.  I don't
really understand what this code is doing but the recommended fix
does work to prevent the panic.

None of the levels included with 3.6.x were affected.
This commit is contained in:
PatR
2018-08-13 18:33:15 -07:00
parent 3774cb29f3
commit 34c1d30370
2 changed files with 31 additions and 7 deletions
+2
View File
@@ -81,6 +81,8 @@ succubus/incubus seduction might result in loss of levitation which in turn
seduction was proceeding as if nothing unusual had happened seduction was proceeding as if nothing unusual had happened
#turn command which aggravated monsters did so without using a turn (not a pun) #turn command which aggravated monsters did so without using a turn (not a pun)
fix hole/trapdoor passage inconsistency when polymorphed into a giant fix hole/trapdoor passage inconsistency when polymorphed into a giant
making a wide-open special level with FLAGS:inaccessibles could trigger a
"floodfill stack overrun" panic (no 3.6.x levels were affected)
Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository
+29 -7
View File
@@ -126,6 +126,8 @@ STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *,
STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int)); STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int));
STATIC_DCL int FDECL(floodfillchk_match_under, (int, int)); STATIC_DCL int FDECL(floodfillchk_match_under, (int, int));
STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int)); STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int));
STATIC_DCL boolean FDECL(sel_flood_havepoint, (int, int,
xchar *, xchar *, int));
STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int, STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int,
int, int, int)); int, int, int));
STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long)); STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long));
@@ -3895,6 +3897,23 @@ int x, y;
|| levl[x][y].typ == SCORR); || levl[x][y].typ == SCORR);
} }
/* check whethere <x,y> is already in xs[],ys[] */
STATIC_OVL boolean
sel_flood_havepoint(x, y, xs, ys, n)
int x, y;
xchar xs[], ys[];
int n;
{
xchar xx = (xchar) x, yy = (xchar) y;
while (n > 0) {
if (xs[n] == xx && ys[n] == yy)
return TRUE;
--n;
}
return FALSE;
}
void void
selection_floodfill(ov, x, y, diagonals) selection_floodfill(ov, x, y, diagonals)
struct opvar *ov; struct opvar *ov;
@@ -3904,7 +3923,7 @@ boolean diagonals;
static const char nhFunc[] = "selection_floodfill"; static const char nhFunc[] = "selection_floodfill";
struct opvar *tmp = selection_opvar((char *) 0); struct opvar *tmp = selection_opvar((char *) 0);
#define SEL_FLOOD_STACK (COLNO * ROWNO) #define SEL_FLOOD_STACK (COLNO * ROWNO)
#define SEL_FLOOD(nx, ny) \ #define SEL_FLOOD(nx, ny) \
do { \ do { \
if (idx < SEL_FLOOD_STACK) { \ if (idx < SEL_FLOOD_STACK) { \
dx[idx] = (nx); \ dx[idx] = (nx); \
@@ -3913,17 +3932,20 @@ boolean diagonals;
} else \ } else \
panic(floodfill_stack_overrun); \ panic(floodfill_stack_overrun); \
} while (0) } while (0)
#define SEL_FLOOD_CHKDIR(mx,my,sel) \ #define SEL_FLOOD_CHKDIR(mx, my, sel) \
if (isok((mx), (my)) \ do { \
&& (*selection_flood_check_func)((mx), (my)) \ if (isok((mx), (my)) \
&& !selection_getpoint((mx), (my), (sel))) \ && (*selection_flood_check_func)((mx), (my)) \
SEL_FLOOD((mx), (my)) && !selection_getpoint((mx), (my), (sel)) \
&& !sel_flood_havepoint((mx), (my), dx, dy, idx)) \
SEL_FLOOD((mx), (my)); \
} while (0)
static const char floodfill_stack_overrun[] = "floodfill stack overrun"; static const char floodfill_stack_overrun[] = "floodfill stack overrun";
int idx = 0; int idx = 0;
xchar dx[SEL_FLOOD_STACK]; xchar dx[SEL_FLOOD_STACK];
xchar dy[SEL_FLOOD_STACK]; xchar dy[SEL_FLOOD_STACK];
if (selection_flood_check_func == NULL) { if (selection_flood_check_func == (int FDECL((*), (int, int))) 0) {
opvar_free(tmp); opvar_free(tmp);
return; return;
} }