aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Harris <bjh21@bjh21.me.uk>2023-01-12 20:55:56 +0000
committerBen Harris <bjh21@bjh21.me.uk>2023-01-15 16:24:27 +0000
commit21193eaf9308ace41004a19180ff382ec6e8754b (patch)
tree485d428a0f54c74bb4f470fbd6daf7093f9c4f30
parentb3d4a4197954c21ac78b68c58dff8f84fe743ea2 (diff)
downloadpuzzles-21193eaf9308ace41004a19180ff382ec6e8754b.zip
puzzles-21193eaf9308ace41004a19180ff382ec6e8754b.tar.gz
puzzles-21193eaf9308ace41004a19180ff382ec6e8754b.tar.bz2
puzzles-21193eaf9308ace41004a19180ff382ec6e8754b.tar.xz
Palisade: forbid moves that remove grid edges
Without this check, a corrupt save file can include a move that removes an edge of the grid, and then is_solved() walks off the edge of the grid causing a buffer over- or under-run. To demonstrate the bug, load this save file in a build with AddressSanitizer: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Palisade PARAMS :5:5x5n5 CPARAMS :5:5x5n5 DESC :0: NSTATES :1:2 STATEPOS:1:2 MOVE :6:F0,0,1
-rw-r--r--palisade.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/palisade.c b/palisade.c
index 6661f5b..4096d12 100644
--- a/palisade.c
+++ b/palisade.c
@@ -1010,10 +1010,9 @@ static game_state *execute_move(const game_state *state, const char *move)
{
int w = state->shared->params.w, h = state->shared->params.h, wh = w * h;
game_state *ret = dup_game(state);
- int nchars, x, y, flag;
+ int nchars, x, y, flag, i;
if (*move == 'S') {
- int i;
++move;
for (i = 0; i < wh && move[i]; ++i)
ret->borders[i] =
@@ -1026,6 +1025,11 @@ static game_state *execute_move(const game_state *state, const char *move)
while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 &&
!OUT_OF_BOUNDS(x, y, w, h)) {
move += nchars;
+ for (i = 0; i < 4; i++)
+ if ((flag & BORDER(i)) &&
+ OUT_OF_BOUNDS(x+dx[i], y+dy[i], w, h))
+ /* No toggling the borders of the grid! */
+ goto badmove;
ret->borders[y*w + x] ^= flag;
}
@@ -1036,6 +1040,10 @@ static game_state *execute_move(const game_state *state, const char *move)
ret->borders);
return ret;
+
+ badmove:
+ sfree(ret);
+ return NULL;
}
/* --- Drawing routines --------------------------------------------- */