Version in base suite: 20191231.79a5378-3 Base version: sgt-puzzles_20191231.79a5378-3 Target version: sgt-puzzles_20191231.79a5378-3+deb11u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/sgt-puzzles/sgt-puzzles_20191231.79a5378-3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/sgt-puzzles/sgt-puzzles_20191231.79a5378-3+deb11u1.dsc .gitignore | 6 changelog | 136 +++ patches/0001-Black-Box-reject-negative-ball-counts-in-game_params.patch | 34 patches/0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch | 125 +++ patches/0004-Makefile.doc-Remove-CHM-files-in-clean-rule.patch | 1 patches/0006-Don-t-allow-Bridges-games-with-2-islands.patch | 56 + patches/0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch | 36 patches/0007-Mines-add-validation-for-negative-mine-count.patch | 22 patches/0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch | 41 + patches/0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch | 38 + patches/0010-Limit-number-of-mines-in-Mines-game-description.patch | 26 patches/0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch | 42 + patches/0012-unruly-Fix-memory-leak-in-dup_game.patch | 1 patches/0013-bridges-Fix-off-by-one-in-WITHIN.patch | 1 patches/0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch | 1 patches/0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch | 28 patches/0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch | 42 + patches/0019-Avoid-invalid-moves-when-solving-Tracks.patch | 64 + patches/0020-Fix-move-validation-in-Netslide.patch | 40 + patches/0021-Tighten-validation-of-Tents-game-descriptions.patch | 55 + patches/0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch | 49 + patches/0023-Forbid-lines-off-the-grid-in-Pearl.patch | 48 + patches/0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch | 40 + patches/0024-Tolerate-incorrect-solutions-in-Inertia.patch | 50 + patches/0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch | 109 ++ patches/0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch | 212 +++++ patches/0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch | 85 ++ patches/0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch | 34 patches/0028-Pearl-fix-bounds-check-in-previous-commit.patch | 22 patches/0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch | 58 + patches/0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch | 27 patches/0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch | 39 + patches/0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch | 35 patches/0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch | 28 patches/0034-Forbid-impossible-moves-in-Bridges.patch | 46 + patches/0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch | 62 + patches/0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch | 129 +++ patches/0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch | 45 + patches/0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch | 51 + patches/0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch | 50 + patches/0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch | 33 patches/0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch | 21 patches/0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch | 29 patches/0046-Don-t-leak-duplicate-edges-in-Untangle.patch | 27 patches/0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch | 22 patches/0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch | 35 patches/0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch | 29 patches/0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch | 32 patches/0055-Validate-that-save-file-values-are-ASCII-mostly.patch | 37 patches/0056-More-validation-of-solve-moves-in-Flood.patch | 29 patches/0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch | 54 + patches/0059-Tighten-grid-size-limit-in-Mines.patch | 46 + patches/0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch | 30 patches/0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch | 28 patches/0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch | 31 patches/0081-Map-add-missing-sresize-in-new_game_desc.patch | 30 patches/0090-Fix-memory-leak-in-midend_game_id_int.patch | 32 patches/0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch | 35 patches/0101-Be-more-careful-with-type-of-left-operand-of.patch | 45 + patches/0102-Map-reduce-maximum-size.patch | 23 patches/0103-Correctly-handle-some-short-save-files.patch | 40 + patches/0104-Inertia-insist-that-solutions-must-be-non-empty.patch | 29 patches/0114-Add-more-validation-to-midend-deserialisation-routin.patch | 98 ++ patches/0115-Correct-and-enable-the-range-check-on-statepos-when-.patch | 35 patches/0115-Galaxies-fix-recursion-depth-limit-in-solver.patch | 89 ++ patches/0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch | 134 +++ patches/0122-Add-assertions-that-game-descriptions-consist-only-o.patch | 73 + patches/0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch | 67 + patches/0124-Assert-that-everything-written-to-a-save-file-is-pri.patch | 31 patches/0129-Build-fix-take-declarations-out-of-for-loops.patch | 35 patches/0138-Correct-a-range-check-in-Magnets-layout-verification.patch | 24 patches/0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch | 31 patches/0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch | 38 + patches/0159-Don-t-allow-zero-clues-in-Pattern.patch | 34 patches/0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch | 63 + patches/0263-magnets-Area-constraints-fix-message.patch | 37 patches/0266-lightup-Ban-2x2-with-either-4-way-type.patch | 25 patches/0267-Remove-_-introduced-from-Android-port.patch | 22 patches/0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch | 26 patches/0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch | 50 + patches/0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch | 40 + patches/0300-Guess-validate-peg-colours-in-decode_ui.patch | 50 + patches/0302-Netslide-Reject-moves-wider-than-the-grid.patch | 60 + patches/0303-Sixteen-limit-length-of-moves.patch | 44 + patches/0304-Undead-check-for-valid-commands-in-execute_move.patch | 55 + patches/0305-Undead-fix-buffer-overrun-in-M-command.patch | 27 patches/0306-Correct-RANGECHECK-macro-in-Black-Box.patch | 23 patches/0307-Range-check-normal-moves-in-Undead.patch | 41 + patches/0308-Range-check-record-lengths-when-deserialising-games.patch | 42 + patches/0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch | 49 + patches/0310-Palisade-forbid-moves-that-remove-grid-edges.patch | 63 + patches/0311-Last-ditch-maximum-size-limit-for-Bridges.patch | 31 patches/0312-Last-ditch-grid-size-limit-for-Dominosa.patch | 32 patches/0313-Last-ditch-grid-size-limit-for-Galaxies.patch | 32 patches/0314-Last-ditch-grid-size-limit-for-Fifteen.patch | 30 patches/0315-Last-ditch-maximum-size-limit-for-Flip.patch | 41 + patches/0316-Last-ditch-grid-size-limit-for-Flood.patch | 30 patches/0317-Insist-that-Flood-grids-must-have-non-zero-size.patch | 21 patches/0318-Last-ditch-grid-size-limit-for-Inertia.patch | 30 patches/0319-Last-ditch-maximum-size-limit-for-Light-Up.patch | 31 patches/0320-Limit-maximum-grid-size-in-Loopy.patch | 373 ++++++++++ patches/0321-Last-ditch-maximum-size-limit-for-Magnets.patch | 31 patches/0322-Last-ditch-maximum-size-limit-for-Map.patch | 43 + patches/0323-Last-ditch-maximum-size-limit-for-Mines.patch | 43 + patches/0324-Also-check-for-tiny-grids-in-Mines.patch | 23 patches/0326-Last-ditch-maximum-size-limit-for-Net.patch | 31 patches/0327-Last-ditch-maximum-size-limit-for-Netslide.patch | 31 patches/0328-Integer-overflow-protection-in-Pattern.patch | 40 + patches/0329-Last-ditch-maximum-size-limit-for-Palisade.patch | 40 + patches/0330-Last-ditch-maximum-size-limit-for-Pearl.patch | 31 patches/0331-Last-ditch-maximum-size-limit-for-Pegs.patch | 42 + patches/0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch | 22 patches/0333-Last-ditch-maximum-size-limit-for-Same-Game.patch | 31 patches/0334-Last-ditch-maximum-size-limit-for-Signpost.patch | 31 patches/0335-Last-ditch-maximum-size-limit-for-Sixteen.patch | 31 patches/0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch | 30 patches/0337-Last-ditch-maximum-size-limit-for-Tracks.patch | 31 patches/0338-Last-ditch-maximum-size-limit-for-Twiddle.patch | 31 patches/0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch | 23 patches/0340-Last-ditch-point-count-limit-for-Untangle.patch | 31 patches/0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch | 28 patches/0342-Palisade-don-t-leak-memory-on-a-bad-move.patch | 41 + patches/0343-Don-t-allow-negative-clues-in-Pattern.patch | 21 patches/0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch | 24 patches/0346-Palisade-remove-assertion-from-decode_ui.patch | 24 patches/0347-Same-Game-reject-moves-with-unexpected-characters-in.patch | 26 patches/0349-Filling-validate-length-of-auto-solve-move-strings.patch | 33 patches/0350-Tighten-Bridges-validate_desc.patch | 29 patches/0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch | 24 patches/0352-Mines-No-moving-once-you-re-dead.patch | 26 patches/0353-Towers-reject-descriptions-with-odd-characters-at-th.patch | 27 patches/0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch | 37 patches/0360-Tracks-let-solve-make-illegal-moves.patch | 44 + patches/0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch | 55 + patches/0362-Allow-repeated-solve-operations-in-Guess.patch | 37 patches/102_fix-pearl-min-dimensions.diff | 2 patches/fix-ftbfs-with-gcc-6.patch | 2 patches/series | 129 +++ 138 files changed, 6005 insertions(+), 8 deletions(-) diff -Nru sgt-puzzles-20191231.79a5378/debian/.gitignore sgt-puzzles-20191231.79a5378/debian/.gitignore --- sgt-puzzles-20191231.79a5378/debian/.gitignore 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -*~ -.#* -/*.debhelper* -/*.substvars -/files -/sgt-puzzles/ diff -Nru sgt-puzzles-20191231.79a5378/debian/changelog sgt-puzzles-20191231.79a5378/debian/changelog --- sgt-puzzles-20191231.79a5378/debian/changelog 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/changelog 2023-04-30 15:35:04.000000000 +0000 @@ -1,3 +1,139 @@ +sgt-puzzles (20191231.79a5378-3+deb11u1) bullseye; urgency=medium + + * Fix various security issues in game loading (Closes: #1028986, #1034190): + - Mines: add validation for negative mine count. + - Galaxies: fix assertion failure when adding out-of-bounds association. + - Filling: fix assertion failure in 3x1 game generation. + - Map: add missing sresize in new_game_desc(). + - Add more validation to midend deserialisation routine + - Correct and enable the range check on statepos when loading + - Add an assertion to check the format of encoded parameters + - Add assertions that game descriptions consist only of printable ASCII. + - Hex-encode non-ASCII random seeds in save files + - Assert that everything written to a save file is printable ASCII + - Build fix: take declarations out of for loops. + - galaxies: Use the same code for handling all dropped arrows + - magnets: Area constraints; fix message. + - lightup: Ban 2x2 with either 4-way type + - Remove _() introduced from Android port. + - Solo: Set max difficulty for small jigsaw puzzles + - Add a macro of an upper bound on the formatted length of an integer + - Guess: Don't allow any moves once the game is solved (CVE-2023-24283) + - Guess: validate peg colours in decode_ui() (CVE-2023-24284) + - Netslide: Reject moves wider than the grid (CVE-2023-24285) + - Sixteen: limit length of moves + - Undead: check for valid commands in execute_move() + - Undead: fix buffer overrun in "M" command (CVE-2023-24287) + - Correct RANGECHECK macro in Black Box + - Range-check normal moves in Undead + - Range-check record lengths when deserialising games (CVE-2023-24291) + - Don't load too many states just because there's no STATEPOS + (CVE-2023-24288) + - Palisade: forbid moves that remove grid edges + - Last-ditch maximum size limit for Bridges + - Last-ditch grid-size limit for Dominosa + - Last-ditch grid-size limit for Galaxies + - Last-ditch grid-size limit for Fifteen + - Last-ditch maximum size limit for Flip + - Last-ditch grid-size limit for Flood + - Insist that Flood grids must have non-zero size + - Last-ditch grid-size limit for Inertia + - Last-ditch maximum size limit for Light Up + - Limit maximum grid size in Loopy + - Last-ditch maximum size limit for Magnets + - Last-ditch maximum size limit for Map + - Last-ditch maximum size limit for Mines + - Also check for tiny grids in Mines + - Last-ditch maximum size limit for Net + - Last-ditch maximum size limit for Netslide + - Integer overflow protection in Pattern + - Last-ditch maximum size limit for Palisade + - Last-ditch maximum size limit for Pearl + - Last-ditch maximum size limit for Pegs + - Also limit Pegs to at least 1x1 even when not doing full validation + - Last-ditch maximum size limit for Same Game + - Last-ditch maximum size limit for Signpost + - Last-ditch maximum size limit for Sixteen + - Limit size of puzzle in Tents to avoid integer overflow + - Last-ditch maximum size limit for Tracks + - Last-ditch maximum size limit for Twiddle + - Adjust Undead upper grid-size limit to avoid overflow + - Last-ditch point-count limit for Untangle + - Black Box: correct order of validation checks for "F" commands + - Palisade: don't leak memory on a bad move + - Don't allow negative clues in Pattern + - When loading, don't decode_ui unless we have a UI + - Palisade: remove assertion from decode_ui() + - Same Game: reject moves with unexpected characters in + - Filling: validate length of auto-solve move strings + - Tighten Bridges' validate_desc() + - Untangle: forbid descriptions that connect a node to itself + - Mines: No moving once you're dead! + - Towers: reject descriptions with odd characters at the end + - Tracks: make sure moves are valid in execute_move() + - Tracks: let solve make illegal moves + - Tracks: tighten up the 'illegal solve submoves' fix. + - Allow repeated "solve" operations in Guess + - Black Box: reject negative ball counts in game_params. + - Add validate_params bounds checks in a few more games. + - Don't allow Bridges games with < 2 islands + - Forbid moves that fill with the current colour in Flood + - Cleanly reject ill-formed solve moves in Flood + - Don't segfault on premature solve moves in Mines + - Limit number of mines in Mines game description + - Validate the number of pegs and holes in a Pegs game ID + - Mines: forbid moves that flag or unflag an exposed square + - Mines: Don't check if the player has won if they've already lost + - Avoid invalid moves when solving Tracks + - Fix move validation in Netslide + - Tighten validation of Tents game descriptions + - Dominosa: require the two halves of a domino to be adjacent + - Forbid lines off the grid in Pearl + - Tolerate incorrect solutions in Inertia + - Palisade: replace dfs_dsf() with a simple iteration. + - latin_solver_alloc: handle clashing numbers in input grid. + - Pearl: fix assertion failure on bad puzzle. + - Pearl: fix bounds check in previous commit. + - Unequal: Don't insist that solve moves must actually solve + - Range: Don't fail an assertion on an all-black board + - Limit width and height to SHRT_MAX in Mines + - Mines: Add assertions to range-check conversions to short + - Unequal: fix sense error in latin_solver_alloc fix. + - Forbid impossible moves in Bridges + - Forbid game descriptions with joined islands in Bridges + - Check state is valid at the end of a move in Pearl + - Cleanly reject more ill-formed solve moves in Flood + - Don't allow moves that change the constraints in Unequal + - Fix memory leaks in Keen's validate_desc() + - Don't leak grids in Loopy's validate_desc() + - Remember to free the to_draw member from Net's drawstate + - Undead: check the return value of sscanf() in execute_move() + - Don't leak duplicate edges in Untangle + - Remember to free the numcolours array from Pattern's drawstate + - Twiddle: don't read off the end of parameter strings ending 'm' + - Loopy: free the grid description string if it's invalid + - Avoid division by zero in Cube grid-size checks + - Validate that save file values are ASCII (mostly) + - More validation of solve moves in Flood + - Make sure that moves in Flood use only valid colours + - Tighten grid-size limit in Mines + - Tracks: set drag_s{x,y} even if starting off-grid + - Undead: be a bit more careful about sprintf buffer sizes + - Fix memory leak in midend_game_id_int() + - Flood: don't read off the end of some parameter strings + - Be more careful with type of left operand of << + - Map: reduce maximum size + - Correctly handle some short save files + - Inertia: insist that solutions must be non-empty + - Galaxies: fix recursion depth limit in solver. + - Correct a range check in Magnets' layout verification + - Magnets: add a check that magnets don't wrap between lines + - Net: assert that cx and cy are in range in compute_active() + - Don't allow zero clues in Pattern + * Solo: cope with pencil marks when tilesize == 1 (Closes: #905852) + + -- Ben Hutchings Sun, 30 Apr 2023 17:35:04 +0200 + sgt-puzzles (20191231.79a5378-3) unstable; urgency=medium * Update German translation, thanks to Helge Kreutzmann diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0001-Black-Box-reject-negative-ball-counts-in-game_params.patch sgt-puzzles-20191231.79a5378/debian/patches/0001-Black-Box-reject-negative-ball-counts-in-game_params.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0001-Black-Box-reject-negative-ball-counts-in-game_params.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0001-Black-Box-reject-negative-ball-counts-in-game_params.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,34 @@ +From: Simon Tatham +Date: Sun, 22 Jan 2023 08:54:06 +0000 +Subject: [PATCH 001/159] Black Box: reject negative ball counts in + game_params. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5cac6a09c4db2b7e05c3e8dfd8920e2cdd1b8b03 +Bug-Debian: https://bugs.debian.org/1034190 + +You can inject one via a game desc string such as "10x10M5m-1", and +it's clearly silly. + +_Zero_ balls, on the other hand, are a perfectly fine number: there's +nothing incoherent about a BB puzzle in which the possible numbers of +balls vary from (say) 0 to 5 inclusive, so that part of the challenge +is to work out as efficiently as possible whether there are even any +balls at all. + +(We only need to check minballs, because once we know minballs >= 0, +the subsequent check ensures that maxballs >= minballs, and hence, by +transitivity, maxballs >= 0 too.) +--- + blackbox.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/blackbox.c ++++ b/blackbox.c +@@ -192,6 +192,8 @@ static const char *validate_params(const + * types, and could be worked around if required. */ + if (params->w > 255 || params->h > 255) + return "Widths and heights greater than 255 are not supported"; ++ if (params->minballs < 0) ++ return "Negative number of balls"; + if (params->minballs > params->maxballs) + return "Minimum number of balls may not be greater than maximum"; + if (params->minballs >= params->w * params->h) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch sgt-puzzles-20191231.79a5378/debian/patches/0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,125 @@ +From: Simon Tatham +Date: Sun, 22 Jan 2023 09:30:57 +0000 +Subject: [PATCH 002/159] Add validate_params bounds checks in a few more + games. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b907e278751b740da7b9dc00c0cbdb93e7498919 +Bug-Debian: https://bugs.debian.org/1034190 + +Ben tells me that his recent work in this area was entirely driven by +fuzzing: he added bounds checks in validate_params when the fuzzer had +managed to prove that the lack of them allowed something buggy to +happen. + +It seemed worth doing an eyeball-review pass to complement that +strategy, so in this commit I've gone through and added a few more +checks that restrict the area of the grid to be less than INT_MAX. + +Notable in this commit: cube.c had to do something complicated because +in the triangular-grid modes the area isn't calculated as easily as +w*h, and Range's existing check that w+h-1 < SCHAR_MAX is sufficient +to rule out w*h being overlarge _but_ should be done before w*h is +ever computed. +--- + cube.c | 24 ++++++++++++++++++++++++ + filling.c | 2 ++ + range.c | 2 +- + rect.c | 2 ++ + slant.c | 2 ++ + unruly.c | 2 ++ + 6 files changed, 33 insertions(+), 1 deletion(-) + +--- a/cube.c ++++ b/cube.c +@@ -542,12 +542,36 @@ static const char *validate_params(const + if (params->solid < 0 || params->solid >= lenof(solids)) + return "Unrecognised solid type"; + ++ if (params->d1 < 0 || params->d2 < 0) ++ return "Grid dimensions may not be negative"; ++ + if (solids[params->solid]->order == 4) { + if (params->d1 <= 1 || params->d2 <= 1) + return "Both grid dimensions must be greater than one"; ++ if (params->d2 > INT_MAX / params->d1) ++ return "Grid area must not be unreasonably large"; + } else { + if (params->d1 <= 0 && params->d2 <= 0) + return "At least one grid dimension must be greater than zero"; ++ ++ /* ++ * Check whether d1^2 + d2^2 + 4 d1 d2 > INT_MAX, without overflow: ++ * ++ * First check d1^2 doesn't overflow by itself. ++ * ++ * Then check d2^2 doesn't exceed the remaining space between ++ * d1^2 and INT_MAX. ++ * ++ * If that's all OK then we know both d1 and d2 are ++ * individually less than the square root of INT_MAX, so we ++ * can safely multiply them and compare against the ++ * _remaining_ space. ++ */ ++ if ((params->d1 > INT_MAX / params->d1) || ++ (params->d2 > (INT_MAX - params->d1*params->d1) / params->d2) || ++ (params->d1*params->d2 > (INT_MAX - params->d1*params->d1 - ++ params->d2*params->d2) / params->d2)) ++ return "Grid area must not be unreasonably large"; + } + + for (i = 0; i < 4; i++) +--- a/filling.c ++++ b/filling.c +@@ -188,6 +188,8 @@ static const char *validate_params(const + { + if (params->w < 1) return "Width must be at least one"; + if (params->h < 1) return "Height must be at least one"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + return NULL; + } +--- a/range.c ++++ b/range.c +@@ -911,8 +911,8 @@ static const char *validate_params(const + int const w = params->w, h = params->h; + if (w < 1) return "Error: width is less than 1"; + if (h < 1) return "Error: height is less than 1"; ++ if (w > SCHAR_MAX - (h - 1)) return "Error: w + h is too big"; + if (w * h < 1) return "Error: size is less than 1"; +- if (w + h - 1 > SCHAR_MAX) return "Error: w + h is too big"; + /* I might be unable to store clues in my puzzle_size *grid; */ + if (full) { + if (w == 2 && h == 2) return "Error: can't create 2x2 puzzles"; +--- a/rect.c ++++ b/rect.c +@@ -218,6 +218,8 @@ static const char *validate_params(const + { + if (params->w <= 0 || params->h <= 0) + return "Width and height must both be greater than zero"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->w*params->h < 2) + return "Grid area must be greater than one"; + if (params->expandfactor < 0.0F) +--- a/slant.c ++++ b/slant.c +@@ -226,6 +226,8 @@ static const char *validate_params(const + + if (params->w < 2 || params->h < 2) + return "Width and height must both be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + return NULL; + } +--- a/unruly.c ++++ b/unruly.c +@@ -284,6 +284,8 @@ static const char *validate_params(const + return "Width and height must both be even"; + if (params->w2 < 6 || params->h2 < 6) + return "Width and height must be at least 6"; ++ if (params->w2 > INT_MAX / params->h2) ++ return "Width times height must not be unreasonably large"; + if (params->unique) { + static const long A177790[] = { + /* diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0004-Makefile.doc-Remove-CHM-files-in-clean-rule.patch sgt-puzzles-20191231.79a5378/debian/patches/0004-Makefile.doc-Remove-CHM-files-in-clean-rule.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0004-Makefile.doc-Remove-CHM-files-in-clean-rule.patch 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0004-Makefile.doc-Remove-CHM-files-in-clean-rule.patch 2023-04-23 19:12:52.000000000 +0000 @@ -1,6 +1,7 @@ From: Ben Hutchings Date: Fri, 10 Aug 2018 09:05:43 +0100 Subject: Makefile.doc: Remove CHM files in clean rule +Applied-Upstream: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=f0f974055b7f8ee91bae6505aad166923ec7117f --- Makefile.doc | 2 +- diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0006-Don-t-allow-Bridges-games-with-2-islands.patch sgt-puzzles-20191231.79a5378/debian/patches/0006-Don-t-allow-Bridges-games-with-2-islands.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0006-Don-t-allow-Bridges-games-with-2-islands.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0006-Don-t-allow-Bridges-games-with-2-islands.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,56 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 00:45:38 +0000 +Subject: [PATCH 006/159] Don't allow Bridges games with < 2 islands +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=a98ac4bb428ab5c1ff665aa1def6cc14d02a4e19 +Bug-Debian: https://bugs.debian.org/1034190 + +Technically, a game with no islands is always solved, but it causes a +null-pointer dereference at startup because there's nowhere to put the +cursor. Games with one island are always insoluble because the island +must have at least one bridge and there's nowhere for it to go. So +the minimum playable game has two islands. + +To demonstrate the segfault, try loading this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :7:Bridges +PARAMS :1:3 +CPARAMS :1:3 +DESC :1:i +NSTATES :1:1 +STATEPOS:1:1 +--- + bridges.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/bridges.c ++++ b/bridges.c +@@ -2007,15 +2007,15 @@ generated: + + static const char *validate_desc(const game_params *params, const char *desc) + { +- int i, wh = params->w * params->h; ++ int i, wh = params->w * params->h, nislands = 0; + + for (i = 0; i < wh; i++) { + if (*desc >= '1' && *desc <= '9') +- /* OK */; ++ nislands++; + else if (*desc >= 'a' && *desc <= 'z') + i += *desc - 'a'; /* plus the i++ */ + else if (*desc >= 'A' && *desc <= 'G') +- /* OK */; ++ nislands++; + else if (!*desc) + return "Game description shorter than expected"; + else +@@ -2024,6 +2024,8 @@ static const char *validate_desc(const g + } + if (*desc || i > wh) + return "Game description longer than expected"; ++ if (nislands < 2) ++ return "Game description has too few islands"; + + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch sgt-puzzles-20191231.79a5378/debian/patches/0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,36 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 18:49:47 +0000 +Subject: [PATCH 007/159] Forbid moves that fill with the current colour in + Flood +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=eb1ae3f3d041f9ff0c11b04613a695be11bda706 +Bug-Debian: https://bugs.debian.org/1034190 + +This avoids an assertion failure, "oldcolour != newcolour" in fill(), +by catching it it execute_move(). As far as I know this couldn't be +triggered from the UI, but it could be demonstrated with this save +file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Flood +PARAMS :1:3 +CPARAMS :1:3 +DESC :12:231353400,11 +NSTATES :1:3 +STATEPOS:1:3 +MOVE :2:M3 +MOVE :2:M3 +--- + flood.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/flood.c ++++ b/flood.c +@@ -873,6 +873,7 @@ static game_state *execute_move(const ga + if (move[0] == 'M' && + sscanf(move+1, "%d", &c) == 1 && + c >= 0 && ++ c != state->grid[FILLY * state->w + FILLX] && + !state->complete) { + int *queue = snewn(state->w * state->h, int); + ret = dup_game(state); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0007-Mines-add-validation-for-negative-mine-count.patch sgt-puzzles-20191231.79a5378/debian/patches/0007-Mines-add-validation-for-negative-mine-count.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0007-Mines-add-validation-for-negative-mine-count.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0007-Mines-add-validation-for-negative-mine-count.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,22 @@ +From: Simon Tatham +Date: Tue, 17 Mar 2020 18:12:33 +0000 +Subject: [PATCH 007/389] Mines: add validation for negative mine count. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d71ac73d8a4397c35b21ec08388a1c6f94691b64 + +If this gets through validation, it causes an infinite loop after +gameplay begins. +--- + mines.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -258,6 +258,8 @@ static const char *validate_params(const + */ + if (full && params->unique && (params->w <= 2 || params->h <= 2)) + return "Width and height must both be greater than two"; ++ if (params->n < 0) ++ return "Mine count may not be negative"; + if (params->n > params->w * params->h - 9) + return "Too many mines for grid size"; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch sgt-puzzles-20191231.79a5378/debian/patches/0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,41 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 19:06:24 +0000 +Subject: [PATCH 008/159] Cleanly reject ill-formed solve moves in Flood +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e4112b322e299a461ddc46daee741c73733e186d +Bug-Debian: https://bugs.debian.org/1034190 + +A solve move containing characters other than digits and commas would +cause an assertion failure, "*p == ','", in execute_move(). Such a move +can't as far as I know be generated in play, but can be read from a +corrupt save file. + +Here's a sample of such a save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Flood +PARAMS :7:3x3c6m5 +CPARAMS :7:3x3c6m5 +DESC :12:403011503,10 +NSTATES :1:2 +STATEPOS:1:2 +SOLVE :2:SA +--- + flood.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/flood.c ++++ b/flood.c +@@ -928,7 +928,11 @@ static game_state *execute_move(const ga + sol->moves[i] = atoi(p); + p += strspn(p, "0123456789"); + if (*p) { +- assert(*p == ','); ++ if (*p != ',') { ++ sfree(sol->moves); ++ sfree(sol); ++ return NULL; ++ } + p++; + } + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch sgt-puzzles-20191231.79a5378/debian/patches/0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,38 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 19:34:28 +0000 +Subject: [PATCH 009/159] Don't segfault on premature solve moves in Mines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=28671e76b736aeb860b1f725898c45fe70ae6212 +Bug-Debian: https://bugs.debian.org/1034190 + +If a save file contained a solve move as the first move, Mines would +dereference a null pointer trying to look up the (at that point +undetermined) mine locations. Now execute_move() politely returns +NULL instead. + +This save file demonstrates the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Mines +PARAMS :5:3x3n0 +CPARAMS :5:3x3n0 +DESC :127:r0,u,7a142789cabddc3fc4dcb7d2baa4a4937b33c9613ea870ac098e217981ad339930af585557d62048ea745d05b01475d9699596b394cc0adeebf0440a02 +UI :2:D0 +TIME :1:0 +NSTATES :1:2 +STATEPOS:1:2 +SOLVE :1:S +--- + mines.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mines.c ++++ b/mines.c +@@ -2608,6 +2608,7 @@ static game_state *execute_move(const ga + if (!strcmp(move, "S")) { + int yy, xx; + ++ if (!from->layout->mines) return NULL; /* Game not started. */ + ret = dup_game(from); + if (!ret->dead) { + /* diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0010-Limit-number-of-mines-in-Mines-game-description.patch sgt-puzzles-20191231.79a5378/debian/patches/0010-Limit-number-of-mines-in-Mines-game-description.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0010-Limit-number-of-mines-in-Mines-game-description.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0010-Limit-number-of-mines-in-Mines-game-description.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,26 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 23:12:52 +0000 +Subject: [PATCH 010/159] Limit number of mines in Mines game description +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=75e8a1a9cabe7567f6019b1226783b61ba1ac42f +Bug-Debian: https://bugs.debian.org/1034190 + +Without this, it's possible to specify a description that has more +mines than there are places on the board to place them, which +eventually leads to a division by zero. This can be demonstrated by +entering a game description of "3:r8,u," and then clicking anywhere on +the board. +--- + mines.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -2006,6 +2006,8 @@ static const char *validate_desc(const g + desc++; + if (!*desc || !isdigit((unsigned char)*desc)) + return "No initial mine count in game description"; ++ if (atoi(desc) > wh - 9) ++ return "Too many mines for grid size"; + while (*desc && isdigit((unsigned char)*desc)) + desc++; /* skip over mine count */ + if (*desc != ',') diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch sgt-puzzles-20191231.79a5378/debian/patches/0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,42 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 23:45:48 +0000 +Subject: [PATCH 011/159] Validate the number of pegs and holes in a Pegs game + ID +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=4359f59dd22770a94e29b2ddd54b533ad1713550 +Bug-Debian: https://bugs.debian.org/1034190 + +Without this, "1:O" causes an assertion violation, '!"new_ui found +nowhere for cursor"'. We may as well require two pegs and one hole, +since that's the minimum for a game in which there are any moves to +make. +--- + pegs.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/pegs.c ++++ b/pegs.c +@@ -663,7 +663,7 @@ static char *new_game_desc(const game_pa + + static const char *validate_desc(const game_params *params, const char *desc) + { +- int len; ++ int len, i, npeg = 0, nhole = 0; + + len = params->w * params->h; + +@@ -671,6 +671,15 @@ static const char *validate_desc(const g + return "Game description is wrong length"; + if (len != strspn(desc, "PHO")) + return "Invalid character in game description"; ++ for (i = 0; i < len; i++) { ++ npeg += desc[i] == 'P'; ++ nhole += desc[i] == 'H'; ++ } ++ /* The minimal soluble game has two pegs and a hole: "3x1:PPH". */ ++ if (npeg < 2) ++ return "Too few pegs in game description"; ++ if (nhole < 1) ++ return "Too few holes in game description"; + + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0012-unruly-Fix-memory-leak-in-dup_game.patch sgt-puzzles-20191231.79a5378/debian/patches/0012-unruly-Fix-memory-leak-in-dup_game.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0012-unruly-Fix-memory-leak-in-dup_game.patch 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0012-unruly-Fix-memory-leak-in-dup_game.patch 2023-04-23 19:12:52.000000000 +0000 @@ -1,6 +1,7 @@ From: Ben Hutchings Date: Sat, 17 Aug 2019 17:33:54 +0100 Subject: unruly: Fix memory leak in dup_game() +Applied-Upstream: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=cd338a1a35394a7abfd517569e908b54bf657aaa The common structure is ref-counted and dup_game() bumps the reference count rather than copying it. However, blank_state() always allocates diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0013-bridges-Fix-off-by-one-in-WITHIN.patch sgt-puzzles-20191231.79a5378/debian/patches/0013-bridges-Fix-off-by-one-in-WITHIN.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0013-bridges-Fix-off-by-one-in-WITHIN.patch 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0013-bridges-Fix-off-by-one-in-WITHIN.patch 2023-04-23 19:12:52.000000000 +0000 @@ -1,6 +1,7 @@ From: Ben Hutchings Date: Sat, 17 Aug 2019 17:36:51 +0100 Subject: bridges: Fix off-by-one in WITHIN() +Applied-Upstream: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=4c1e47b272274972556d7790384998e593d0ae57 WITHIN() used to treat the min and max as inclusive bounds but was changed to treat the max as exclusive, apparently accidentally. diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch sgt-puzzles-20191231.79a5378/debian/patches/0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch 2023-04-23 19:12:52.000000000 +0000 @@ -5,6 +5,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit +Forwarded: not-needed Building with gcc 9 and _FORTIFY_SOURCE=2 (the default on Debian) fails for some architectures, with error messages such as: diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch sgt-puzzles-20191231.79a5378/debian/patches/0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,28 @@ +From: Ben Harris +Date: Wed, 1 Feb 2023 17:07:12 +0000 +Subject: [PATCH 017/159] Mines: forbid moves that flag or unflag an exposed + square +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=17364455186ae61e015d0f0de3f09423f78d0727 +Bug-Debian: https://bugs.debian.org/1034190 + +interpret_move() couldn't generate them, but execute_move() also needs +to forbid them to defend against corrupt save files. I don't think this +actually caused any crashes, but it did cause unexpected "1" squares not +adjacent to mines. +--- + mines.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/mines.c ++++ b/mines.c +@@ -2672,7 +2672,9 @@ static game_state *execute_move(const ga + while (*move) { + if (move[0] == 'F' && + sscanf(move+1, "%d,%d", &cx, &cy) == 2 && +- cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) { ++ cx >= 0 && cx < from->w && cy >= 0 && cy < from->h && ++ (ret->grid[cy * from->w + cx] == -1 || ++ ret->grid[cy * from->w + cx] == -2)) { + ret->grid[cy * from->w + cx] ^= (-2 ^ -1); + } else if (move[0] == 'O' && + sscanf(move+1, "%d,%d", &cx, &cy) == 2 && diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch sgt-puzzles-20191231.79a5378/debian/patches/0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,42 @@ +From: Ben Harris +Date: Wed, 1 Feb 2023 20:12:29 +0000 +Subject: [PATCH 018/159] Mines: Don't check if the player has won if they've + already lost +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=2a9be2b89df3e6a07a1d90a06f8ac00a92d789e5 +Bug-Debian: https://bugs.debian.org/1034190 + +It can't happen in normal play, but if a save file had a "C" (clear +around) move that set off a mine, Mines could end up hitting an +assertion failure, "ncovered >= nmines". This was because it would +check if the player had won by counting covered squares and mines, and +of course an uncovered mine is no longer a covered square but is still a +mine. + +Since winning after you're dead isn't possible (at least in Mines), we +now skip the check entirely if the player has already died. + +This save file demonstrates the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :5:Mines +PARAMS :1:7 +CPARAMS :1:7 +DESC :22:r31,u,0000C000d0000020 +NSTATES :1:2 +STATEPOS:1:1 +MOVE :4:C6,2 +--- + mines.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -2146,6 +2146,8 @@ static int open_square(game_state *state + break; + } + ++ /* If the player has already lost, don't let them win as well. */ ++ if (state->dead) return 0; + /* + * Finally, scan the grid and see if exactly as many squares + * are still covered as there are mines. If so, set the `won' diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0019-Avoid-invalid-moves-when-solving-Tracks.patch sgt-puzzles-20191231.79a5378/debian/patches/0019-Avoid-invalid-moves-when-solving-Tracks.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0019-Avoid-invalid-moves-when-solving-Tracks.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0019-Avoid-invalid-moves-when-solving-Tracks.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,64 @@ +From: Ben Harris +Date: Wed, 1 Feb 2023 21:28:35 +0000 +Subject: [PATCH 019/159] Avoid invalid moves when solving Tracks +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=875f0af21fbced5cbf6cf63b86fe3dc51682c863 +Bug-Debian: https://bugs.debian.org/1034190 + +The solver, when it decided that an edge or square should be both TRACK +and NOTRACK, would correctly decide that the puzzle was insoluble, but +would also mark the edge with both flags in its working copy. This +could then lead to assertion violations if that working copy of the +board was used for something else, for instance if it was fed back into +the solver. This couldn't happen in normal play, since failed solutions +just cause the solve command to fail, but the diagnostic "H" command +could trigger it from a save file, causing an assertion failure: +"state->sflags[y*state->p.w + x] & S_CLUE". + +Now when the solver runs into this situation, it marks the puzzle as +insoluble but doesn't set the invalid flag, so the board remains valid +and future solve operations are safe. + +This save file is the one that demonstrated the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :12:Train Tracks +PARAMS :5:6x6t0 +CPARAMS :5:6x6t0 +DESC :31:b0t9l,,S0,00,0,0,4,0,0,S0,0,0,0 +NSTATES :1:8 +STATEPOS:1:2 +MOVE :1:H +MOVE :1:H +MOVE :1:H +MOVE :1:H +MOVE :1:H +MOVE :1:H +MOVE :1:H +--- + tracks.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/tracks.c ++++ b/tracks.c +@@ -897,8 +897,8 @@ static int solve_set_sflag(game_state *s + if (state->sflags[i] & (f == S_TRACK ? S_NOTRACK : S_TRACK)) { + debug(("solve: opposite flag already set there, marking IMPOSSIBLE")); + state->impossible = true; +- } +- state->sflags[i] |= f; ++ } else ++ state->sflags[i] |= f; + return 1; + } + +@@ -915,8 +915,8 @@ static int solve_set_eflag(game_state *s + if (sf & (f == E_TRACK ? E_NOTRACK : E_TRACK)) { + debug(("solve: opposite flag already set there, marking IMPOSSIBLE")); + state->impossible = true; +- } +- S_E_SET(state, x, y, d, f); ++ } else ++ S_E_SET(state, x, y, d, f); + return 1; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0020-Fix-move-validation-in-Netslide.patch sgt-puzzles-20191231.79a5378/debian/patches/0020-Fix-move-validation-in-Netslide.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0020-Fix-move-validation-in-Netslide.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0020-Fix-move-validation-in-Netslide.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,40 @@ +From: Ben Harris +Date: Wed, 1 Feb 2023 23:00:14 +0000 +Subject: [PATCH 020/159] Fix move validation in Netslide +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ed0e4c304bed990948541fc0cf87309d75653806 +Bug-Debian: https://bugs.debian.org/1034190 + +The maximum length of a column move in Netslide is the height of the +puzzle, and the maximum length of a row move is the width, not the +other way around. + +Moves of absolute length more than 1 can't be generated by +interpret_move(), but they can come from save files. On non-square +grids, the incorrect check led to assertion failures: "0 <= tx && tx < +w" and "0 <= ty && ty < h". This save file demonstrates the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :8:Netslide +PARAMS :3:4x9 +CPARAMS :3:4x9 +DESC :39:0000000000000h0h0000000000000000000000v +NSTATES :1:2 +STATEPOS:1:2 +MOVE :4:R0,5 +--- + netslide.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/netslide.c ++++ b/netslide.c +@@ -1139,8 +1139,8 @@ static game_state *execute_move(const ga + if ((move[0] == 'C' || move[0] == 'R') && + sscanf(move+1, "%d,%d", &c, &d) == 2 && + c >= 0 && c < (move[0] == 'C' ? from->width : from->height) && +- d <= (move[0] == 'C' ? from->width : from->height) && +- d >= -(move[0] == 'C' ? from->width : from->height) && d != 0) { ++ d <= (move[0] == 'C' ? from->height : from->width) && ++ d >= -(move[0] == 'C' ? from->height : from->width) && d != 0) { + col = (move[0] == 'C'); + } else if (move[0] == 'S' && + strlen(move) == from->width * from->height + 1) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0021-Tighten-validation-of-Tents-game-descriptions.patch sgt-puzzles-20191231.79a5378/debian/patches/0021-Tighten-validation-of-Tents-game-descriptions.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0021-Tighten-validation-of-Tents-game-descriptions.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0021-Tighten-validation-of-Tents-game-descriptions.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,55 @@ +From: Ben Harris +Date: Thu, 2 Feb 2023 21:58:10 +0000 +Subject: [PATCH 021/159] Tighten validation of Tents game descriptions +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ed682bd5c608156d12ebaa2d84c4ce2e2877c10a +Bug-Debian: https://bugs.debian.org/1034190 + +Specifically, TENT and NONTENT markers ('!' and '-') cannot appear as +the first or last character of a description, because that would +attempt to place them on squares outside the grid. This was caught by +assertions in new_game(), as can be demonstrated by feeding these +descriptions to older versions of Tents: "4:-p,0,0,0,0,0,0,0,0" +("new_game: Assertion `i >= 0 && i <= w*h' failed.") and +4:p-,0,0,0,0,0,0,0,0 ("new_game: Assertion `*desc == ','' failed."). +--- + tents.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +--- a/tents.c ++++ b/tents.c +@@ -1191,6 +1191,21 @@ static char *new_game_desc(const game_pa + return ret; + } + ++/* ++ * Grid description format: ++ * ++ * _ = tree ++ * a = 1 BLANK then TREE ++ * ... ++ * y = 25 BLANKs then TREE ++ * z = 25 BLANKs ++ * ! = set previous square to TENT ++ * - = set previous square to NONTENT ++ * ++ * Last character must be one that would insert a tree as the first ++ * square after the grid. ++ */ ++ + static const char *validate_desc(const game_params *params, const char *desc) + { + int w = params->w, h = params->h; +@@ -1204,9 +1219,10 @@ static const char *validate_desc(const g + area += *desc - 'a' + 2; + else if (*desc == 'z') + area += 25; +- else if (*desc == '!' || *desc == '-') +- /* do nothing */; +- else ++ else if (*desc == '!' || *desc == '-') { ++ if (area == 0 || area > w * h) ++ return "Tent or non-tent placed off the grid"; ++ } else + return "Invalid character in grid specification"; + + desc++; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch sgt-puzzles-20191231.79a5378/debian/patches/0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,49 @@ +From: Ben Harris +Date: Thu, 2 Feb 2023 22:26:24 +0000 +Subject: [PATCH 022/159] Dominosa: require the two halves of a domino to be + adjacent +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=294a3ac6e703c2820ceb7b28a1a5492b61e9a531 +Bug-Debian: https://bugs.debian.org/1034190 + +Also that a line indicating no domino be between adjacent squares. +Without this, execute_move would allow you to place dominos and edges +between any pair ot squares, and then generate assertion failures +("execute_move: Assertion `d2 - w >= 0' failed." and "execute_move: +Assertion `d1 - w >= 0' failed.") when a domino was placed over an +invalid edge. This example save file demonstrates the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :8:Dominosa +PARAMS :1:6 +CPARAMS :1:6 +DESC :56:55521461210004364611033535444421636022603153156422620503 +NSTATES :1:3 +STATEPOS:1:3 +MOVE :4:E0,2 +MOVE :4:D0,2 +--- + dominosa.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/dominosa.c ++++ b/dominosa.c +@@ -2870,7 +2870,8 @@ static game_state *execute_move(const ga + move++; + } else if (move[0] == 'D' && + sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && +- d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2) { ++ d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 && ++ (d2 - d1 == 1 || d2 - d1 == w)) { + + /* + * Toggle domino presence between d1 and d2. +@@ -2938,7 +2939,8 @@ static game_state *execute_move(const ga + } else if (move[0] == 'E' && + sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && + d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 && +- ret->grid[d1] == d1 && ret->grid[d2] == d2) { ++ ret->grid[d1] == d1 && ret->grid[d2] == d2 && ++ (d2 - d1 == 1 || d2 - d1 == w)) { + + /* + * Toggle edge presence between d1 and d2. diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0023-Forbid-lines-off-the-grid-in-Pearl.patch sgt-puzzles-20191231.79a5378/debian/patches/0023-Forbid-lines-off-the-grid-in-Pearl.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0023-Forbid-lines-off-the-grid-in-Pearl.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0023-Forbid-lines-off-the-grid-in-Pearl.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,48 @@ +From: Ben Harris +Date: Thu, 2 Feb 2023 23:09:19 +0000 +Subject: [PATCH 023/159] Forbid lines off the grid in Pearl +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=15f4fa851a5781cf77984a6046405ffa758e7b33 +Bug-Debian: https://bugs.debian.org/1034190 + +While they couldn't be generated in normal play, execute_move() would +permit lines and marks across the edge of the grid that would then +generate assertion failures ("dsf_update_completion: Assertion +`INGRID(state, bx, by)' failed."). + +I've added a check to execute_move() that after updating a square, the +square doesn't have any lines or marks that leave the grid. + +This save file demonstrated the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSZON :1:1 +GAME :5:Pearl +PARAMS :5:5x6dt +CPARAMS :5:5x6dt +DESC :6:eeeeee +NSTATES :1:2 +STATEPOS:1:1 +MOVE :6:F1,4,2 +--- + pearl.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/pearl.c ++++ b/pearl.c +@@ -2235,6 +2235,16 @@ static game_state *execute_move(const ga + (ret->marks[y*w + x] & (char)l)) + goto badmove; + ++ /* ++ * Similarly, if we've ended up with a line or mark going ++ * off the board, that's not acceptable. ++ */ ++ for (l = 1; l <= 8; l <<= 1) ++ if (((ret->lines[y*w + x] & (char)l) || ++ (ret->marks[y*w + x] & (char)l)) && ++ !INGRID(state, x+DX(l), y+DY(l))) ++ goto badmove; ++ + move += n; + } else if (strcmp(move, "H") == 0) { + pearl_solve(ret->shared->w, ret->shared->h, diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch sgt-puzzles-20191231.79a5378/debian/patches/0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,40 @@ +From: Franklin Wei +Date: Sun, 5 Jul 2020 19:32:26 -0400 +Subject: [PATCH 023/389] Galaxies: fix assertion failure when adding + out-of-bounds association. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=84cb4c6701e027090ff3fd955ce08065e20121b2 + +Adding an association with an out-of-bounds square (i.e. by pressing Return +with a dot selected, and then moving the cursor so the `opposite' arrow was +off the screen) would cause space_opposite_dot() to return NULL, in turn +causing ok_to_add_assoc_with_opposite_internal() to return false, failing +the assertion. + +This assertion appears to have been introduced in 68363231. +--- + galaxies.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/galaxies.c ++++ b/galaxies.c +@@ -382,12 +382,15 @@ static bool ok_to_add_assoc_with_opposit + static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) { + space *opposite = space_opposite_dot(state, tile, dot); + +- assert(ok_to_add_assoc_with_opposite_internal(state, tile, opposite)); ++ if(opposite) ++ { ++ assert(ok_to_add_assoc_with_opposite_internal(state, tile, opposite)); + +- remove_assoc_with_opposite(state, tile); +- add_assoc(state, tile, dot); +- remove_assoc_with_opposite(state, opposite); +- add_assoc(state, opposite, dot); ++ remove_assoc_with_opposite(state, tile); ++ add_assoc(state, tile, dot); ++ remove_assoc_with_opposite(state, opposite); ++ add_assoc(state, opposite, dot); ++ } + } + + static space *sp2dot(const game_state *state, int x, int y) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0024-Tolerate-incorrect-solutions-in-Inertia.patch sgt-puzzles-20191231.79a5378/debian/patches/0024-Tolerate-incorrect-solutions-in-Inertia.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0024-Tolerate-incorrect-solutions-in-Inertia.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0024-Tolerate-incorrect-solutions-in-Inertia.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,50 @@ +From: Ben Harris +Date: Fri, 3 Feb 2023 20:52:05 +0000 +Subject: [PATCH 024/159] Tolerate incorrect solutions in Inertia +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=843d4ca17def11671809786f2a5aebd75f230dd9 +Bug-Debian: https://bugs.debian.org/1034190 + +The "solve" operation in Inertia generates a proposed solution as a +move string. But if such a move string is loaded from a save file it +might not actually describe a solution. If that happens then it's +possible to reach the end of the "solution" without winning, and doing +so should probably cause a recalculation of the solution rather than +an assertion failure ("execute_move: Assertion `ret->solnpos < +ret->soln->len' failed."). + +I am a little concerned by the way that normal solve operations end up +encoded in the save file, but the re-solvings caused by going off +course don't, but I haven't got a good answer to that. + +Here's a save file that demonstrates the assertion failure: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :7:Inertia +PARAMS :3:8x8 +CPARAMS :3:8x8 +DESC :64:sbgwsmswwgggwggmmbwgwbssbwbsbwbbwsSmwbbsbbmggbmssgmgwbmmwmbmmwsw +NSTATES :2:3 +STATEPOS:1:1 +MOVE 000:2:S0 +MOVE 000:2:00 +--- + inertia.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/inertia.c ++++ b/inertia.c +@@ -1732,11 +1732,10 @@ static game_state *execute_move(const ga + if (ret->soln) { + if (ret->dead || ret->gems == 0) + discard_solution(ret); +- else if (ret->soln->list[ret->solnpos] == dir) { ++ else if (ret->soln->list[ret->solnpos] == dir && ++ ret->solnpos+1 < ret->soln->len) + ++ret->solnpos; +- assert(ret->solnpos < ret->soln->len); /* or gems == 0 */ +- assert(!ret->dead); /* or not a solution */ +- } else { ++ else { + const char *error = NULL; + char *soln = solve_game(NULL, ret, NULL, &error); + if (!error) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch sgt-puzzles-20191231.79a5378/debian/patches/0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,109 @@ +From: Simon Tatham +Date: Fri, 3 Feb 2023 23:12:38 +0000 +Subject: [PATCH 025/159] Palisade: replace dfs_dsf() with a simple iteration. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=517b14e666b0b71fc0bcd5da1b22cdc90d3434c9 +Bug-Debian: https://bugs.debian.org/1034190 + +The whole purpose of a dsf is that you can traverse the edges of your +graph in any order you feel like. So if you want to build the +connected components of a graph you can just loop over all the edges +once. There's no need to run a depth-first search. + +In fact there were an amazing number of things wrong with this 10-line +function: + + - As Ben points out in commit 21193eaf9308ace, it didn't bother with + bounds checking when searching the grid, instead relying on the + never-removed grid boundary to stop the search - which was fragile in + the face of other bugs. + + - The recursion uses linear stack, which is much worse than linear + heap, since stacks are often much more limited. (And the dsf _also_ + used linear heap.) + + - The recursion was completely unnecessary. + + - The function used internal knowledge about dsf.c in order to define + the value UNVISITED to match what would happen to work. + + - The name 'dfs_dsf' is totally confusing and almost impossible to + type! +--- + palisade.c | 36 ++++++++++++++++-------------------- + 1 file changed, 16 insertions(+), 20 deletions(-) + +--- a/palisade.c ++++ b/palisade.c +@@ -505,19 +505,20 @@ static bool solver_equivalent_edges(solv + return changed; + } + +-#define UNVISITED 6 +- + /* build connected components in `dsf', along the lines of `borders'. */ +-static void dfs_dsf(int i, int w, borderflag *border, int *dsf, bool black) ++static void build_dsf(int w, int h, borderflag *border, int *dsf, bool black) + { +- int dir; +- for (dir = 0; dir < 4; ++dir) { +- int ii = i + dx[dir] + w*dy[dir], bdir = BORDER(dir); +- if (black ? (border[i] & bdir) : !(border[i] & DISABLED(bdir))) +- continue; +- if (dsf[ii] != UNVISITED) continue; +- dsf_merge(dsf, i, ii); +- dfs_dsf(ii, w, border, dsf, black); ++ int x, y; ++ ++ for (y = 0; y < h; y++) { ++ for (x = 0; x < w; x++) { ++ if (x+1 < w && (black ? !(border[y*w+x] & BORDER_R) : ++ (border[y*w+x] & DISABLED(BORDER_R)))) ++ dsf_merge(dsf, y*w+x, y*w+(x+1)); ++ if (y+1 < h && (black ? !(border[y*w+x] & BORDER_D) : ++ (border[y*w+x] & DISABLED(BORDER_D)))) ++ dsf_merge(dsf, y*w+x, (y+1)*w+x); ++ } + } + } + +@@ -528,7 +529,7 @@ static bool is_solved(const game_params + int i, x, y; + int *dsf = snew_dsf(wh); + +- assert (dsf[0] == UNVISITED); /* check: UNVISITED and dsf.c match up */ ++ build_dsf(w, h, border, dsf, true); + + /* + * A game is solved if: +@@ -539,7 +540,6 @@ static bool is_solved(const game_params + * - the borders also satisfy the clue set + */ + for (i = 0; i < wh; ++i) { +- if (dsf[i] == UNVISITED) dfs_dsf(i, params->w, border, dsf, true); + if (dsf_size(dsf, i) != k) goto error; + if (clues[i] == EMPTY) continue; + if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error; +@@ -1177,7 +1177,7 @@ static void game_redraw(drawing *dr, gam + float animtime, float flashtime) + { + int w = state->shared->params.w, h = state->shared->params.h, wh = w*h; +- int r, c, i, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; ++ int r, c, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; + int *black_border_dsf = snew_dsf(wh), *yellow_border_dsf = snew_dsf(wh); + int k = state->shared->params.k; + +@@ -1199,12 +1199,8 @@ static void game_redraw(drawing *dr, gam + status_bar(dr, buf); + } + +- for (i = 0; i < wh; ++i) { +- if (black_border_dsf[i] == UNVISITED) +- dfs_dsf(i, w, state->borders, black_border_dsf, true); +- if (yellow_border_dsf[i] == UNVISITED) +- dfs_dsf(i, w, state->borders, yellow_border_dsf, false); +- } ++ build_dsf(w, h, state->borders, black_border_dsf, true); ++ build_dsf(w, h, state->borders, yellow_border_dsf, false); + + for (r = 0; r < h; ++r) + for (c = 0; c < w; ++c) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch sgt-puzzles-20191231.79a5378/debian/patches/0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,212 @@ +From: Simon Tatham +Date: Sun, 5 Feb 2023 10:29:42 +0000 +Subject: [PATCH 026/159] latin_solver_alloc: handle clashing numbers in input + grid. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5030d87903191d581586ecda2382ad5bcd70f63d +Bug-Debian: https://bugs.debian.org/1034190 + +In the setup phase of the centralised latin.c solver, we start by +going over the input grid containing already-placed clue numbers, and +calling latin_solver_place to enter each on into the solver's data +structure. This has the side effect of ruling out each number from the +rest of the row and column, and _also_ checking by assertion that the +number being placed is not ruled out. + +Those are a bad combination, because it means that if you give an +obviously inconsistent input grid to latin_solver_alloc (e.g. with two +identical numbers in a row already), it will fail an assertion. In +that situation, you want the solver run as a whole to return +diff_impossible so that the error is reported cleanly. + +This assertion failure could be provoked by giving either Towers or +Group a manually-constructed game description inconsistent in that +way, and hitting Solve. Worse, it could be provoked during live play +in Unequal, by filling in a number clashing with a clue and then +pressing 'h' to get hints. + +[benh: Backported to 20191231: The latin_solver functions don't take + a validator callback.] +--- + latin.c | 45 +++++++++++++++++++++++++++++---------------- + latin.h | 9 ++++++--- + unequal.c | 26 ++++++++++++++------------ + unfinished/group.c | 15 ++++++++------- + 4 files changed, 57 insertions(+), 38 deletions(-) + +--- a/latin.c ++++ b/latin.c +@@ -563,7 +563,7 @@ void latin_solver_free_scratch(struct la + sfree(scratch); + } + +-void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o) ++bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o) + { + int x, y; + +@@ -577,14 +577,23 @@ void latin_solver_alloc(struct latin_sol + memset(solver->row, 0, o*o); + memset(solver->col, 0, o*o); + +- for (x = 0; x < o; x++) +- for (y = 0; y < o; y++) +- if (grid[y*o+x]) +- latin_solver_place(solver, x, y, grid[y*o+x]); +- + #ifdef STANDALONE_SOLVER + solver->names = NULL; + #endif ++ ++ for (x = 0; x < o; x++) { ++ for (y = 0; y < o; y++) { ++ int n = grid[y*o+x]; ++ if (n) { ++ if (cube(x, y, n)) ++ latin_solver_place(solver, x, y, n); ++ else ++ return false; /* puzzle is already inconsistent */ ++ } ++ } ++ } ++ ++ return true; + } + + void latin_solver_free(struct latin_solver *solver) +@@ -810,14 +819,16 @@ static int latin_solver_recurse + } else { + newctx = ctx; + } +- latin_solver_alloc(&subsolver, outgrid, o); + #ifdef STANDALONE_SOLVER + subsolver.names = solver->names; + #endif +- ret = latin_solver_top(&subsolver, diff_recursive, +- diff_simple, diff_set_0, diff_set_1, +- diff_forcing, diff_recursive, +- usersolvers, newctx, ctxnew, ctxfree); ++ if (latin_solver_alloc(&subsolver, outgrid, o)) ++ ret = latin_solver_top(&subsolver, diff_recursive, ++ diff_simple, diff_set_0, diff_set_1, ++ diff_forcing, diff_recursive, ++ usersolvers, newctx, ctxnew, ctxfree); ++ else ++ ret = diff_impossible; + latin_solver_free(&subsolver); + if (ctxnew) + ctxfree(newctx); +@@ -1046,11 +1057,13 @@ int latin_solver(digit *grid, int o, int + struct latin_solver solver; + int diff; + +- latin_solver_alloc(&solver, grid, o); +- diff = latin_solver_main(&solver, maxdiff, +- diff_simple, diff_set_0, diff_set_1, +- diff_forcing, diff_recursive, +- usersolvers, ctx, ctxnew, ctxfree); ++ if (latin_solver_alloc(&solver, grid, o)) ++ diff = latin_solver_main(&solver, maxdiff, ++ diff_simple, diff_set_0, diff_set_1, ++ diff_forcing, diff_recursive, ++ usersolvers, ctx, ctxnew, ctxfree); ++ else ++ diff = diff_impossible; + latin_solver_free(&solver); + return diff; + } +--- a/latin.h ++++ b/latin.h +@@ -61,10 +61,13 @@ int latin_solver_forcing(struct latin_so + /* --- Solver allocation --- */ + + /* Fills in (and allocates members for) a latin_solver struct. +- * Will allocate members of snew, but not snew itself ++ * Will allocate members of solver, but not solver itself + * (allowing 'struct latin_solver' to be the first element in a larger +- * struct, for example). */ +-void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o); ++ * struct, for example). ++ * ++ * latin_solver_alloc returns false if the digits already in the grid ++ * could not be legally placed. */ ++bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o); + void latin_solver_free(struct latin_solver *solver); + + /* Allocates scratch space (for _set and _forcing) */ +--- a/unequal.c ++++ b/unequal.c +@@ -822,12 +822,13 @@ static int solver_state(game_state *stat + struct latin_solver solver; + int diff; + +- latin_solver_alloc(&solver, state->nums, state->order); +- +- diff = latin_solver_main(&solver, maxdiff, +- DIFF_LATIN, DIFF_SET, DIFF_EXTREME, +- DIFF_EXTREME, DIFF_RECURSIVE, +- unequal_solvers, ctx, clone_ctx, free_ctx); ++ if (!latin_solver_alloc(&solver, state->nums, state->order)) ++ diff = latin_solver_main(&solver, maxdiff, ++ DIFF_LATIN, DIFF_SET, DIFF_EXTREME, ++ DIFF_EXTREME, DIFF_RECURSIVE, ++ unequal_solvers, ctx, clone_ctx, free_ctx); ++ else ++ diff = DIFF_IMPOSSIBLE; + + memcpy(state->hints, solver.cube, state->order*state->order*state->order); + +@@ -2150,12 +2151,13 @@ static int solve(game_params *p, char *d + solver_show_working = debug; + game_debug(state); + +- latin_solver_alloc(&solver, state->nums, state->order); +- +- diff = latin_solver_main(&solver, DIFF_RECURSIVE, +- DIFF_LATIN, DIFF_SET, DIFF_EXTREME, +- DIFF_EXTREME, DIFF_RECURSIVE, +- unequal_solvers, ctx, clone_ctx, free_ctx); ++ if (latin_solver_alloc(&solver, state->nums, state->order)) ++ diff = latin_solver_main(&solver, DIFF_RECURSIVE, ++ DIFF_LATIN, DIFF_SET, DIFF_EXTREME, ++ DIFF_EXTREME, DIFF_RECURSIVE, ++ unequal_solvers, ctx, clone_ctx, free_ctx); ++ else ++ diff = DIFF_IMPOSSIBLE; + + free_ctx(ctx); + +--- a/unfinished/group.c ++++ b/unfinished/group.c +@@ -369,13 +369,11 @@ static int solver(const game_params *par + int w = params->w; + int ret; + struct latin_solver solver; ++ + #ifdef STANDALONE_SOLVER + char *p, text[100], *names[50]; + int i; +-#endif + +- latin_solver_alloc(&solver, grid, w); +-#ifdef STANDALONE_SOLVER + for (i = 0, p = text; i < w; i++) { + names[i] = p; + *p++ = TOCHAR(i+1, params->id); +@@ -384,10 +382,13 @@ static int solver(const game_params *par + solver.names = names; + #endif + +- ret = latin_solver_main(&solver, maxdiff, +- DIFF_TRIVIAL, DIFF_HARD, DIFF_EXTREME, +- DIFF_EXTREME, DIFF_UNREASONABLE, +- group_solvers, NULL, NULL, NULL); ++ if (latin_solver_alloc(&solver, grid, w)) ++ ret = latin_solver_main(&solver, maxdiff, ++ DIFF_TRIVIAL, DIFF_HARD, DIFF_EXTREME, ++ DIFF_EXTREME, DIFF_UNREASONABLE, ++ group_solvers, NULL, NULL, NULL); ++ else ++ ret = diff_impossible; + + latin_solver_free(&solver); + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch sgt-puzzles-20191231.79a5378/debian/patches/0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,85 @@ +From: Simon Tatham +Date: Sun, 5 Feb 2023 11:19:30 +0000 +Subject: [PATCH 027/159] Pearl: fix assertion failure on bad puzzle. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=05c536e50d0c3114e1de5283eac97ff22bad0fc7 +Bug-Debian: https://bugs.debian.org/1034190 + +Similarly to the previous commit, if you started Pearl with at least +some kinds of invalid puzzle (e.g. "6x6:abBfWcWWrBa") and then pressed +'h' to get hints, you could provoke an assertion failure. But this +time the assertion wasn't in the solver itself; the solver gave up +gracefully and didn't crash, but it _did_ leave the links between +squares in the game_state in an inconsistent state, in that one square +was marked as linking to its neighbour without the neighbour also +linking back to it. This caused the /* should have reciprocal link */ +assertion in dsf_update_completion to fail, when that was called from +check_completion after the solver had finished, to decide whether the +puzzle was now solved. + +In this commit, I arrange that whether or not pearl_solve returns a +grid layout that's legal by the rules of the _puzzle_, it at least +returns one that's legal by the rules of the _data representation_, in +that every link between squares is either bidirectional or absent. + +This is a better solution than just removing the assertion, because if +the inconsistent data were allowed to persist, it would lead to +further problems in gameplay. For example, if you just remove that +assertion instead of this fix and press 'h' on the example puzzle id +above, you'll find that the non-reciprocal links are actually visible, +in the form of several thick lines that stop at a grid square boundary +instead of connecting two square-centres. (It looks even sillier if +you set PEARL_GUI_LOOPY=y.) + +That's a situation that can't be created by a normal move, and if you +try to make normal moves after it (e.g. click one of the weird edges), +you'll find that both sides of the half-link get toggled, so now it's +a half-link the other way round. So not only can't you _create_ this +situation in normal play, you can't get rid of it either! + +That assertion in dsf_update_completion was commented out at one +point, and I put it back in commit c5500926bf7458a saying that if it +failed I'd like to know about it. And indeed, I'm glad I did, because +this kind of unfixable wrongness in the resulting game_state was worth +noticing and getting rid of! +--- + pearl.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +--- a/pearl.c ++++ b/pearl.c +@@ -855,6 +855,35 @@ cleanup: + if (ret == 1) assert(b < 0xD); /* we should have had a break by now */ + } + } ++ ++ /* ++ * Ensure we haven't left the _data structure_ inconsistent, ++ * regardless of the consistency of the _puzzle_. In ++ * particular, we should never have marked one square as ++ * linked to its neighbour if the neighbour is not ++ * reciprocally linked back to the original square. ++ * ++ * This can happen if we get part way through solving an ++ * impossible puzzle and then give up trying to make further ++ * progress. So here we fix it up to avoid confusing the rest ++ * of the game. ++ */ ++ for (y = 0; y < h; y++) { ++ for (x = 0; x < w; x++) { ++ for (d = 1; d <= 8; d += d) { ++ int nx = x + DX(d), ny = y + DY(d); ++ int rlink; ++ if (0 <= nx && nx < w && 0 <= ny && ny < w) ++ rlink = result[ny*w+nx] & F(d); ++ else ++ rlink = 0; /* off-board squares don't link back */ ++ ++ /* If other square doesn't link to us, don't link to it */ ++ if (!rlink) ++ result[y*w+x] &= ~d; ++ } ++ } ++ } + } + + sfree(dsfsize); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch sgt-puzzles-20191231.79a5378/debian/patches/0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,34 @@ +From: Simon Tatham +Date: Sun, 14 Mar 2021 22:05:23 +0000 +Subject: [PATCH 028/389] Filling: fix assertion failure in 3x1 game + generation. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=1fcb61cffe538c11a11fc2ec94d6470a61df019e + +This would come up on the game id "3x1#12345", for example. The +failing assertion was (s->board[f] != EMPTY) in expand(), called in +turn from learn_expand_or_one(). + +It looks as if the problem was that the #define SENTINEL was set too +small. It was intended to be a value that can't coincide with the true +size of any region - and it was set to precisely the area of the whole +board. But on a 3x1 grid, that _can_ coincide with the size of a +region! So a board entry was set to a real region size, and then +mistaken for SENTINEL by another part of the code. + +Easy fix: set SENTINEL to be sz+1. Now it really can't coincide with a +region area. +--- + filling.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/filling.c ++++ b/filling.c +@@ -310,7 +310,7 @@ static void print_board(int *board, int + static game_state *new_game(midend *, const game_params *, const char *); + static void free_game(game_state *); + +-#define SENTINEL sz ++#define SENTINEL (sz+1) + + static bool mark_region(int *board, int w, int h, int i, int n, int m) { + int j; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0028-Pearl-fix-bounds-check-in-previous-commit.patch sgt-puzzles-20191231.79a5378/debian/patches/0028-Pearl-fix-bounds-check-in-previous-commit.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0028-Pearl-fix-bounds-check-in-previous-commit.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0028-Pearl-fix-bounds-check-in-previous-commit.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,22 @@ +From: Simon Tatham +Date: Sun, 5 Feb 2023 12:05:28 +0000 +Subject: [PATCH 028/159] Pearl: fix bounds check in previous commit. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=9ce0a6d93212ffc0986a2b399fd8e9e983f62904 +Bug-Debian: https://bugs.debian.org/1034190 + +Ahem. That's what I get for testing the fix on a square puzzle. +--- + pearl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/pearl.c ++++ b/pearl.c +@@ -873,7 +873,7 @@ cleanup: + for (d = 1; d <= 8; d += d) { + int nx = x + DX(d), ny = y + DY(d); + int rlink; +- if (0 <= nx && nx < w && 0 <= ny && ny < w) ++ if (0 <= nx && nx < w && 0 <= ny && ny < h) + rlink = result[ny*w+nx] & F(d); + else + rlink = 0; /* off-board squares don't link back */ diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch sgt-puzzles-20191231.79a5378/debian/patches/0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,58 @@ +From: Ben Harris +Date: Sat, 4 Feb 2023 16:18:27 +0000 +Subject: [PATCH 029/159] Unequal: Don't insist that solve moves must actually + solve +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=84ec2a0a77d63450311f7c25b36d4b9f7e3c53e1 +Bug-Debian: https://bugs.debian.org/1034190 + +A corrupt save file can include an "S" move that doesn't give a valid +solution. An assertion failure ("execute_move: Assertion `rc > 0' +failed.") at that point is rude, so now we just don't set the +"completed" flag in that case. We still set the "cheated" flag, to +reward (lack of) effort. + +Here's a trivial test case: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :7:Unequal +CPARAMS :1:3 +PARAMS :1:3 +DESC :17:0,0,0,0,0,0,0,0,0 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :10:S222222222 +--- + unequal.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/unequal.c ++++ b/unequal.c +@@ -1556,7 +1556,7 @@ static char *interpret_move(const game_s + static game_state *execute_move(const game_state *state, const char *move) + { + game_state *ret = NULL; +- int x, y, n, i, rc; ++ int x, y, n, i; + + debug(("execute_move: %s", move)); + +@@ -1581,7 +1581,7 @@ static game_state *execute_move(const ga + const char *p; + + ret = dup_game(state); +- ret->completed = ret->cheated = true; ++ ret->cheated = true; + + p = move+1; + for (i = 0; i < state->order*state->order; i++) { +@@ -1592,8 +1592,8 @@ static game_state *execute_move(const ga + p++; + } + if (*p) goto badmove; +- rc = check_complete(ret->nums, ret, true); +- assert(rc > 0); ++ if (!ret->completed && check_complete(ret->nums, ret, true) > 0) ++ ret->completed = true; + return ret; + } else if (move[0] == 'M') { + ret = dup_game(state); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch sgt-puzzles-20191231.79a5378/debian/patches/0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,27 @@ +From: Ben Harris +Date: Sat, 4 Feb 2023 16:50:55 +0000 +Subject: [PATCH 030/159] Range: Don't fail an assertion on an all-black board +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ae73ad76ef95f0e40868436cb750126322051dd0 +Bug-Debian: https://bugs.debian.org/1034190 + +If there are no white squares, then Range's check that all the white +squares form a connected component goes wrong. Skip the check in that +case to avoid an assretion violation ("edsf_canonify: Assertion `index +>= 0' failed."). This can be demonstrated by starting a game with no +clues (e.g. "range 3:i") and then filling in every square. +--- + range.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/range.c ++++ b/range.c +@@ -1474,7 +1474,8 @@ static bool find_errors(const game_state + if (state->grid[r*w+c] != BLACK && + state->grid[r*w+(c+1)] != BLACK) + dsf_merge(dsf, r*w+c, r*w+(c+1)); +- if (nblack + dsf_size(dsf, any_white_cell) < n) { ++ if (any_white_cell != -1 && ++ nblack + dsf_size(dsf, any_white_cell) < n) { + int biggest, canonical; + + if (!report) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch sgt-puzzles-20191231.79a5378/debian/patches/0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,39 @@ +From: Ben Harris +Date: Sat, 28 Jan 2023 22:27:21 +0000 +Subject: [PATCH 031/159] Limit width and height to SHRT_MAX in Mines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c0e08f308792b15425e10ad494263d77a45ad92d +Bug-Debian: https://bugs.debian.org/1034190 + +Mines' "struct set" stores co-ordinates within the grid in a pair of +shorts, which leads to very bad behaviour (including heap-based buffer +overruns) if the grid is bigger than SHRT_MAX in either dimension. So +now we don't allow that. + +The overrun can be demonstrated by loading this save file, though the +precise crash is quite variable. In particular, you seem to get +better crashes if the file doesn't have a trailing newline. + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +PARAMS :5:06000 +CPARAMS :7:6x60000 +NSTATES :1:3 +STATEPOS:1:2 +MOVE :5:C0,00 +GAME :5:Mines +DESC :22:r8,u,00000000000000000 +MOVE :: +--- + mines.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -263,6 +263,8 @@ static const char *validate_params(const + return "Width and height must both be greater than two"; + if (params->w < 1 || params->h < 1) + return "Width and height must both be at least one"; ++ if (params->w > SHRT_MAX || params->h > SHRT_MAX) ++ return "Neither width nor height may be unreasonably large"; + if (params->w > INT_MAX / params->h) + return "Width times height must not be unreasonably large"; + if (params->n < 0) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch sgt-puzzles-20191231.79a5378/debian/patches/0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,35 @@ +From: Ben Harris +Date: Tue, 31 Jan 2023 21:08:05 +0000 +Subject: [PATCH 032/159] Mines: Add assertions to range-check conversions to + short +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=49841bd0fc04490d94cf32c0e6f9d3f4ffabe098 +Bug-Debian: https://bugs.debian.org/1034190 + +I think these should be adequately guarded by the new restrictions on +grid size, but I'd prefer to be sure. +--- + mines.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -435,7 +435,9 @@ static void ss_add(struct setstore *ss, + * Create a set structure and add it to the tree. + */ + s = snew(struct set); ++ assert(SHRT_MIN <= x && x <= SHRT_MAX); + s->x = x; ++ assert(SHRT_MIN <= y && y <= SHRT_MAX); + s->y = y; + s->mask = mask; + s->mines = mines; +@@ -506,7 +508,9 @@ static struct set **ss_overlap(struct se + /* + * Find the first set with these top left coordinates. + */ ++ assert(SHRT_MIN <= xx && xx <= SHRT_MAX); + stmp.x = xx; ++ assert(SHRT_MIN <= yy && yy <= SHRT_MAX); + stmp.y = yy; + stmp.mask = 0; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch sgt-puzzles-20191231.79a5378/debian/patches/0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,28 @@ +From: Simon Tatham +Date: Wed, 8 Feb 2023 18:22:23 +0000 +Subject: [PATCH 033/159] Unequal: fix sense error in latin_solver_alloc fix. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=bd5c0a37a019c540eda05f8291cad90ffd598134 +Bug-Debian: https://bugs.debian.org/1034190 + +In commit 5030d87903191d5 I gave latin_solver_alloc a return value, +and introduced a check of that value at every call site. One of the +checks was backwards, with the effect that Unequal game generation now +more or less always fails an assertion. For example: + +$ unequal --generate 1 4#12345 +unequal: unequal.c:1072: gg_best_clue: Assertion `best != -1' failed. +--- + unequal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/unequal.c ++++ b/unequal.c +@@ -822,7 +822,7 @@ static int solver_state(game_state *stat + struct latin_solver solver; + int diff; + +- if (!latin_solver_alloc(&solver, state->nums, state->order)) ++ if (latin_solver_alloc(&solver, state->nums, state->order)) + diff = latin_solver_main(&solver, maxdiff, + DIFF_LATIN, DIFF_SET, DIFF_EXTREME, + DIFF_EXTREME, DIFF_RECURSIVE, diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0034-Forbid-impossible-moves-in-Bridges.patch sgt-puzzles-20191231.79a5378/debian/patches/0034-Forbid-impossible-moves-in-Bridges.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0034-Forbid-impossible-moves-in-Bridges.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0034-Forbid-impossible-moves-in-Bridges.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,46 @@ +From: Ben Harris +Date: Fri, 10 Feb 2023 17:09:18 +0000 +Subject: [PATCH 034/159] Forbid impossible moves in Bridges +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=bf9abb2a127a4a81babe50ecb419527f8aeffe28 +Bug-Debian: https://bugs.debian.org/1034190 + +Specifically, a bridge or a non-bridge must connect two islands that +differ in precisely one co-ordinate. Without this, a save file that +tries to connect or disconnect two non-orthogonal islands will cause +"island_join: Assertion `!"island_join: islands not orthogonal."' +failed." + +Here's a save file demonstrating the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :7:Bridges +PARAMS :13:3x3i30e10m2d0 +CPARAMS :13:3x3i30e10m2d0 +DESC :6:b1c1a2 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :10:L0,2,2,0,1 +--- + bridges.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/bridges.c ++++ b/bridges.c +@@ -2543,6 +2543,8 @@ static game_state *execute_move(const ga + goto badmove; + if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) + goto badmove; ++ /* Precisely one co-ordinate must differ between islands. */ ++ if ((x1 != x2) + (y1 != y2) != 1) goto badmove; + is1 = INDEX(ret, gridi, x1, y1); + is2 = INDEX(ret, gridi, x2, y2); + if (!is1 || !is2) goto badmove; +@@ -2554,6 +2556,7 @@ static game_state *execute_move(const ga + goto badmove; + if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) + goto badmove; ++ if ((x1 != x2) + (y1 != y2) != 1) goto badmove; + is1 = INDEX(ret, gridi, x1, y1); + is2 = INDEX(ret, gridi, x2, y2); + if (!is1 || !is2) goto badmove; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch sgt-puzzles-20191231.79a5378/debian/patches/0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,62 @@ +From: Ben Harris +Date: Fri, 10 Feb 2023 18:28:36 +0000 +Subject: [PATCH 035/159] Forbid game descriptions with joined islands in + Bridges +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ad2fb760fc881d1ceb1ac1151bf60b85deb16c71 +Bug-Debian: https://bugs.debian.org/1034190 + +A game description with islands in adjacent grid squares, like +"3x3:11g", shouldn't be allowed. If it is, then bridges between the +islands are invisible and clicking one of them causes an assertion +failure: "Assertion `is_loop->adj.points[j].off > 1' failed." + +The code to check this is really rather complex, but I think the +complexity is mostly necessary. +--- + bridges.c | 27 ++++++++++++++++++++------- + 1 file changed, 20 insertions(+), 7 deletions(-) + +--- a/bridges.c ++++ b/bridges.c +@@ -2007,21 +2007,34 @@ generated: + + static const char *validate_desc(const game_params *params, const char *desc) + { +- int i, wh = params->w * params->h, nislands = 0; ++ int i, j, wh = params->w * params->h, nislands = 0; ++ bool *last_row = snewn(params->w, bool); + ++ memset(last_row, 0, params->w * sizeof(bool)); + for (i = 0; i < wh; i++) { +- if (*desc >= '1' && *desc <= '9') ++ if ((*desc >= '1' && *desc <= '9') || (*desc >= 'A' && *desc <= 'G')) { + nislands++; +- else if (*desc >= 'a' && *desc <= 'z') ++ /* Look for other islands to the left and above. */ ++ if ((i % params->w > 0 && last_row[i % params->w - 1]) || ++ last_row[i % params->w]) { ++ sfree(last_row); ++ return "Game description contains joined islands"; ++ } ++ last_row[i % params->w] = true; ++ } else if (*desc >= 'a' && *desc <= 'z') { ++ for (j = 0; j < *desc - 'a' + 1; j++) ++ last_row[(i + j) % params->w] = false; + i += *desc - 'a'; /* plus the i++ */ +- else if (*desc >= 'A' && *desc <= 'G') +- nislands++; +- else if (!*desc) ++ } else if (!*desc) { ++ sfree(last_row); + return "Game description shorter than expected"; +- else ++ } else { ++ sfree(last_row); + return "Game description contains unexpected character"; ++ } + desc++; + } ++ sfree(last_row); + if (*desc || i > wh) + return "Game description longer than expected"; + if (nislands < 2) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch sgt-puzzles-20191231.79a5378/debian/patches/0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,129 @@ +From: Ben Harris +Date: Sat, 11 Feb 2023 21:22:49 +0000 +Subject: [PATCH 037/159] Check state is valid at the end of a move in Pearl +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c0b2f0fc98e87392dcb4dd8faf3076786fc49367 +Bug-Debian: https://bugs.debian.org/1034190 + +A Pearl move string contains a sequence of sub-moves, each of which +can affect the state of the connection between the centre of a square +and one of its edges. interpret_move() generates these in pairs so +that the two halves of a connection between the centres of adjacent +squares stay in the same state. + +If, however, a save file contains mismatched half-moves, +execute_move() should ideally return NULL rather than causing an +assertion failure. This has to be checked at the end of the whole +move string, so I've arranged for check_completion() to return a +boolean indicating whether the current state (and hence the move +preceding it) is valid. It now returns 'false' when a connection +stops at a square boundary or when it goes off the board. These +conditions used to be assertion failures, and now they just cause the +move to be rejected. + +This supersedes the check for off-board connections added in 15f4fa8, +since now check_completion() can check for off-board links for the +whole board at once. + +This save file trivially demonstrates the problem, causing +"dsf_update_completion: Assertion `state->lines[bc] & F(dir)' failed" +without this fix: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :5:Pearl +PARAMS :5:6x6t0 +CPARAMS :5:6x6t0 +DESC :17:BbBfWceBbWaBWWgWB +NSTATES :1:2 +STATEPOS:1:2 +MOVE :6:R1,0,0 +--- + pearl.c | 37 ++++++++++++++++++------------------- + 1 file changed, 18 insertions(+), 19 deletions(-) + +--- a/pearl.c ++++ b/pearl.c +@@ -1525,25 +1525,30 @@ static char nbits[16] = { 0, 1, 1, 2, + + #define ERROR_CLUE 16 + +-static void dsf_update_completion(game_state *state, int ax, int ay, char dir, ++/* Returns false if the state is invalid. */ ++static bool dsf_update_completion(game_state *state, int ax, int ay, char dir, + int *dsf) + { + int w = state->shared->w /*, h = state->shared->h */; + int ac = ay*w+ax, bx, by, bc; + +- if (!(state->lines[ac] & dir)) return; /* no link */ ++ if (!(state->lines[ac] & dir)) return true; /* no link */ + bx = ax + DX(dir); by = ay + DY(dir); + +- assert(INGRID(state, bx, by)); /* should not have a link off grid */ ++ if (!INGRID(state, bx, by)) ++ return false; /* should not have a link off grid */ + + bc = by*w+bx; +- assert(state->lines[bc] & F(dir)); /* should have reciprocal link */ +- if (!(state->lines[bc] & F(dir))) return; ++ if (!(state->lines[bc] & F(dir))) ++ return false; /* should have reciprocal link */ ++ if (!(state->lines[bc] & F(dir))) return true; + + dsf_merge(dsf, ac, bc); ++ return true; + } + +-static void check_completion(game_state *state, bool mark) ++/* Returns false if the state is invalid. */ ++static bool check_completion(game_state *state, bool mark) + { + int w = state->shared->w, h = state->shared->h, x, y, i, d; + bool had_error = false; +@@ -1571,8 +1576,11 @@ static void check_completion(game_state + /* Build the dsf. */ + for (x = 0; x < w; x++) { + for (y = 0; y < h; y++) { +- dsf_update_completion(state, x, y, R, dsf); +- dsf_update_completion(state, x, y, D, dsf); ++ if (!dsf_update_completion(state, x, y, R, dsf) || ++ !dsf_update_completion(state, x, y, D, dsf)) { ++ sfree(dsf); ++ return false; ++ } + } + } + +@@ -1727,6 +1735,7 @@ static void check_completion(game_state + if (!had_error) + state->completed = true; + } ++ return true; + } + + /* completion check: +@@ -2264,16 +2273,6 @@ static game_state *execute_move(const ga + (ret->marks[y*w + x] & (char)l)) + goto badmove; + +- /* +- * Similarly, if we've ended up with a line or mark going +- * off the board, that's not acceptable. +- */ +- for (l = 1; l <= 8; l <<= 1) +- if (((ret->lines[y*w + x] & (char)l) || +- (ret->marks[y*w + x] & (char)l)) && +- !INGRID(state, x+DX(l), y+DY(l))) +- goto badmove; +- + move += n; + } else if (strcmp(move, "H") == 0) { + pearl_solve(ret->shared->w, ret->shared->h, +@@ -2290,7 +2289,7 @@ static game_state *execute_move(const ga + goto badmove; + } + +- check_completion(ret, true); ++ if (!check_completion(ret, true)) goto badmove; + + return ret; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch sgt-puzzles-20191231.79a5378/debian/patches/0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,45 @@ +From: Ben Harris +Date: Sat, 11 Feb 2023 22:00:49 +0000 +Subject: [PATCH 038/159] Cleanly reject more ill-formed solve moves in Flood +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=896a73bd7ff8cbde44e97d89cef57346478f0072 +Bug-Debian: https://bugs.debian.org/1034190 + +The fix in e4112b3 was incomplete: there was another assertion that could be failed by a save file with an ill-formed solve move. That now gets rejected properly. Here's an example save file to demonstrate the problem: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :5:Flood +PARAMS :7:6x6c6m0 +CPARAMS :7:6x6c6m0 +DESC :39:000000000000000000000000000000000000,00 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :1:S +--- + flood.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/flood.c ++++ b/flood.c +@@ -924,15 +924,16 @@ static game_state *execute_move(const ga + + sol->moves = snewn(sol->nmoves, char); + for (i = 0, p = move; i < sol->nmoves; i++) { +- assert(*p); ++ if (!*p) { ++ badsolve: ++ sfree(sol->moves); ++ sfree(sol); ++ return NULL; ++ }; + sol->moves[i] = atoi(p); + p += strspn(p, "0123456789"); + if (*p) { +- if (*p != ',') { +- sfree(sol->moves); +- sfree(sol); +- return NULL; +- } ++ if (*p != ',') goto badsolve; + p++; + } + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch sgt-puzzles-20191231.79a5378/debian/patches/0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,51 @@ +From: Ben Harris +Date: Sat, 11 Feb 2023 22:49:36 +0000 +Subject: [PATCH 039/159] Don't allow moves that change the constraints in + Unequal +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=97b03cc67a31c1d0869a21c50b9ca31f78775ff9 +Bug-Debian: https://bugs.debian.org/1034190 + +Unequal has a flags word per cell. Some of those flags are fixed, +like the locations of the ">" signs, but others indicate errors and +are used to allow the player to mark clues as "spent". Move strings +beginning with "F" allow the user to change the "spent" flags, but +they shouldn't allow the user to change any other flags, especially +those marking the constraints. + +Without this fix, the following save file gives a "solver_nminmax: +Assertion `x >= 0 && y >= 0 && x < o && y < o' failed" after it adds a +clue that points off the board: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +GAME :7:Unequal +PARAMS :3:3e0 +CPARAMS :3:3e0 +DESC :17:0,0,0,0,0,0,0,0,0 +NSTATES :2:3 +STATEPOS:1:3 +MOVE :6:F2,0,4 +MOVE :1:H +--- + unequal.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/unequal.c ++++ b/unequal.c +@@ -84,6 +84,7 @@ struct game_params { + #define ADJ_TO_SPENT(x) ((x) << 9) + + #define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT) ++#define F_SPENT_MASK (F_SPENT_UP|F_SPENT_RIGHT|F_SPENT_DOWN|F_SPENT_LEFT) + + struct game_state { + int order; +@@ -1610,7 +1611,8 @@ static game_state *execute_move(const ga + check_complete(ret->nums, ret, true); + return ret; + } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && +- x >= 0 && x < state->order && y >= 0 && y < state->order) { ++ x >= 0 && x < state->order && y >= 0 && y < state->order && ++ (n & ~F_SPENT_MASK) == 0) { + ret = dup_game(state); + GRID(ret, flags, x, y) ^= n; + return ret; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch sgt-puzzles-20191231.79a5378/debian/patches/0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,50 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 09:31:03 +0000 +Subject: [PATCH 041/159] Fix memory leaks in Keen's validate_desc() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=bb31efdbc91495a4385ca0afffa4c8bb8f564d7b +Bug-Debian: https://bugs.debian.org/1034190 + +Keen uses a DSF to validate its game descriptions and almost always +failed to free it, even when the validation succeeded. +--- + keen.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/keen.c ++++ b/keen.c +@@ -1224,8 +1224,10 @@ static const char *validate_desc(const g + return ret; + } + +- if (*p != ',') ++ if (*p != ',') { ++ sfree(dsf); + return "Expected ',' after block structure description"; ++ } + p++; + + /* +@@ -1237,17 +1239,22 @@ static const char *validate_desc(const g + if (*p == 'a' || *p == 'm') { + /* these clues need no validation */ + } else if (*p == 'd' || *p == 's') { +- if (dsf_size(dsf, i) != 2) ++ if (dsf_size(dsf, i) != 2) { ++ sfree(dsf); + return "Subtraction and division blocks must have area 2"; ++ } + } else if (!*p) { ++ sfree(dsf); + return "Too few clues for block structure"; + } else { ++ sfree(dsf); + return "Unrecognised clue type"; + } + p++; + while (*p && isdigit((unsigned char)*p)) p++; + } + } ++ sfree(dsf); + if (*p) + return "Too many clues for block structure"; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch sgt-puzzles-20191231.79a5378/debian/patches/0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,33 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 09:45:08 +0000 +Subject: [PATCH 043/159] Don't leak grids in Loopy's validate_desc() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=11b631ea870355306c4b1d03458bb3cea8f29188 +Bug-Debian: https://bugs.debian.org/1034190 + +--- + loopy.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/loopy.c ++++ b/loopy.c +@@ -788,13 +788,18 @@ static const char *validate_desc(const g + count += *desc - 'a' + 1; + continue; + } ++ grid_free(g); + return "Unknown character in description"; + } + +- if (count < g->num_faces) ++ if (count < g->num_faces) { ++ grid_free(g); + return "Description too short for board size"; +- if (count > g->num_faces) ++ } ++ if (count > g->num_faces) { ++ grid_free(g); + return "Description too long for board size"; ++ } + + grid_free(g); + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch sgt-puzzles-20191231.79a5378/debian/patches/0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,21 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 09:48:16 +0000 +Subject: [PATCH 044/159] Remember to free the to_draw member from Net's + drawstate +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=493bf16ddbe2185664d6c3053f7891a9f232c75c +Bug-Debian: https://bugs.debian.org/1034190 + +--- + net.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net.c ++++ b/net.c +@@ -2464,6 +2464,7 @@ static game_drawstate *game_new_drawstat + static void game_free_drawstate(drawing *dr, game_drawstate *ds) + { + sfree(ds->visible); ++ sfree(ds->to_draw); + sfree(ds); + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch sgt-puzzles-20191231.79a5378/debian/patches/0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,29 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 10:04:47 +0000 +Subject: [PATCH 045/159] Undead: check the return value of sscanf() in + execute_move() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0a7c531e8f4c1970662f7c30aea006e65d5ff010 +Bug-Debian: https://bugs.debian.org/1034190 + +sscanf() assigns its output in order, so if a conversion specifier fails +to match, a later "%n" specifier will also not get its result assigned. +In Undead's execute_move(), this led to the result of "%n" being used +without being initialised. That could cause it to try to parse +arbitrary memory as part of the move string, which shouldn't be a +security problem (since execute_move() handles untrusted input anyway), +but could lead to a crash and certainly wasn't helpful. +--- + undead.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/undead.c ++++ b/undead.c +@@ -2059,7 +2059,7 @@ static game_state *execute_move(const ga + } else if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' || + c == 'g' || c == 'v' || c == 'z') { + move++; +- sscanf(move, "%d%n", &x, &n); ++ if (sscanf(move, "%d%n", &x, &n) != 1) goto badmove; + if (x < 0 || x >= ret->common->num_total) goto badmove; + if (c == 'G') ret->guess[x] = 1; + if (c == 'V') ret->guess[x] = 2; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0046-Don-t-leak-duplicate-edges-in-Untangle.patch sgt-puzzles-20191231.79a5378/debian/patches/0046-Don-t-leak-duplicate-edges-in-Untangle.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0046-Don-t-leak-duplicate-edges-in-Untangle.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0046-Don-t-leak-duplicate-edges-in-Untangle.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,27 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 11:08:14 +0000 +Subject: [PATCH 046/159] Don't leak duplicate edges in Untangle +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=19401e95e0a75577103e9c1a877611234a0d8ab5 +Bug-Debian: https://bugs.debian.org/1034190 + +Untangle game descriptions are allowed to contain duplicate edges, and +add234() can handle deduping them. However, when add234() reports that +your newly-allocated edge is a duplicate, it's important to free it +again. +--- + untangle.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/untangle.c ++++ b/untangle.c +@@ -420,7 +420,9 @@ static void addedge(tree234 *edges, int + e->a = min(a, b); + e->b = max(a, b); + +- add234(edges, e); ++ if (add234(edges, e) != e) ++ /* Duplicate edge. */ ++ sfree(e); + } + + static bool isedge(tree234 *edges, int a, int b) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch sgt-puzzles-20191231.79a5378/debian/patches/0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,22 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 11:13:03 +0000 +Subject: [PATCH 047/159] Remember to free the numcolours array from Pattern's + drawstate +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=1aa67e7a75ac21d15780d6aaab65a2c0f6f65198 +Bug-Debian: https://bugs.debian.org/1034190 + +[benh: Backported to 20191231: Adjust context] +--- + pattern.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/pattern.c ++++ b/pattern.c +@@ -1706,6 +1706,7 @@ static game_drawstate *game_new_drawstat + static void game_free_drawstate(drawing *dr, game_drawstate *ds) + { + sfree(ds->visible); ++ sfree(ds->numcolours); + sfree(ds); + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch sgt-puzzles-20191231.79a5378/debian/patches/0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,35 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 14:31:39 +0000 +Subject: [PATCH 049/159] Twiddle: don't read off the end of parameter strings + ending 'm' +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=73c7bc090155ab8c4661feaeea9e6a6e74ee6f77 +Bug-Debian: https://bugs.debian.org/1034190 + +The overrun could be demonstrated by specifying a parameter string of +"3x3m" to a build with AddressSanitizer. +--- + twiddle.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/twiddle.c ++++ b/twiddle.c +@@ -124,14 +124,16 @@ static void decode_params(game_params *r + while (*string) { + if (*string == 'r') { + ret->rowsonly = true; ++ string++; + } else if (*string == 'o') { + ret->orientable = true; ++ string++; + } else if (*string == 'm') { + string++; + ret->movetarget = atoi(string); +- while (string[1] && isdigit((unsigned char)string[1])) string++; +- } +- string++; ++ while (*string && isdigit((unsigned char)*string)) string++; ++ } else ++ string++; + } + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch sgt-puzzles-20191231.79a5378/debian/patches/0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,29 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 20:17:58 +0000 +Subject: [PATCH 050/159] Loopy: free the grid description string if it's + invalid +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e336513be755159158c5ba017c91b018ad4cd36c +Bug-Debian: https://bugs.debian.org/1034190 + +--- + loopy.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/loopy.c ++++ b/loopy.c +@@ -774,10 +774,13 @@ static const char *validate_desc(const g + * know is the precise number of faces. */ + grid_desc = extract_grid_desc(&desc); + ret = grid_validate_desc(grid_types[params->type], params->w, params->h, grid_desc); +- if (ret) return ret; ++ if (ret) { ++ sfree(grid_desc); ++ return ret; ++ } + + g = loopy_generate_grid(params, grid_desc); +- if (grid_desc) sfree(grid_desc); ++ sfree(grid_desc); + + for (; *desc; ++desc) { + if ((*desc >= '0' && *desc <= '9') || (*desc >= 'A' && *desc <= 'Z')) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch sgt-puzzles-20191231.79a5378/debian/patches/0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,32 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 00:14:22 +0000 +Subject: [PATCH 052/159] Avoid division by zero in Cube grid-size checks +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=df783b93e3271264a8d54f90876f41a80ef2247d +Bug-Debian: https://bugs.debian.org/1034190 + +On a triangular grid, Cube allows either d1 or d2 (but not both) to be +zero, so it's important to check that each one is not zero before +dividing by it. + +The crash could be triggered by, for instance "cube t0x2". +--- + cube.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/cube.c ++++ b/cube.c +@@ -567,9 +567,11 @@ static const char *validate_params(const + * can safely multiply them and compare against the + * _remaining_ space. + */ +- if ((params->d1 > INT_MAX / params->d1) || +- (params->d2 > (INT_MAX - params->d1*params->d1) / params->d2) || +- (params->d1*params->d2 > (INT_MAX - params->d1*params->d1 - ++ if ((params->d1 > 0 && params->d1 > INT_MAX / params->d1) || ++ (params->d2 > 0 && ++ params->d2 > (INT_MAX - params->d1*params->d1) / params->d2) || ++ (params->d2 > 0 && ++ params->d1*params->d2 > (INT_MAX - params->d1*params->d1 - + params->d2*params->d2) / params->d2)) + return "Grid area must not be unreasonably large"; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0055-Validate-that-save-file-values-are-ASCII-mostly.patch sgt-puzzles-20191231.79a5378/debian/patches/0055-Validate-that-save-file-values-are-ASCII-mostly.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0055-Validate-that-save-file-values-are-ASCII-mostly.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0055-Validate-that-save-file-values-are-ASCII-mostly.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,37 @@ +From: Ben Harris +Date: Sun, 12 Feb 2023 23:04:12 +0000 +Subject: [PATCH 055/159] Validate that save file values are ASCII (mostly) +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c3a5a7842eb6c41fb75a8a110a3f2cbc1c8fc5d9 +Bug-Debian: https://bugs.debian.org/1034190 + +Apart from "SEED" records, all values in save files generated by Puzzles +should be printable ASCII. This is enforced by assertion in the saving +code. However, if a save file with non-ASCII move strings (for +instance) manages to get loaded then these non-ASCII values can cause an +assertion failure on saving. Instead, the loading code now checks +values for ASCIIness. + +This will not only avoid problems when re-saving files, but will also +defend the various internal parsers from at least some evil strings. It +shouldn't invalidate any save files actually generated by Puzzles, but +it will sadly invalidate some of my fuzzing corpus. +--- + midend.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/midend.c ++++ b/midend.c +@@ -2198,6 +2198,13 @@ static const char *midend_deserialise_in + goto cleanup; + } + val[len] = '\0'; ++ /* Validate that all values (apart from SEED) are printable ASCII. */ ++ if (strcmp(key, "SEED")) ++ for (i = 0; val[i]; i++) ++ if (val[i] < 32 || val[i] >= 127) { ++ ret = "Forbidden characters in saved game file"; ++ goto cleanup; ++ } + + if (!started) { + if (strcmp(key, "SAVEFILE") || strcmp(val, SERIALISE_MAGIC)) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0056-More-validation-of-solve-moves-in-Flood.patch sgt-puzzles-20191231.79a5378/debian/patches/0056-More-validation-of-solve-moves-in-Flood.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0056-More-validation-of-solve-moves-in-Flood.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0056-More-validation-of-solve-moves-in-Flood.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,29 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 00:00:30 +0000 +Subject: [PATCH 056/159] More validation of solve moves in Flood +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e8668dc883e940f0852ff4520abc3d30cae90aef +Bug-Debian: https://bugs.debian.org/1034190 + +To avoid assertion failures while painting it, we need to ensure that +the purported solution in a solve move doesn't include filling with the +current top-left colour at any point. That means checking the first +entry against the current top-left colours, and each later one against +its predecessor. +--- + flood.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/flood.c ++++ b/flood.c +@@ -931,6 +931,11 @@ static game_state *execute_move(const ga + return NULL; + }; + sol->moves[i] = atoi(p); ++ if (i == 0 ? ++ sol->moves[i] == state->grid[FILLY * state->w + FILLX] : ++ sol->moves[i] == sol->moves[i-1]) ++ /* Solution contains a fill with the current colour. */ ++ goto badsolve; + p += strspn(p, "0123456789"); + if (*p) { + if (*p != ',') goto badsolve; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch sgt-puzzles-20191231.79a5378/debian/patches/0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,54 @@ +From: Ben Harris +Date: Tue, 14 Feb 2023 22:02:35 +0000 +Subject: [PATCH 058/159] Make sure that moves in Flood use only valid colours +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=7364ce8e266d947be146d635958a7b282752aac6 +Bug-Debian: https://bugs.debian.org/1034190 + +If execute_move() receieves a move that uses a colour beyond the range +for the current game, it now rejects it. Without this a solve string +containing an invalid colour would cause an assertion failure: "fill: +Assertion `oldcolour != newcolour' failed." While I was in the area I +put a range check on colours for normal moves as well. To demonstrate +the problem, load this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Flood +PARAMS :7:6x6c6m5 +CPARAMS :7:6x6c6m3 +DESC :39:432242034203340350204502505323231342,17 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :2:S6 +--- + flood.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/flood.c ++++ b/flood.c +@@ -872,7 +872,7 @@ static game_state *execute_move(const ga + + if (move[0] == 'M' && + sscanf(move+1, "%d", &c) == 1 && +- c >= 0 && ++ c >= 0 && c < state->colours && + c != state->grid[FILLY * state->w + FILLX] && + !state->complete) { + int *queue = snewn(state->w * state->h, int); +@@ -931,10 +931,12 @@ static game_state *execute_move(const ga + return NULL; + }; + sol->moves[i] = atoi(p); +- if (i == 0 ? +- sol->moves[i] == state->grid[FILLY * state->w + FILLX] : +- sol->moves[i] == sol->moves[i-1]) +- /* Solution contains a fill with the current colour. */ ++ if (sol->moves[i] < 0 || sol->moves[i] >= state->colours || ++ (i == 0 ? ++ sol->moves[i] == state->grid[FILLY * state->w + FILLX] : ++ sol->moves[i] == sol->moves[i-1])) ++ /* Solution contains a fill with an invalid colour or ++ * the current colour. */ + goto badsolve; + p += strspn(p, "0123456789"); + if (*p) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0059-Tighten-grid-size-limit-in-Mines.patch sgt-puzzles-20191231.79a5378/debian/patches/0059-Tighten-grid-size-limit-in-Mines.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0059-Tighten-grid-size-limit-in-Mines.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0059-Tighten-grid-size-limit-in-Mines.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,46 @@ +From: Ben Harris +Date: Wed, 15 Feb 2023 14:07:34 +0000 +Subject: [PATCH 059/159] Tighten grid-size limit in Mines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=9394e9c74bdb48dc1c74693bcb41fd35f8fc743c +Bug-Debian: https://bugs.debian.org/1034190 + +Mines uses random_upto() to decide where to place mines, and +random_upto() takes a maximum limit of 2^28-1, so limit the number of +grid squares to that (or INT_MAX if someone's still trying to build on +a 16-bit system). + +This avoids an assertion failure: "random_upto: Assertion `bits < 32' +failed." which can be demonstrated by this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Mines +PARAMS :5:18090 +CPARAMS :5:18090 +DESC :11:r9,u,MEdff6 +UI :2:D0 +TIME :1:0 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :4:O2,1 +--- + mines.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -265,7 +265,14 @@ static const char *validate_params(const + return "Width and height must both be at least one"; + if (params->w > SHRT_MAX || params->h > SHRT_MAX) + return "Neither width nor height may be unreasonably large"; ++ /* ++ * We use random_upto() to place mines, and its maximum limit is 2^28-1. ++ */ ++#if (1<<28)-1 < INT_MAX ++ if (params->w > ((1<<28)-1) / params->h) ++#else + if (params->w > INT_MAX / params->h) ++#endif + return "Width times height must not be unreasonably large"; + if (params->n < 0) + return "Mine count may not be negative"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch sgt-puzzles-20191231.79a5378/debian/patches/0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,30 @@ +From: Ben Harris +Date: Thu, 16 Feb 2023 15:54:17 +0000 +Subject: [PATCH 061/159] Solo: cope with pencil marks when tilesize == 1 +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=3cd51d001769c657ebb4184bd05343af4d7e12b1 +Bug-Debian: https://bugs.debian.org/905852 + +Solo's layout calculations for pencil marks could fail with a tilesize +of 1, generating an assertion failure: "draw_number: Assertion `pbest +> 0' failed." This was reported as Debian bug #905852. + +My solution is slightly silly, namely to change a ">" in the test for +whether a new layout is the best so far to ">=". This allows for +finding a (terrible) layout even for tilesize == 1, and also has the +side-effect of slightly preserring wide layouts over tall ones. +Personally, I think that's an improvement. +--- + solo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/solo.c ++++ b/solo.c +@@ -5105,7 +5105,7 @@ static void draw_number(drawing *dr, gam + fw = (pr - pl) / (float)pw; + fh = (pb - pt) / (float)ph; + fs = min(fw, fh); +- if (fs > bestsize) { ++ if (fs >= bestsize) { + bestsize = fs; + pbest = pw; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch sgt-puzzles-20191231.79a5378/debian/patches/0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,28 @@ +From: Chris Boyle +Date: Fri, 10 Feb 2023 15:23:33 +0000 +Subject: [PATCH 065/159] Tracks: set drag_s{x,y} even if starting off-grid +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=111db0743bd273c340dd683449076fd9ec5797f5 +Bug-Debian: https://bugs.debian.org/1034190 + +Otherwise, if subsequent mouse/finger movement lines up with the previous +drag attempt's start, then suddenly a drag is in progress from there, which +is confusing. + +Fixes #588 + +(cherry picked from Android port, +commit 8ce1bbe460d70a915caf2dbeb30354d22dc8a8ef) +--- + tracks.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/tracks.c ++++ b/tracks.c +@@ -1916,6 +1916,7 @@ static char *interpret_move(const game_s + + if (!INGRID(state, gx, gy)) { + /* can't drag from off grid */ ++ ui->drag_sx = ui->drag_sy = -1; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch sgt-puzzles-20191231.79a5378/debian/patches/0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Sat, 18 Feb 2023 21:26:38 +0000 +Subject: [PATCH 080/159] Undead: be a bit more careful about sprintf buffer + sizes +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=448095ede815b1a63ddedc602c3ac768a0d52968 +Bug-Debian: https://bugs.debian.org/1034190 + +--- + undead.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/undead.c ++++ b/undead.c +@@ -2405,7 +2405,7 @@ static void draw_monster(drawing *dr, ga + static void draw_monster_count(drawing *dr, game_drawstate *ds, + const game_state *state, int c, bool hflash) { + int dx,dy; +- char buf[8]; ++ char buf[MAX_DIGITS(int) + 1]; + char bufm[8]; + + dy = TILESIZE/4; +@@ -2450,7 +2450,7 @@ static void draw_path_hint(drawing *dr, + const struct game_params *params, + int hint_index, bool hflash, int hint) { + int x, y, color, dx, dy, text_dx, text_dy, text_size; +- char buf[4]; ++ char buf[MAX_DIGITS(int) + 1]; + + if (ds->hint_errors[hint_index]) + color = COL_ERROR; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0081-Map-add-missing-sresize-in-new_game_desc.patch sgt-puzzles-20191231.79a5378/debian/patches/0081-Map-add-missing-sresize-in-new_game_desc.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0081-Map-add-missing-sresize-in-new_game_desc.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0081-Map-add-missing-sresize-in-new_game_desc.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,30 @@ +From: Simon Tatham +Date: Sat, 11 Dec 2021 11:03:20 +0000 +Subject: [PATCH 081/389] Map: add missing sresize in new_game_desc(). +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=3e006158451a7ff8f130cbcb7dd80f165a58396e + +Every time we append to the string 'ret', we check first that there's +enough space, and realloc it larger if it's getting close to full. +Except that I missed one case at the join between the two parts of the +encoding. + +(Spotted because apparently on someone's build platform this led to a +compiler warning that 'ret' might be null. I think _that's_ not a +serious worry, but the missing resize was definitely unintentional.) +--- + map.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/map.c ++++ b/map.c +@@ -1659,6 +1659,10 @@ static char *new_game_desc(const game_pa + } + } + ++ if (retlen + 10 >= retsize) { ++ retsize = retlen + 256; ++ ret = sresize(ret, retsize, char); ++ } + ret[retlen++] = 'a'-1 + run; + ret[retlen++] = ','; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0090-Fix-memory-leak-in-midend_game_id_int.patch sgt-puzzles-20191231.79a5378/debian/patches/0090-Fix-memory-leak-in-midend_game_id_int.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0090-Fix-memory-leak-in-midend_game_id_int.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0090-Fix-memory-leak-in-midend_game_id_int.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,32 @@ +From: Ben Harris +Date: Mon, 20 Feb 2023 14:50:22 +0000 +Subject: [PATCH 090/159] Fix memory leak in midend_game_id_int() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=4e09175fdaaffc0483fc9bf767311268794d956c +Bug-Debian: https://bugs.debian.org/1034190 + +The "par" string wasn't getting freed on some error paths. Fixed by +freeing it immediately after its last use, which is before any of the +error paths. +--- + midend.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -1669,6 +1669,7 @@ static const char *midend_game_id_int(mi + newcurparams = me->ourgame->default_params(); + } + me->ourgame->decode_params(newcurparams, par); ++ sfree(par); + error = me->ourgame->validate_params(newcurparams, desc == NULL); + if (error) { + me->ourgame->free_params(newcurparams); +@@ -1744,8 +1745,6 @@ static const char *midend_game_id_int(mi + me->genmode = GOT_SEED; + } + +- sfree(par); +- + me->newgame_can_store_undo = false; + + return NULL; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch sgt-puzzles-20191231.79a5378/debian/patches/0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,35 @@ +From: Ben Harris +Date: Mon, 20 Feb 2023 14:57:31 +0000 +Subject: [PATCH 092/159] Flood: don't read off the end of some parameter + strings +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=bbe866a3819c6a754a5b1d8c5bc5d0701796acfb +Bug-Debian: https://bugs.debian.org/1034190 + +This is essentially the same fix as 73c7bc090155ab8c was for Twiddle. +The new code is less clever but more correct (and more obviously +correct). The bug could be demonstrated by using a parameter string +of "c" or "m" with an AddressSanitizer build of Flood. +--- + flood.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/flood.c ++++ b/flood.c +@@ -141,13 +141,13 @@ static void decode_params(game_params *r + if (*string == 'c') { + string++; + ret->colours = atoi(string); +- while (string[1] && isdigit((unsigned char)string[1])) string++; ++ while (*string && isdigit((unsigned char)*string)) string++; + } else if (*string == 'm') { + string++; + ret->leniency = atoi(string); +- while (string[1] && isdigit((unsigned char)string[1])) string++; +- } +- string++; ++ while (*string && isdigit((unsigned char)*string)) string++; ++ } else ++ string++; + } + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0101-Be-more-careful-with-type-of-left-operand-of.patch sgt-puzzles-20191231.79a5378/debian/patches/0101-Be-more-careful-with-type-of-left-operand-of.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0101-Be-more-careful-with-type-of-left-operand-of.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0101-Be-more-careful-with-type-of-left-operand-of.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,45 @@ +From: Ben Harris +Date: Sun, 26 Feb 2023 14:24:38 +0000 +Subject: [PATCH 101/159] Be more careful with type of left operand of << +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=93be3f7ccaa63b0fd953bcfd88d685b47b76605e +Bug-Debian: https://bugs.debian.org/1034190 + +On a 32-bit system, evaluating 1<<31 causes undefined behaviour because +1 is signed and so it produces signed overflow. UBSan has spotted a +couple of occasions where this happens in Puzzles, so in each case I've +converted the left operand to the unsigned result type we actually want. +--- + cube.c | 4 ++-- + random.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/cube.c ++++ b/cube.c +@@ -202,8 +202,8 @@ struct game_grid { + }; + + #define SET_SQUARE(state, i, val) \ +- ((state)->bluemask[(i)/32] &= ~(1 << ((i)%32)), \ +- (state)->bluemask[(i)/32] |= ((!!val) << ((i)%32))) ++ ((state)->bluemask[(i)/32] &= ~(1UL << ((i)%32)), \ ++ (state)->bluemask[(i)/32] |= ((unsigned long)(!!val) << ((i)%32))) + #define GET_SQUARE(state, i) \ + (((state)->bluemask[(i)/32] >> ((i)%32)) & 1) + +--- a/random.c ++++ b/random.c +@@ -254,12 +254,12 @@ unsigned long random_bits(random_state * + } + + /* +- * `(1 << bits) - 1' is not good enough, since if bits==32 on a ++ * `(1UL << bits) - 1' is not good enough, since if bits==32 on a + * 32-bit machine, behaviour is undefined and Intel has a nasty + * habit of shifting left by zero instead. We'll shift by + * bits-1 and then separately shift by one. + */ +- ret &= (1 << (bits-1)) * 2 - 1; ++ ret &= (1UL << (bits-1)) * 2 - 1; + return ret; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0102-Map-reduce-maximum-size.patch sgt-puzzles-20191231.79a5378/debian/patches/0102-Map-reduce-maximum-size.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0102-Map-reduce-maximum-size.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0102-Map-reduce-maximum-size.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,23 @@ +From: Ben Harris +Date: Sun, 26 Feb 2023 14:51:09 +0000 +Subject: [PATCH 102/159] Map: reduce maximum size +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e2d390aae872cee4cb16d746af3b2eeb7713cbf5 +Bug-Debian: https://bugs.debian.org/1034190 + +validate_desc relies on being able to calculate 2*wh in an int, so the +maximum grid size is at most INT_MAX/2. +--- + map.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/map.c ++++ b/map.c +@@ -255,7 +255,7 @@ static const char *validate_params(const + { + if (params->w < 2 || params->h < 2) + return "Width and height must be at least two"; +- if (params->w > INT_MAX / params->h) ++ if (params->w > INT_MAX / 2 / params->h) + return "Width times height must not be unreasonably large"; + if (params->n < 5) + return "Must have at least five regions"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0103-Correctly-handle-some-short-save-files.patch sgt-puzzles-20191231.79a5378/debian/patches/0103-Correctly-handle-some-short-save-files.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0103-Correctly-handle-some-short-save-files.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0103-Correctly-handle-some-short-save-files.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,40 @@ +From: Ben Harris +Date: Sun, 26 Feb 2023 21:48:10 +0000 +Subject: [PATCH 103/159] Correctly handle some short save files +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=6ee62a43abe7d7e77226415b21d1cbf16dbda85a +Bug-Debian: https://bugs.debian.org/1034190 + +A save file that ended in the middle of a value before the "SAVEFILE" +field had been loaded would cause a read from uninitialised memory. +While technically undefined behaviour this was practically pretty +harmless. Fixed by handling unexpected EOF here the same an +unexpected EOF anywhere else. + +This bug could be demonstrated by loading a truncated save file like +this in a build with MemorySanitizer enabled: + +SAVEFILE:41:Simo +--- + midend.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -2192,7 +2192,7 @@ static const char *midend_deserialise_in + + val = snewn(len+1, char); + if (!read(rctx, val, len)) { +- if (started) ++ /* unexpected EOF */ + goto cleanup; + } + val[len] = '\0'; +@@ -2597,7 +2597,7 @@ const char *identify_game(char **name, + + val = snewn(len+1, char); + if (!read(rctx, val, len)) { +- if (started) ++ /* unexpected EOF */ + goto cleanup; + } + val[len] = '\0'; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0104-Inertia-insist-that-solutions-must-be-non-empty.patch sgt-puzzles-20191231.79a5378/debian/patches/0104-Inertia-insist-that-solutions-must-be-non-empty.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0104-Inertia-insist-that-solutions-must-be-non-empty.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0104-Inertia-insist-that-solutions-must-be-non-empty.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,29 @@ +From: Ben Harris +Date: Sun, 26 Feb 2023 23:18:44 +0000 +Subject: [PATCH 104/159] Inertia: insist that solutions must be non-empty +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5a491c5ad333ef34c1e7713f920f51cbb205af60 +Bug-Debian: https://bugs.debian.org/1034190 + +Any solution actually generated by the solver will contain at least one +move, because it refuses to solve games that are already solved. +However, a save file might contain an empty "solve" move. This causes +an uninitialised read when execute_move() then tries to check if the +next move is in accordance with the solution, because the check for +running off the end of the solution happens after that. + +We now avoid this by treating a zero-length "solution" as an invalid +move. +--- + inertia.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/inertia.c ++++ b/inertia.c +@@ -1688,6 +1688,7 @@ static game_state *execute_move(const ga + * This is a solve move, so we don't actually _change_ the + * grid but merely set up a stored solution path. + */ ++ if (move[1] == '\0') return NULL; /* Solution must be non-empty. */ + ret = dup_game(state); + install_new_solution(ret, move); + return ret; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0114-Add-more-validation-to-midend-deserialisation-routin.patch sgt-puzzles-20191231.79a5378/debian/patches/0114-Add-more-validation-to-midend-deserialisation-routin.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0114-Add-more-validation-to-midend-deserialisation-routin.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0114-Add-more-validation-to-midend-deserialisation-routin.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,98 @@ +From: Ben Harris +Date: Sun, 16 Oct 2022 18:31:54 +0100 +Subject: [PATCH 114/389] Add more validation to midend deserialisation routine +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=02e5e93046d1ee2ce7acde629a6562db9b36fa5d + +These are all pretty obvious and enforce constraints that would +otherwise be enforced by segfault. +--- + midend.c | 45 +++++++++++++++++++++++++++++---------------- + 1 file changed, 29 insertions(+), 16 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -2205,15 +2205,15 @@ static const char *midend_deserialise_in + } else if (!strcmp(key, "TIME")) { + data.elapsed = (float)atof(val); + } else if (!strcmp(key, "NSTATES")) { ++ if (data.states) { ++ ret = "Two state counts provided in save file"; ++ goto cleanup; ++ } + data.nstates = atoi(val); + if (data.nstates <= 0) { + ret = "Number of states in save file was negative"; + goto cleanup; + } +- if (data.states) { +- ret = "Two state counts provided in save file"; +- goto cleanup; +- } + data.states = snewn(data.nstates, struct midend_state_entry); + for (i = 0; i < data.nstates; i++) { + data.states[i].state = NULL; +@@ -2222,19 +2222,20 @@ static const char *midend_deserialise_in + } + } else if (!strcmp(key, "STATEPOS")) { + data.statepos = atoi(val); +- } else if (!strcmp(key, "MOVE")) { +- gotstates++; +- data.states[gotstates].movetype = MOVE; +- data.states[gotstates].movestr = val; +- val = NULL; +- } else if (!strcmp(key, "SOLVE")) { +- gotstates++; +- data.states[gotstates].movetype = SOLVE; +- data.states[gotstates].movestr = val; +- val = NULL; +- } else if (!strcmp(key, "RESTART")) { ++ } else if (!strcmp(key, "MOVE") || ++ !strcmp(key, "SOLVE") || ++ !strcmp(key, "RESTART")) { ++ if (!data.states) { ++ ret = "No state count provided in save file"; ++ goto cleanup; ++ } + gotstates++; +- data.states[gotstates].movetype = RESTART; ++ if (!strcmp(key, "MOVE")) ++ data.states[gotstates].movetype = MOVE; ++ else if (!strcmp(key, "SOLVE")) ++ data.states[gotstates].movetype = SOLVE; ++ else ++ data.states[gotstates].movetype = RESTART; + data.states[gotstates].movestr = val; + val = NULL; + } +@@ -2245,12 +2246,20 @@ static const char *midend_deserialise_in + } + + data.params = me->ourgame->default_params(); ++ if (!data.parstr) { ++ ret = "Long-term parameters in save file are missing"; ++ goto cleanup; ++ } + me->ourgame->decode_params(data.params, data.parstr); + if (me->ourgame->validate_params(data.params, true)) { + ret = "Long-term parameters in save file are invalid"; + goto cleanup; + } + data.cparams = me->ourgame->default_params(); ++ if (!data.cparstr) { ++ ret = "Short-term parameters in save file are missing"; ++ goto cleanup; ++ } + me->ourgame->decode_params(data.cparams, data.cparstr); + if (me->ourgame->validate_params(data.cparams, false)) { + ret = "Short-term parameters in save file are invalid"; +@@ -2280,6 +2289,10 @@ static const char *midend_deserialise_in + ret = "Game position in save file is out of range"; + } + ++ if (!data.states) { ++ ret = "No state count provided in save file"; ++ goto cleanup; ++ } + data.states[0].state = me->ourgame->new_game( + me, data.cparams, data.privdesc ? data.privdesc : data.desc); + for (i = 1; i < data.nstates; i++) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0115-Correct-and-enable-the-range-check-on-statepos-when-.patch sgt-puzzles-20191231.79a5378/debian/patches/0115-Correct-and-enable-the-range-check-on-statepos-when-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0115-Correct-and-enable-the-range-check-on-statepos-when-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0115-Correct-and-enable-the-range-check-on-statepos-when-.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,35 @@ +From: Ben Harris +Date: Sun, 16 Oct 2022 19:14:24 +0100 +Subject: [PATCH 115/389] Correct and enable the range check on statepos when + loading +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=1bab1d1d2ab472bb8fc7cddfce1d3c37e63a2ed5 + +statepos == 0 shouldn't ever occur in a save file because it indicates +an uninitialised midend. OTOH statepos == nstates is normal. Also +added an equivalent assertion when saving because Simon and I spent +some time discussing whether it could happen. +--- + midend.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/midend.c ++++ b/midend.c +@@ -2031,6 +2031,7 @@ void midend_serialise(midend *me, + char buf[80]; + sprintf(buf, "%d", me->nstates); + wr("NSTATES", buf); ++ assert(me->statepos >= 1 && me->statepos <= me->nstates); + sprintf(buf, "%d", me->statepos); + wr("STATEPOS", buf); + } +@@ -2285,8 +2286,9 @@ static const char *midend_deserialise_in + ret = "Game private description in save file is invalid"; + goto cleanup; + } +- if (data.statepos < 0 || data.statepos >= data.nstates) { ++ if (data.statepos < 1 || data.statepos > data.nstates) { + ret = "Game position in save file is out of range"; ++ goto cleanup; + } + + if (!data.states) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0115-Galaxies-fix-recursion-depth-limit-in-solver.patch sgt-puzzles-20191231.79a5378/debian/patches/0115-Galaxies-fix-recursion-depth-limit-in-solver.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0115-Galaxies-fix-recursion-depth-limit-in-solver.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0115-Galaxies-fix-recursion-depth-limit-in-solver.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,89 @@ +From: Simon Tatham +Date: Sun, 12 Mar 2023 14:11:34 +0000 +Subject: [PATCH 115/159] Galaxies: fix recursion depth limit in solver. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=f018ef97d34b9126744e63cc2112c302fcae4ab4 +Bug-Debian: https://bugs.debian.org/1034190 + +The static variable 'solver_recurse_depth' is _mostly_ used by the +standalone solver, to appropriately indent the solver diagnostics for +the current recursion level. So most uses of it are guarded by an +'#ifdef STANDALONE_SOLVER' statement, or some equivalent (such as +being inside the solvep() macro). + +One exception is the check that limits the recursion depth to 5, to +avoid getting hung up forever on a too-hard game. Unfortunately, this +check depends on the variable actually incrementing when we recurse +another level - and it wasn't, because the increment itself was under +ifdef! So the generator in live Galaxies could recurse arbitrarily +deep, and generate puzzles that the standalone solver found too hard +_even_ at Unreasonable mode. + +Removed the ifdefs, so that solver_recurse_depth is now incremented +and decremented. Also, make sure to initialise the depth to 0 at the +start of a solver run, just in case it had a bogus value left over +from a previous run. +--- + galaxies.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/galaxies.c ++++ b/galaxies.c +@@ -150,6 +150,7 @@ struct game_state { + }; + + static bool check_complete(const game_state *state, int *dsf, int *colours); ++static int solver_state_inner(game_state *state, int maxdiff); + static int solver_state(game_state *state, int maxdiff); + static int solver_obvious(game_state *state); + static int solver_obvious_dot(game_state *state, space *dot); +@@ -2156,9 +2157,7 @@ static int solver_recurse(game_state *st + solver_recurse_depth*4, "", + rctx.best->x, rctx.best->y, rctx.bestn)); + +-#ifdef STANDALONE_SOLVER + solver_recurse_depth++; +-#endif + + ingrid = snewn(gsz, space); + memcpy(ingrid, state->grid, gsz * sizeof(space)); +@@ -2173,7 +2172,7 @@ static int solver_recurse(game_state *st + state->dots[n]->x, state->dots[n]->y, + "Attempting for recursion"); + +- ret = solver_state(state, maxdiff); ++ ret = solver_state_inner(state, maxdiff); + + if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) { + /* we found our first solved grid; copy it away. */ +@@ -2205,9 +2204,7 @@ static int solver_recurse(game_state *st + break; + } + +-#ifdef STANDALONE_SOLVER + solver_recurse_depth--; +-#endif + + if (outgrid) { + /* we found (at least one) soln; copy it back to state */ +@@ -2218,7 +2215,7 @@ static int solver_recurse(game_state *st + return diff; + } + +-static int solver_state(game_state *state, int maxdiff) ++static int solver_state_inner(game_state *state, int maxdiff) + { + solver_ctx *sctx = new_solver(state); + int ret, diff = DIFF_NORMAL; +@@ -2282,6 +2279,12 @@ got_result: + return diff; + } + ++static int solver_state(game_state *state, int maxdiff) ++{ ++ solver_recurse_depth = 0; ++ return solver_state_inner(state, maxdiff); ++} ++ + #ifndef EDITOR + static char *solve_game(const game_state *state, const game_state *currstate, + const char *aux, const char **error) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch sgt-puzzles-20191231.79a5378/debian/patches/0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,134 @@ +From: Ben Harris +Date: Sat, 15 Oct 2022 20:46:28 +0100 +Subject: [PATCH 121/389] Add an assertion to check the format of encoded + parameters +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e29d8a3ecad734967cdcf2d4ce222ab27e9c524b + +Whenever the midend calls encode_params, it also checks that the +result is a printable ASCII string that doesn't contain '#' or ':'. + +Parameter strings are embedded in save files, so they have to fit within +ASCII. They can't contain '#' or ':' because those delimit the +parameter section of a game ID. Nothing explicitly says they can't +contain control characters, but those would be a particularly egregious +violation of the recommendation that parameter strings be easy to type +into a shell. +--- + midend.c | 36 +++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -380,6 +380,18 @@ game_params *midend_get_params(midend *m + return me->ourgame->dup_params(me->params); + } + ++static char *encode_params(midend *me, const game_params *params, bool full) ++{ ++ char *encoded = me->ourgame->encode_params(params, full); ++ ++ /* Assert that the params consist of printable ASCII containing ++ * neither '#' nor ':'. */ ++ for (int i = 0; encoded[i]; i++) ++ assert(encoded[i] >= 32 && encoded[i] < 127 && ++ encoded[i] != '#' && encoded[i] != ':'); ++ return encoded; ++} ++ + static void midend_set_timer(midend *me) + { + me->timing = (me->ourgame->is_timed && +@@ -613,8 +626,8 @@ static const char *newgame_undo_deserial + * We check both params and cparams, to be as safe as possible. + */ + +- old = me->ourgame->encode_params(me->params, true); +- new = me->ourgame->encode_params(data->params, true); ++ old = encode_params(me, me->params, true); ++ new = encode_params(me, data->params, true); + if (strcmp(old, new)) { + /* Set a flag to distinguish this deserialise failure + * from one due to faulty decoding */ +@@ -622,8 +635,8 @@ static const char *newgame_undo_deserial + return "Undoing this new-game operation would change params"; + } + +- old = me->ourgame->encode_params(me->curparams, true); +- new = me->ourgame->encode_params(data->cparams, true); ++ old = encode_params(me, me->curparams, true); ++ new = encode_params(me, data->cparams, true); + if (strcmp(old, new)) { + ctx->refused = true; + return "Undoing this new-game operation would change params"; +@@ -1359,7 +1372,7 @@ static void preset_menu_encode_params(mi + for (i = 0; i < menu->n_entries; i++) { + if (menu->entries[i].params) { + me->encoded_presets[menu->entries[i].id] = +- me->ourgame->encode_params(menu->entries[i].params, true); ++ encode_params(me, menu->entries[i].params, true); + } else { + preset_menu_encode_params(me, menu->entries[i].submenu); + } +@@ -1438,7 +1451,7 @@ struct preset_menu *midend_get_presets(m + + int midend_which_preset(midend *me) + { +- char *encoding = me->ourgame->encode_params(me->params, true); ++ char *encoding = encode_params(me, me->params, true); + int i, ret; + + ret = -1; +@@ -1516,7 +1529,7 @@ config_item *midend_get_config(midend *m + * the former is likely to persist across many code + * changes). + */ +- parstr = me->ourgame->encode_params(me->curparams, which == CFG_SEED); ++ parstr = encode_params(me, me->curparams, which == CFG_SEED); + assert(parstr); + if (which == CFG_DESC) { + rest = me->desc ? me->desc : ""; +@@ -1660,7 +1673,7 @@ static const char *midend_game_id_int(mi + + newparams = me->ourgame->dup_params(me->params); + +- tmpstr = me->ourgame->encode_params(newcurparams, false); ++ tmpstr = encode_params(me, newcurparams, false); + me->ourgame->decode_params(newparams, tmpstr); + + sfree(tmpstr); +@@ -1732,7 +1745,7 @@ char *midend_get_game_id(midend *me) + { + char *parstr, *ret; + +- parstr = me->ourgame->encode_params(me->curparams, false); ++ parstr = encode_params(me, me->curparams, false); + assert(parstr); + assert(me->desc); + ret = snewn(strlen(parstr) + strlen(me->desc) + 2, char); +@@ -1748,7 +1761,7 @@ char *midend_get_random_seed(midend *me) + if (!me->seedstr) + return NULL; + +- parstr = me->ourgame->encode_params(me->curparams, true); ++ parstr = encode_params(me, me->curparams, true); + assert(parstr); + ret = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char); + sprintf(ret, "%s#%s", parstr, me->seedstr); +@@ -1957,7 +1970,7 @@ void midend_serialise(midend *me, + * The current long-term parameters structure, in full. + */ + if (me->params) { +- char *s = me->ourgame->encode_params(me->params, true); ++ char *s = encode_params(me, me->params, true); + wr("PARAMS", s); + sfree(s); + } +@@ -1966,7 +1979,7 @@ void midend_serialise(midend *me, + * The current short-term parameters structure, in full. + */ + if (me->curparams) { +- char *s = me->ourgame->encode_params(me->curparams, true); ++ char *s = encode_params(me, me->curparams, true); + wr("CPARAMS", s); + sfree(s); + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0122-Add-assertions-that-game-descriptions-consist-only-o.patch sgt-puzzles-20191231.79a5378/debian/patches/0122-Add-assertions-that-game-descriptions-consist-only-o.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0122-Add-assertions-that-game-descriptions-consist-only-o.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0122-Add-assertions-that-game-descriptions-consist-only-o.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,73 @@ +From: Ben Harris +Date: Sat, 15 Oct 2022 21:25:08 +0100 +Subject: [PATCH 122/389] Add assertions that game descriptions consist only of + printable ASCII. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=9f2eef876275a451b015c22961130b2e507ddd49 + +That they are ASCII is implied by their inclusion in save files. +Nothing requires an absence of control characters, but it seems polite +to make them slightly readable. +--- + midend.c | 16 ++++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/midend.c ++++ b/midend.c +@@ -392,6 +392,14 @@ static char *encode_params(midend *me, c + return encoded; + } + ++static void assert_printable_ascii(char const *s) ++{ ++ /* Assert that s is entirely printable ASCII, and hence safe for ++ * writing in a save file. */ ++ for (int i = 0; s[i]; i++) ++ assert(s[i] >= 32 && s[i] < 127); ++} ++ + static void midend_set_timer(midend *me) + { + me->timing = (me->ourgame->is_timed && +@@ -499,6 +507,7 @@ void midend_new_game(midend *me) + */ + me->desc = me->ourgame->new_desc(me->curparams, rs, + &me->aux_info, (me->drawing != NULL)); ++ assert_printable_ascii(me->desc); + me->privdesc = NULL; + random_free(rs); + } +@@ -921,6 +930,7 @@ static bool midend_really_process_key(mi + if (movestr == UI_UPDATE) + s = me->states[me->statepos-1].state; + else { ++ assert_printable_ascii(movestr); + s = me->ourgame->execute_move(me->states[me->statepos-1].state, + movestr); + assert(s != NULL); +@@ -1479,6 +1489,10 @@ void midend_request_id_changes(midend *m + void midend_supersede_game_desc(midend *me, const char *desc, + const char *privdesc) + { ++ /* Assert that the descriptions consists only of printable ASCII. */ ++ assert_printable_ascii(desc); ++ if (privdesc) ++ assert_printable_ascii(privdesc); + sfree(me->desc); + sfree(me->privdesc); + me->desc = dupstr(desc); +@@ -1838,6 +1852,7 @@ const char *midend_solve(midend *me) + msg = "Solve operation failed"; /* _shouldn't_ happen, but can */ + return msg; + } ++ assert_printable_ascii(movestr); + s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); + assert(s); + +@@ -2021,6 +2036,7 @@ void midend_serialise(midend *me, + */ + if (me->ui) { + char *s = me->ourgame->encode_ui(me->ui); ++ assert_printable_ascii(s); + if (s) { + wr("UI", s); + sfree(s); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch sgt-puzzles-20191231.79a5378/debian/patches/0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,67 @@ +From: Ben Harris +Date: Mon, 17 Oct 2022 00:56:37 +0100 +Subject: [PATCH 123/389] Hex-encode non-ASCII random seeds in save files +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=304796f9f184a783d0af21e445c690ed69de048b + +The developer documentation claims that save files are long ASCII +strings. This is mostly true, but there's nothing stopping a user +from entering non-ASCII characters as random seeds. The ASCII +property of save files is useful, so encode seeds in hex before +writing them unless they consist only of printable ASCII characters. + +Hex-encoded seeds are written under a new key, HEXSEED, to distinguish +them from unencoded seeds. This means that old versions of the code +won't be able to load encoded seeds, but that's not a great loss: +seeds aren't generally portable between versions anyway. +--- + midend.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -2001,8 +2001,27 @@ void midend_serialise(midend *me, + /* + * The current game description, the privdesc, and the random seed. + */ +- if (me->seedstr) +- wr("SEED", me->seedstr); ++ if (me->seedstr) { ++ /* ++ * Random seeds are not necessarily printable ASCII. ++ * Hex-encode the seed if necessary. Printable ASCII seeds ++ * are emitted unencoded for compatibility with older ++ * versions. ++ */ ++ int i; ++ ++ for (i = 0; me->seedstr[i]; i++) ++ if (me->seedstr[i] < 32 || me->seedstr[i] >= 127) ++ break; ++ if (me->seedstr[i]) { ++ char *hexseed = bin2hex((unsigned char *)me->seedstr, ++ strlen(me->seedstr)); ++ ++ wr("HEXSEED", hexseed); ++ sfree(hexseed); ++ } else ++ wr("SEED", me->seedstr); ++ } + if (me->desc) + wr("DESC", me->desc); + if (me->privdesc) +@@ -2204,6 +2223,15 @@ static const char *midend_deserialise_in + sfree(data.cparstr); + data.cparstr = val; + val = NULL; ++ } else if (!strcmp(key, "HEXSEED")) { ++ unsigned char *tmp; ++ int len = strlen(val) / 2; /* length in bytes */ ++ tmp = hex2bin(val, len); ++ sfree(data.seed); ++ data.seed = snewn(len + 1, char); ++ memcpy(data.seed, tmp, len); ++ data.seed[len] = '\0'; ++ sfree(tmp); + } else if (!strcmp(key, "SEED")) { + sfree(data.seed); + data.seed = val; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0124-Assert-that-everything-written-to-a-save-file-is-pri.patch sgt-puzzles-20191231.79a5378/debian/patches/0124-Assert-that-everything-written-to-a-save-file-is-pri.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0124-Assert-that-everything-written-to-a-save-file-is-pri.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0124-Assert-that-everything-written-to-a-save-file-is-pri.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Mon, 17 Oct 2022 00:59:18 +0100 +Subject: [PATCH 124/389] Assert that everything written to a save file is + printable ASCII +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=7f4d038258d2bd585a0dce87177bf429d168ffb5 + +Apart from the newlines of course. +--- + midend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/midend.c ++++ b/midend.c +@@ -1959,7 +1959,9 @@ void midend_serialise(midend *me, + char lbuf[9]; \ + copy_left_justified(lbuf, sizeof(lbuf), h); \ + sprintf(hbuf, "%s:%d:", lbuf, (int)strlen(str)); \ ++ assert_printable_ascii(hbuf); \ + write(wctx, hbuf, strlen(hbuf)); \ ++ assert_printable_ascii(str); \ + write(wctx, str, strlen(str)); \ + write(wctx, "\n", 1); \ + } while (0) +@@ -2055,7 +2057,6 @@ void midend_serialise(midend *me, + */ + if (me->ui) { + char *s = me->ourgame->encode_ui(me->ui); +- assert_printable_ascii(s); + if (s) { + wr("UI", s); + sfree(s); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0129-Build-fix-take-declarations-out-of-for-loops.patch sgt-puzzles-20191231.79a5378/debian/patches/0129-Build-fix-take-declarations-out-of-for-loops.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0129-Build-fix-take-declarations-out-of-for-loops.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0129-Build-fix-take-declarations-out-of-for-loops.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,35 @@ +From: Simon Tatham +Date: Fri, 21 Oct 2022 07:52:14 +0100 +Subject: [PATCH 129/389] Build fix: take declarations out of for loops. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=373dadacc06210197e3d68c55a6d611126915120 + +The NestedVM build is still unhappy with this C99ism, unfortunately. +--- + midend.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -383,10 +383,11 @@ game_params *midend_get_params(midend *m + static char *encode_params(midend *me, const game_params *params, bool full) + { + char *encoded = me->ourgame->encode_params(params, full); ++ int i; + + /* Assert that the params consist of printable ASCII containing + * neither '#' nor ':'. */ +- for (int i = 0; encoded[i]; i++) ++ for (i = 0; encoded[i]; i++) + assert(encoded[i] >= 32 && encoded[i] < 127 && + encoded[i] != '#' && encoded[i] != ':'); + return encoded; +@@ -396,7 +397,8 @@ static void assert_printable_ascii(char + { + /* Assert that s is entirely printable ASCII, and hence safe for + * writing in a save file. */ +- for (int i = 0; s[i]; i++) ++ int i; ++ for (i = 0; s[i]; i++) + assert(s[i] >= 32 && s[i] < 127); + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0138-Correct-a-range-check-in-Magnets-layout-verification.patch sgt-puzzles-20191231.79a5378/debian/patches/0138-Correct-a-range-check-in-Magnets-layout-verification.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0138-Correct-a-range-check-in-Magnets-layout-verification.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0138-Correct-a-range-check-in-Magnets-layout-verification.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,24 @@ +From: Ben Harris +Date: Fri, 31 Mar 2023 20:38:31 +0100 +Subject: [PATCH 138/159] Correct a range check in Magnets' layout verification +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=91735e5019be84d2fa693c5d40746c818ace28f8 +Bug-Debian: https://bugs.debian.org/1034190 + +Squares in the grid are numbered from 0, so the upper limit check +needs to use "<=" rather than "<". Without this, invalid descriptions +can cause a read overrun off the end of the board. +--- + magnets.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/magnets.c ++++ b/magnets.c +@@ -520,7 +520,7 @@ nextchar: + * (i.e. each end points to the other) */ + for (idx = 0; idx < state->wh; idx++) { + if (state->common->dominoes[idx] < 0 || +- state->common->dominoes[idx] > state->wh || ++ state->common->dominoes[idx] >= state->wh || + state->common->dominoes[state->common->dominoes[idx]] != idx) { + *prob = "Domino descriptions inconsistent"; + goto done; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch sgt-puzzles-20191231.79a5378/debian/patches/0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Sat, 1 Apr 2023 18:54:29 +0100 +Subject: [PATCH 139/159] Magnets: add a check that magnets don't wrap between + lines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0bd1a8057841386754f9f4a8a268616c7ce80e80 +Bug-Debian: https://bugs.debian.org/1034190 + +There was nothing in Magnet's description validation to prevent there +being the left end of a magnet at the right end of a row and the right +end of a magnet at the left end of the row below. Indeed as far as I +can such a game (e.g. 3x3:..2,2..,...,1.1,TLRB*LRLR) plays entirely +correctly except that one magnet is discontinuous. + +While this worked, it was entirely an artefact of the particular memory +layout that Magnets uses and shouldn't have been allowed, so I've added +an additional validation rule to stop it. +--- + magnets.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/magnets.c ++++ b/magnets.c +@@ -521,6 +521,8 @@ nextchar: + for (idx = 0; idx < state->wh; idx++) { + if (state->common->dominoes[idx] < 0 || + state->common->dominoes[idx] >= state->wh || ++ (state->common->dominoes[idx] % state->w != idx % state->w && ++ state->common->dominoes[idx] / state->w != idx / state->w) || + state->common->dominoes[state->common->dominoes[idx]] != idx) { + *prob = "Domino descriptions inconsistent"; + goto done; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch sgt-puzzles-20191231.79a5378/debian/patches/0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,38 @@ +From: Ben Harris +Date: Mon, 13 Feb 2023 22:14:26 +0000 +Subject: [PATCH 155/159] Net: assert that cx and cy are in range in + compute_active() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e411db788cfc0d0ed54b3c9b9deb15edba7d237a +Bug-Debian: https://bugs.debian.org/1034190 + +This avoids an out-of-range heap write shortly afterwards. An assertion +failure is better than a buffer overrun, but still not ideal. Fixing +the problem properly will require fairly wide-ranging changes, though. + +The bug can be demonstrated by loading this save file into a build with +AddressSanitizer: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :3:Net +PARAMS :4:5x5w +CPARAMS :4:5x5w +DESC :25:9893e85285bb72e6de5182741 +UI :9:O0,0;C6,6 +NSTATES :1:1 +STATEPOS:1:1 +--- + net.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net.c ++++ b/net.c +@@ -1878,6 +1878,8 @@ static unsigned char *compute_active(con + active = snewn(state->width * state->height, unsigned char); + memset(active, 0, state->width * state->height); + ++ assert(0 <= cx && cx < state->width); ++ assert(0 <= cy && cy < state->height); + /* + * We only store (x,y) pairs in todo, but it's easier to reuse + * xyd_cmp and just store direction 0 every time. diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0159-Don-t-allow-zero-clues-in-Pattern.patch sgt-puzzles-20191231.79a5378/debian/patches/0159-Don-t-allow-zero-clues-in-Pattern.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0159-Don-t-allow-zero-clues-in-Pattern.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0159-Don-t-allow-zero-clues-in-Pattern.patch 2023-04-23 19:12:52.000000000 +0000 @@ -0,0 +1,34 @@ +From: Ben Harris +Date: Tue, 14 Feb 2023 13:16:53 +0000 +Subject: [PATCH 159/159] Don't allow zero clues in Pattern +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=71cf891fdc3ab237ecf0e5d1aae39b6c9fe97a4d +Bug-Debian: https://bugs.debian.org/1034190 + +Some nonogram implementations allow zero clues so that a row or column +with a single zero clue is equivalent to one with no clues, that is it +has no black squares in it. Pattern, however, doesn't interpret them +like this and treats a puzzle with a zero clue as insoluble, so it's +not helpful to permit them. + +Permitting zero clues also confuses Pattern's memory allocation so +that it can suffer a buffer overrun. As an example, before this +commit a build with AddressSanitizer would report a buffer overrun +with the description "1:0/0.0" because it tries to put two clues in a +row that can have a maximum of one. +--- + pattern.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/pattern.c ++++ b/pattern.c +@@ -912,8 +912,8 @@ static const char *validate_desc(const g + p = desc; + while (*desc && isdigit((unsigned char)*desc)) desc++; + n = atoi(p); +- if (n < 0) +- return "at least one clue is negative"; ++ if (n <= 0) ++ return "all clues must be positive"; + if (n > INT_MAX - 1) + return "at least one clue is grossly excessive"; + rowspace -= n+1; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch sgt-puzzles-20191231.79a5378/debian/patches/0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,63 @@ +From: Ben Harris +Date: Wed, 7 Dec 2022 18:43:34 +0000 +Subject: [PATCH 246/389] galaxies: Use the same code for handling all dropped + arrows +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0b036c9e79578cec5425aaca1b1af13a4ae0d937 + +The keyboard code was prone to adding null items to the undo history, +and was also unreadable. Rather than fix it, I've replaced it with a +jump to the mouse drop handling, lightly enhanced to reject drops on +things that aren't tiles. +--- + galaxies.c | 20 ++++++-------------- + 1 file changed, 6 insertions(+), 14 deletions(-) + +--- a/galaxies.c ++++ b/galaxies.c +@@ -352,6 +352,8 @@ static bool ok_to_add_assoc_with_opposit + int *colors; + bool toret; + ++ if (tile->type != s_tile) ++ return false; + if (tile->flags & F_DOT) + return false; + if (opposite == NULL) +@@ -2583,14 +2585,14 @@ static char *interpret_move(const game_s + ui->dy = y; + return UI_UPDATE; + } else if (button == RIGHT_RELEASE && ui->dragging) { +- ui->dragging = false; +- + /* + * Drags are always targeted at a single square. + */ + px = 2*FROMCOORD(x+TILE_SIZE) - 1; + py = 2*FROMCOORD(y+TILE_SIZE) - 1; + ++ dropped: /* We arrive here from the end of a keyboard drag. */ ++ ui->dragging = false; + /* + * Dragging an arrow on to the same square it started from + * is a null move; just update the ui and finish. +@@ -2648,18 +2650,8 @@ static char *interpret_move(const game_s + } + sp = &SPACE(state, ui->cur_x, ui->cur_y); + if (ui->dragging) { +- ui->dragging = false; +- +- if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) && +- SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) { +- sprintf(buf, "%sU%d,%d", sep, ui->srcx, ui->srcy); +- sep = ";"; +- } +- if (sp->type == s_tile && !(sp->flags & F_DOT) && !(sp->flags & F_TILE_ASSOC)) { +- sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d", +- sep, ui->cur_x, ui->cur_y, ui->dotx, ui->doty); +- } +- return dupstr(buf); ++ px = ui->cur_x; py = ui->cur_y; ++ goto dropped; + } else if (sp->flags & F_DOT) { + ui->dragging = true; + ui->dx = SCOORD(ui->cur_x); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0263-magnets-Area-constraints-fix-message.patch sgt-puzzles-20191231.79a5378/debian/patches/0263-magnets-Area-constraints-fix-message.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0263-magnets-Area-constraints-fix-message.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0263-magnets-Area-constraints-fix-message.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,37 @@ +From: Chris Boyle +Date: Tue, 20 Dec 2016 09:13:20 +0000 +Subject: [PATCH 263/389] magnets: Area constraints; fix message. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=69e63a810e0bd6f85a46d8490c6e366237e061ef + +(The restriction on 2x2 puzzles is because the board layer-out doesn't +use neutral pieces on such small boards, and the only soluble 2x2 boards +have neutral pieces. I haven't investigated the Tricky size limit, but +it seems entirely reasonable that all the smaller boards are too easy. +--bjh21) + +(cherry picked from Android port, commit +133794977a13767e0c1596be6a5b26f2cf2d1fd1) +--- + magnets.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/magnets.c ++++ b/magnets.c +@@ -230,8 +230,15 @@ static game_params *custom_params(const + + static const char *validate_params(const game_params *params, bool full) + { +- if (params->w < 2) return "Width must be at least one"; +- if (params->h < 2) return "Height must be at least one"; ++ if (params->w < 2) return "Width must be at least two"; ++ if (params->h < 2) return "Height must be at least two"; ++ if (params->diff >= DIFF_TRICKY) { ++ if (params->w < 5 && params->h < 5) ++ return "Either width or height must be at least five for Tricky"; ++ } else { ++ if (params->w < 3 && params->h < 3) ++ return "Either width or height must be at least three"; ++ } + if (params->diff < 0 || params->diff >= DIFFCOUNT) + return "Unknown difficulty level"; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0266-lightup-Ban-2x2-with-either-4-way-type.patch sgt-puzzles-20191231.79a5378/debian/patches/0266-lightup-Ban-2x2-with-either-4-way-type.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0266-lightup-Ban-2x2-with-either-4-way-type.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0266-lightup-Ban-2x2-with-either-4-way-type.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,25 @@ +From: Chris Boyle +Date: Tue, 20 Dec 2016 23:48:01 +0000 +Subject: [PATCH 266/389] lightup: Ban 2x2 with either 4-way type +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=cbf2ede64ad91346e6399603ff7b8df432be5a06 + +(2x2 with four-way symmetry must be either all-black (trivial) or +all-white (ambiguous). --bjh21) + +(cherry picked from Android port, commit +27ae898e118b0a31a98d393bf56aa138845123e6) +--- + lightup.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/lightup.c ++++ b/lightup.c +@@ -353,6 +353,8 @@ static const char *validate_params(const + if (params->symm == SYMM_ROT4) + return "4-fold symmetry is only available with square grids"; + } ++ if ((params->symm == SYMM_ROT4 || params->symm == SYMM_REF4) && params->w < 3 && params->h < 3) ++ return _("Width or height must be at least 3 for 4-way symmetry"); + if (params->symm < 0 || params->symm >= SYMM_MAX) + return "Unknown symmetry type"; + if (params->difficulty < 0 || params->difficulty > DIFFCOUNT) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0267-Remove-_-introduced-from-Android-port.patch sgt-puzzles-20191231.79a5378/debian/patches/0267-Remove-_-introduced-from-Android-port.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0267-Remove-_-introduced-from-Android-port.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0267-Remove-_-introduced-from-Android-port.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,22 @@ +From: Jacob Nevins +Date: Fri, 16 Dec 2022 11:17:29 +0000 +Subject: [PATCH 267/389] Remove _() introduced from Android port. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0d43753ff2e02f54dd35e6872be3dafa14d2ea7d + +Introduced in cbf2ede64a. It's used there for marking up text for i18n +in a gettext stylee, but is not available here. +--- + lightup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lightup.c ++++ b/lightup.c +@@ -354,7 +354,7 @@ static const char *validate_params(const + return "4-fold symmetry is only available with square grids"; + } + if ((params->symm == SYMM_ROT4 || params->symm == SYMM_REF4) && params->w < 3 && params->h < 3) +- return _("Width or height must be at least 3 for 4-way symmetry"); ++ return "Width or height must be at least 3 for 4-way symmetry"; + if (params->symm < 0 || params->symm >= SYMM_MAX) + return "Unknown symmetry type"; + if (params->difficulty < 0 || params->difficulty > DIFFCOUNT) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch sgt-puzzles-20191231.79a5378/debian/patches/0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch 2023-04-23 19:12:44.000000000 +0000 @@ -0,0 +1,26 @@ +From: Michael Quevillon +Date: Sun, 3 Apr 2022 13:02:30 -0500 +Subject: [PATCH 269/389] Solo: Set max difficulty for small jigsaw puzzles +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=11c1447eac7698f01c2a00764c2b1a900a9d6a90 + +(cherry picked from Android port, commit +5c9a7b64a06d07f97a41622c4b91d81f3419a51b) +--- + solo.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/solo.c ++++ b/solo.c +@@ -3654,10 +3654,11 @@ static char *new_game_desc(const game_pa + * the puzzle size: all 2x2 puzzles appear to be Trivial + * (DIFF_BLOCK) so we cannot hold out for even a Basic + * (DIFF_SIMPLE) one. ++ * Jigsaw puzzles of size 2 and 3 are also all trivial. + */ + dlev.maxdiff = params->diff; + dlev.maxkdiff = params->kdiff; +- if (c == 2 && r == 2) ++ if ((c == 2 && r == 2) || (r == 1 && c < 4)) + dlev.maxdiff = DIFF_BLOCK; + + grid = snewn(area, digit); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch sgt-puzzles-20191231.79a5378/debian/patches/0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,50 @@ +From: Ben Harris +Date: Mon, 2 Jan 2023 16:48:20 +0000 +Subject: [PATCH 285/389] Add a macro of an upper bound on the formatted length + of an integer +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d246077e78bb1aeafe8829927db23f281cd03c72 +Bug-Debian: https://bugs.debian.org/1028986 + +There are lots of places where Puzzles formats integers into +fixed-length buffers using sprintf() with a "%d" format. This isn't +very safe, since C doesn't guarantee any particular maximum size for an +"int". However, the restrictions on representations of integers means +we can infer an upper bound using sizeof(), CHAR_BIT, and an +approximation to the binary log of 10. +--- + devel.but | 11 +++++++++++ + puzzles.h | 3 +++ + 2 files changed, 14 insertions(+) + +--- a/devel.but ++++ b/devel.but +@@ -4155,6 +4155,17 @@ returns the one which compares greater o + These macros may evaluate their arguments multiple times. Avoid side + effects. + ++\S{utils-max-digits} \cw{MAX_DIGITS()} ++ ++The \cw{MAX_DIGITS()} macro, defined in the main Puzzles header file, ++takes a type (or a variable of that type) and expands to an integer ++constant representing a reasonable upper bound on the number of ++characters that a number of that type could expand to when formatted ++as a decimal number using the \c{%u} or \c{%d} format of ++\cw{printf()}. This is useful for allocating a fixed-size buffer ++that's guaranteed to be big enough to \cw{sprintf()} a value into. ++Don't forget to add one for the trailing \cw{'\\0'}! ++ + \S{utils-pi} \cw{PI} + + The main Puzzles header file defines a macro \cw{PI} which expands +--- a/puzzles.h ++++ b/puzzles.h +@@ -18,6 +18,9 @@ + #define STR_INT(x) #x + #define STR(x) STR_INT(x) + ++/* An upper bound on the length of sprintf'ed integers (signed or unsigned). */ ++#define MAX_DIGITS(x) (sizeof(x) * CHAR_BIT / 3 + 2) ++ + /* NB not perfect because they evaluate arguments multiple times. */ + #ifndef max + #define max(x,y) ( (x)>(y) ? (x) : (y) ) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch sgt-puzzles-20191231.79a5378/debian/patches/0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,40 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 19:45:03 +0000 +Subject: [PATCH 299/389] Guess: Don't allow any moves once the game is solved +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c84af670b52f09e9e47587584c0559c508d4a37d +Bug-Debian: https://bugs.debian.org/1028986 + +If the game is solved (either by a win or a loss), interpret_move() +can never return a move, but execute_move() should also reject any +moves in case we're loading a corrupt or malicious save file. +Otherwise a save file with more guesses than the maximum allowed can +cause a buffer overrun. + +This save file demonstrates the problem when loaded into a build of +Puzzles with AddressSanitizer: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Guess +PARAMS :9:c6p4g1Bm +CPARAMS :9:c6p4g1Bm +DESC :8:b5f3faed +NSTATES :1:3 +STATEPOS:1:3 +MOVE :8:G1,1,2,2 +MOVE :8:G4,3,1,1 +--- + guess.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/guess.c ++++ b/guess.c +@@ -920,6 +920,8 @@ static game_state *execute_move(const ga + game_state *ret; + const char *p; + ++ /* No moves are allowed once the game is solved. */ ++ if (from->solved) return NULL; + if (!strcmp(move, "S")) { + ret = dup_game(from); + ret->solved = -1; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0300-Guess-validate-peg-colours-in-decode_ui.patch sgt-puzzles-20191231.79a5378/debian/patches/0300-Guess-validate-peg-colours-in-decode_ui.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0300-Guess-validate-peg-colours-in-decode_ui.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0300-Guess-validate-peg-colours-in-decode_ui.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,50 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 20:28:23 +0000 +Subject: [PATCH 300/389] Guess: validate peg colours in decode_ui() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5279fd24b2f4a51e760bfde873fe1d29547220a6 +Bug-Debian: https://bugs.debian.org/1028986 + +Peg colours in the current guess must be within the range of colours +for the current game, just as they must be for completed moves. +Otherwise is_markable() can cause a buffer overrun. + +Since there's no way for decode_ui() to report an error, it just ignores +the bad peg colours. I've also added an assertion to catch this problem +in is_markable(). + +The following save file demonstrates the problem when loaded in a build +with AddressSanitizer: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :5:Guess +PARAMS :9:c6p4g10Bm +CPARAMS :9:c6p4g10Bm +DESC :8:2de917c0 +UI :7:7,7,7,7 +NSTATES :1:1 +STATEPOS:1:1 +--- + guess.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/guess.c ++++ b/guess.c +@@ -386,6 +386,7 @@ static bool is_markable(const game_param + for (i = 0; i < params->npegs; i++) { + int c = pegs->pegs[i]; + if (c > 0) { ++ assert(c <= params->ncolours); + colcount->pegs[c-1]++; + nset++; + } +@@ -468,6 +469,9 @@ static void decode_ui(game_ui *ui, const + const char *p = encoding; + for (i = 0; i < ui->curr_pegs->npegs; i++) { + ui->curr_pegs->pegs[i] = atoi(p); ++ if (ui->curr_pegs->pegs[i] < 0 || ++ ui->curr_pegs->pegs[i] > ui->params.ncolours) ++ ui->curr_pegs->pegs[i] = 0; /* Remove invalid pegs. */ + while (*p && isdigit((unsigned char)*p)) p++; + if (*p == '_') { + /* NB: old versions didn't store holds */ diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0302-Netslide-Reject-moves-wider-than-the-grid.patch sgt-puzzles-20191231.79a5378/debian/patches/0302-Netslide-Reject-moves-wider-than-the-grid.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0302-Netslide-Reject-moves-wider-than-the-grid.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0302-Netslide-Reject-moves-wider-than-the-grid.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,60 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 22:05:33 +0000 +Subject: [PATCH 302/389] Netslide: Reject moves wider than the grid +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=1aded127eb3fb7194a1752d96bfba95a5b7fa4dc +Bug-Debian: https://bugs.debian.org/1028986 + +Also add a corresponding assertion to the underlying move primitive. +Without this limit, long moves cause a buffer overrun. + +To demonstrate the problem, build Netslide with AddressSanitizer and +load this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :8:Netslide +PARAMS :3:4x4 +CPARAMS :3:4x4 +DESC :16:49b59aca247714b4 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :5:R3,51 +--- + netslide.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/netslide.c ++++ b/netslide.c +@@ -1004,7 +1004,9 @@ static void slide_row_int(int w, int h, + int x = dir > 0 ? -1 : w; + int tx = x + dir; + int n = w - 1; +- unsigned char endtile = tiles[row * w + tx]; ++ unsigned char endtile; ++ assert(0 <= tx && tx < w); ++ endtile = tiles[row * w + tx]; + do { + x = tx; + tx = (x + dir + w) % w; +@@ -1018,7 +1020,9 @@ static void slide_col_int(int w, int h, + int y = dir > 0 ? -1 : h; + int ty = y + dir; + int n = h - 1; +- unsigned char endtile = tiles[ty * w + col]; ++ unsigned char endtile; ++ assert(0 <= ty && ty < h); ++ endtile = tiles[ty * w + col]; + do { + y = ty; + ty = (y + dir + h) % h; +@@ -1131,7 +1135,9 @@ static game_state *execute_move(const ga + + if ((move[0] == 'C' || move[0] == 'R') && + sscanf(move+1, "%d,%d", &c, &d) == 2 && +- c >= 0 && c < (move[0] == 'C' ? from->width : from->height)) { ++ c >= 0 && c < (move[0] == 'C' ? from->width : from->height) && ++ d <= (move[0] == 'C' ? from->width : from->height) && ++ d >= -(move[0] == 'C' ? from->width : from->height) && d != 0) { + col = (move[0] == 'C'); + } else if (move[0] == 'S' && + strlen(move) == from->width * from->height + 1) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0303-Sixteen-limit-length-of-moves.patch sgt-puzzles-20191231.79a5378/debian/patches/0303-Sixteen-limit-length-of-moves.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0303-Sixteen-limit-length-of-moves.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0303-Sixteen-limit-length-of-moves.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,44 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 23:06:13 +0000 +Subject: [PATCH 303/389] Sixteen: limit length of moves +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=023ce7554c19dcf6f4432407b9eedb850acc7289 +Bug-Debian: https://bugs.debian.org/1028986 + +The code that actually executes the moves can only cope with moves of +at most the width (or height as appropriate) of the grid. Reject any +longer move, and for symmetry also negative moves of the same +magnitude. + +Without this, the tile-moving code tends to access off the start of the +tile array. To demonstrate this, build Sixteen with AddressSanitizer +and load this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :7:Sixteen +PARAMS :3:4x4 +CPARAMS :3:4x4 +DESC :38:2,16,3,10,13,8,7,4,9,14,12,11,15,1,5,6 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :4:C1,9 +--- + sixteen.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sixteen.c ++++ b/sixteen.c +@@ -747,11 +747,11 @@ static game_state *execute_move(const ga + } + + if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 && +- cy >= 0 && cy < from->h) { ++ cy >= 0 && cy < from->h && -from->h <= dx && dx <= from->w ) { + cx = dy = 0; + n = from->w; + } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 && +- cx >= 0 && cx < from->w) { ++ cx >= 0 && cx < from->w && -from->h <= dy && dy <= from->h) { + cy = dx = 0; + n = from->h; + } else diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0304-Undead-check-for-valid-commands-in-execute_move.patch sgt-puzzles-20191231.79a5378/debian/patches/0304-Undead-check-for-valid-commands-in-execute_move.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0304-Undead-check-for-valid-commands-in-execute_move.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0304-Undead-check-for-valid-commands-in-execute_move.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,55 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 23:31:25 +0000 +Subject: [PATCH 304/389] Undead: check for valid commands in execute_move() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=a02c55b0492453ea7ca4e4ae63cb90ba4c93a3a5 +Bug-Debian: https://bugs.debian.org/1028986 + +Previously, Undead's execute_move would go into a spin when it +encountered an unexpected command character in a move string. Now it +rejects the move instead. +--- + undead.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/undead.c ++++ b/undead.c +@@ -2056,9 +2056,8 @@ static game_state *execute_move(const ga + if (c == 'S') { + move++; + solver = true; +- } +- if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' || +- c == 'g' || c == 'v' || c == 'z') { ++ } else if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' || ++ c == 'g' || c == 'v' || c == 'z') { + move++; + sscanf(move, "%d%n", &x, &n); + if (c == 'G') ret->guess[x] = 1; +@@ -2069,13 +2068,11 @@ static game_state *execute_move(const ga + if (c == 'v') ret->pencils[x] ^= 2; + if (c == 'z') ret->pencils[x] ^= 4; + move += n; +- } +- if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 && +- is_clue(ret, x, y)) { ++ } else if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 && ++ is_clue(ret, x, y)) { + ret->hints_done[clue_index(ret, x, y)] ^= 1; + move += n + 1; +- } +- if (c == 'M') { ++ } else if (c == 'M') { + /* + * Fill in absolutely all pencil marks in unfilled + * squares, for those who like to play by the rigorous +@@ -2086,6 +2083,10 @@ static game_state *execute_move(const ga + if (ret->guess[i] == 7) + ret->pencils[i] = 7; + move++; ++ } else { ++ /* Unknown move type. */ ++ free_game(ret); ++ return NULL; + } + if (*move == ';') move++; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0305-Undead-fix-buffer-overrun-in-M-command.patch sgt-puzzles-20191231.79a5378/debian/patches/0305-Undead-fix-buffer-overrun-in-M-command.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0305-Undead-fix-buffer-overrun-in-M-command.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0305-Undead-fix-buffer-overrun-in-M-command.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,27 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 23:44:31 +0000 +Subject: [PATCH 305/389] Undead: fix buffer overrun in "M" command +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=952ef8ca565d803da1134466358bd85683a489a3 +Bug-Debian: https://bugs.debian.org/1028986 + +The guessable squares are numbered up to num_total, not "wh". The +latter includes mirror squares that aren't included in the various +arrays describing the game state. + +To reproduce the problem, build Undead with AddressSanitizer and press +"M". +--- + undead.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/undead.c ++++ b/undead.c +@@ -2079,7 +2079,7 @@ static game_state *execute_move(const ga + * approach of starting off in that state and eliminating + * things. + */ +- for (i = 0; i < ret->common->wh; i++) ++ for (i = 0; i < ret->common->num_total; i++) + if (ret->guess[i] == 7) + ret->pencils[i] = 7; + move++; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0306-Correct-RANGECHECK-macro-in-Black-Box.patch sgt-puzzles-20191231.79a5378/debian/patches/0306-Correct-RANGECHECK-macro-in-Black-Box.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0306-Correct-RANGECHECK-macro-in-Black-Box.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0306-Correct-RANGECHECK-macro-in-Black-Box.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,23 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 10:05:12 +0000 +Subject: [PATCH 306/389] Correct RANGECHECK macro in Black Box +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=4845f3e913a02417fe7a8d84c6407d40807ec0ec +Bug-Debian: https://bugs.debian.org/1028986 + +Lasers are numbered from 0 to nlasers-1 inclusive, so the upper limit +should be "<", not "<=". +--- + blackbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/blackbox.c ++++ b/blackbox.c +@@ -305,7 +305,7 @@ struct game_state { + + #define GRID(s,x,y) ((s)->grid[(y)*((s)->w+2) + (x)]) + +-#define RANGECHECK(s,x) ((x) >= 0 && (x) <= (s)->nlasers) ++#define RANGECHECK(s,x) ((x) >= 0 && (x) < (s)->nlasers) + + /* specify numbers because they must match array indexes. */ + enum { DIR_UP = 0, DIR_RIGHT = 1, DIR_DOWN = 2, DIR_LEFT = 3 }; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0307-Range-check-normal-moves-in-Undead.patch sgt-puzzles-20191231.79a5378/debian/patches/0307-Range-check-normal-moves-in-Undead.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0307-Range-check-normal-moves-in-Undead.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0307-Range-check-normal-moves-in-Undead.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,41 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 10:20:26 +0000 +Subject: [PATCH 307/389] Range-check normal moves in Undead +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=942d883d9bf86f4240dc7ec22b726d64f6db9af2 +Bug-Debian: https://bugs.debian.org/1028986 + +Normal moves shouldn't be allowed to write outside the board. This +buffer overrun can be demonstrated by building Undead with +AddressSanitizer and loading this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :6:Undead +PARAMS :5:4x4dn +CPARAMS :5:4x4dn +DESC :48:5,0,5,cRRaLRcLRc,0,2,1,3,1,0,0,3,4,3,2,3,4,2,1,1 +NSTATES :1:2 +STATEPOS:1:2 +MOVE :3:Z10 +--- + undead.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/undead.c ++++ b/undead.c +@@ -2060,6 +2060,7 @@ static game_state *execute_move(const ga + c == 'g' || c == 'v' || c == 'z') { + move++; + sscanf(move, "%d%n", &x, &n); ++ if (x < 0 || x >= ret->common->num_total) goto badmove; + if (c == 'G') ret->guess[x] = 1; + if (c == 'V') ret->guess[x] = 2; + if (c == 'Z') ret->guess[x] = 4; +@@ -2085,6 +2086,7 @@ static game_state *execute_move(const ga + move++; + } else { + /* Unknown move type. */ ++ badmove: + free_game(ret); + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0308-Range-check-record-lengths-when-deserialising-games.patch sgt-puzzles-20191231.79a5378/debian/patches/0308-Range-check-record-lengths-when-deserialising-games.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0308-Range-check-record-lengths-when-deserialising-games.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0308-Range-check-record-lengths-when-deserialising-games.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,42 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 11:31:36 +0000 +Subject: [PATCH 308/389] Range-check record lengths when deserialising games +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e5717d1ba2184eb6e38b4e2a9d29dc4704aeef30 +Bug-Debian: https://bugs.debian.org/1028986 + +"1999999999999999999999999999999999999999999999999999" as a record +length should lead to an error, not a buffer overrun. + +(fun fact that was less obvious to me than it should have been: very +large powers of ten are multiples of large powers of two, so that number +is -1 mod 2^32) + +This bug can be demonstrated by building any puzzle with +AddressSanitizer and then loading this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1999999999999999999999999999999999999999999999999999:1 +--- + midend.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/midend.c ++++ b/midend.c +@@ -2181,7 +2181,7 @@ static const char *midend_deserialise_in + + if (c == ':') { + break; +- } else if (c >= '0' && c <= '9') { ++ } else if (c >= '0' && c <= '9' && len < (INT_MAX - 10) / 10) { + len = (len * 10) + (c - '0'); + } else { + if (started) +@@ -2573,7 +2573,7 @@ const char *identify_game(char **name, + + if (c == ':') { + break; +- } else if (c >= '0' && c <= '9') { ++ } else if (c >= '0' && c <= '9' && len < (INT_MAX - 10) / 10) { + len = (len * 10) + (c - '0'); + } else { + if (started) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch sgt-puzzles-20191231.79a5378/debian/patches/0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,49 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 19:32:08 +0000 +Subject: [PATCH 309/389] Don't load too many states just because there's no + STATEPOS +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b3d4a4197954c21ac78b68c58dff8f84fe743ea2 +Bug-Debian: https://bugs.debian.org/1028986 + +If we start seeing state records in a save file (MOVE, SOLVE, or +RESTART), we should already have seen STATEPOS, so emit an error if not. +This avoids the situation where we overrun the end of the state array +because we're continuing loading states in the hope a STATEPOS will come +along. I've also added an assertion that we're not overrunning the +state array for added paranoia. + +An earlier version of this fix just removed the test for data.statepos +at the head of the loop, but that's wrong for a file that only has the +initial state. + +This bug can be demonstrated by building Bridges with AddressSanitizer +and loading this save file: + +SAVEFILE:41:Simon Tatham's Portable Puzzle Collection +VERSION :1:1 +GAME :7:Bridges +PARAMS :13:7x7i30e10m2d0 +CPARAMS :13:7x7i30e10m2d0 +DESC :24:a4b4a1g1a2a8a4a4m2b2b3e3 +NSTATES :1:2 +MOVE :10:L1,0,4,0,1 +MOVE :10:L1,0,4,0,2 +--- + midend.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/midend.c ++++ b/midend.c +@@ -2289,7 +2289,12 @@ static const char *midend_deserialise_in + ret = "No state count provided in save file"; + goto cleanup; + } ++ if (data.statepos < 0) { ++ ret = "No game position provided in save file"; ++ goto cleanup; ++ } + gotstates++; ++ assert(gotstates < data.nstates); + if (!strcmp(key, "MOVE")) + data.states[gotstates].movetype = MOVE; + else if (!strcmp(key, "SOLVE")) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0310-Palisade-forbid-moves-that-remove-grid-edges.patch sgt-puzzles-20191231.79a5378/debian/patches/0310-Palisade-forbid-moves-that-remove-grid-edges.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0310-Palisade-forbid-moves-that-remove-grid-edges.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0310-Palisade-forbid-moves-that-remove-grid-edges.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,63 @@ +From: Ben Harris +Date: Thu, 12 Jan 2023 20:55:56 +0000 +Subject: [PATCH 310/389] Palisade: forbid moves that remove grid edges +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=21193eaf9308ace41004a19180ff382ec6e8754b +Bug-Debian: https://bugs.debian.org/1028986 + +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 +--- + palisade.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/palisade.c ++++ b/palisade.c +@@ -1008,10 +1008,9 @@ static game_state *execute_move(const ga + { + 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] = +@@ -1024,6 +1023,11 @@ static game_state *execute_move(const ga + 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; + } + +@@ -1034,6 +1038,10 @@ static game_state *execute_move(const ga + ret->borders); + + return ret; ++ ++ badmove: ++ sfree(ret); ++ return NULL; + } + + /* --- Drawing routines --------------------------------------------- */ diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0311-Last-ditch-maximum-size-limit-for-Bridges.patch sgt-puzzles-20191231.79a5378/debian/patches/0311-Last-ditch-maximum-size-limit-for-Bridges.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0311-Last-ditch-maximum-size-limit-for-Bridges.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0311-Last-ditch-maximum-size-limit-for-Bridges.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:09:11 +0000 +Subject: [PATCH 311/389] Last-ditch maximum size limit for Bridges +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=97484b098f33266f6c747c292c708281cb15a286 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + bridges.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/bridges.c ++++ b/bridges.c +@@ -72,6 +72,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -803,6 +804,8 @@ static const char *validate_params(const + { + if (params->w < 3 || params->h < 3) + return "Width and height must be at least 3"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->maxb < 1 || params->maxb > MAX_BRIDGES) + return "Too many bridges."; + if (full) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0312-Last-ditch-grid-size-limit-for-Dominosa.patch sgt-puzzles-20191231.79a5378/debian/patches/0312-Last-ditch-grid-size-limit-for-Dominosa.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0312-Last-ditch-grid-size-limit-for-Dominosa.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0312-Last-ditch-grid-size-limit-for-Dominosa.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,32 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 00:03:57 +0000 +Subject: [PATCH 312/389] Last-ditch grid-size limit for Dominosa +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b3f3345764b0808a7a97b9c3a2a1888fd62383a0 +Bug-Debian: https://bugs.debian.org/1028986 + +At least prevent integer overflow when constructing the grid. +--- + dominosa.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/dominosa.c ++++ b/dominosa.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -243,6 +244,10 @@ static const char *validate_params(const + { + if (params->n < 1) + return "Maximum face number must be at least one"; ++ if (params->n > INT_MAX - 2 || ++ params->n + 2 > INT_MAX / (params->n + 1)) ++ return "Maximum face number must not be unreasonably large"; ++ + if (params->diff >= DIFFCOUNT) + return "Unknown difficulty rating"; + return NULL; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0313-Last-ditch-grid-size-limit-for-Galaxies.patch sgt-puzzles-20191231.79a5378/debian/patches/0313-Last-ditch-grid-size-limit-for-Galaxies.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0313-Last-ditch-grid-size-limit-for-Galaxies.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0313-Last-ditch-grid-size-limit-for-Galaxies.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,32 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:53:07 +0000 +Subject: [PATCH 313/389] Last-ditch grid-size limit for Galaxies +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d422dd6009f3e48e13d5f7f162813537902e125c +Bug-Debian: https://bugs.debian.org/1028986 + +At least prevent integer overflow when constructing the grid. +--- + galaxies.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/galaxies.c ++++ b/galaxies.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -281,6 +282,10 @@ static const char *validate_params(const + { + if (params->w < 3 || params->h < 3) + return "Width and height must both be at least 3"; ++ if (params->w > INT_MAX / 2 || params->h > INT_MAX / 2 || ++ params->w > (INT_MAX - params->w*2 - params->h*2 - 1) / 4 / params->h) ++ return "Width times height must not be unreasonably large"; ++ + /* + * This shouldn't be able to happen at all, since decode_params + * and custom_params will never generate anything that isn't diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0314-Last-ditch-grid-size-limit-for-Fifteen.patch sgt-puzzles-20191231.79a5378/debian/patches/0314-Last-ditch-grid-size-limit-for-Fifteen.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0314-Last-ditch-grid-size-limit-for-Fifteen.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0314-Last-ditch-grid-size-limit-for-Fifteen.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,30 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 23:37:21 +0000 +Subject: [PATCH 314/389] Last-ditch grid-size limit for Fifteen +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=522588f699b3c910c5a47f8b8185e69250665313 +Bug-Debian: https://bugs.debian.org/1028986 + +At least prevent integer overflow when constructing the grid. +--- + fifteen.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fifteen.c ++++ b/fifteen.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -138,6 +139,8 @@ static const char *validate_params(const + { + if (params->w < 2 || params->h < 2) + return "Width and height must both be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0315-Last-ditch-maximum-size-limit-for-Flip.patch sgt-puzzles-20191231.79a5378/debian/patches/0315-Last-ditch-maximum-size-limit-for-Flip.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0315-Last-ditch-maximum-size-limit-for-Flip.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0315-Last-ditch-maximum-size-limit-for-Flip.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,41 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 11:07:14 +0000 +Subject: [PATCH 315/389] Last-ditch maximum size limit for Flip +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=26d0633f87ccdbaf7035e2e14d9dfbfd7f379527 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. Also in Flip's case that the square of the area still fits in +an int. +--- + flip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/flip.c ++++ b/flip.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -181,9 +182,16 @@ static game_params *custom_params(const + + static const char *validate_params(const game_params *params, bool full) + { ++ int wh; ++ + if (params->w <= 0 || params->h <= 0) + return "Width and height must both be greater than zero"; +- return NULL; ++ if (params->w > (INT_MAX - 3) / params->h) ++ return "Width times height must not be unreasonably large"; ++ wh = params->w * params->h; ++ if (wh > (INT_MAX - 3) / wh) ++ return "Width times height is too large"; ++ return NULL; + } + + static char *encode_bitmap(unsigned char *bmp, int len) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0316-Last-ditch-grid-size-limit-for-Flood.patch sgt-puzzles-20191231.79a5378/debian/patches/0316-Last-ditch-grid-size-limit-for-Flood.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0316-Last-ditch-grid-size-limit-for-Flood.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0316-Last-ditch-grid-size-limit-for-Flood.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,30 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 21:20:35 +0000 +Subject: [PATCH 316/389] Last-ditch grid-size limit for Flood +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=da220a77d1793edd14144fd96584b7f461f06dfb +Bug-Debian: https://bugs.debian.org/1028986 + +At least prevent integer overflow when constructing the grid. +--- + flood.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/flood.c ++++ b/flood.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -209,6 +210,8 @@ static const char *validate_params(const + { + if (params->w < 2 && params->h < 2) + return "Grid must contain at least two squares"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->colours < 3 || params->colours > 10) + return "Must have between 3 and 10 colours"; + if (params->leniency < 0) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0317-Insist-that-Flood-grids-must-have-non-zero-size.patch sgt-puzzles-20191231.79a5378/debian/patches/0317-Insist-that-Flood-grids-must-have-non-zero-size.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0317-Insist-that-Flood-grids-must-have-non-zero-size.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0317-Insist-that-Flood-grids-must-have-non-zero-size.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,21 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 09:35:51 +0000 +Subject: [PATCH 317/389] Insist that Flood grids must have non-zero size +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d60192531e3ee6b492151f6aa8edd481ebddcdf7 +Bug-Debian: https://bugs.debian.org/1028986 + +--- + flood.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/flood.c ++++ b/flood.c +@@ -210,6 +210,8 @@ static const char *validate_params(const + { + if (params->w < 2 && params->h < 2) + return "Grid must contain at least two squares"; ++ if (params->w < 1 || params->h < 1) ++ return "Width and height must be at least one"; + if (params->w > INT_MAX / params->h) + return "Width times height must not be unreasonably large"; + if (params->colours < 3 || params->colours > 10) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0318-Last-ditch-grid-size-limit-for-Inertia.patch sgt-puzzles-20191231.79a5378/debian/patches/0318-Last-ditch-grid-size-limit-for-Inertia.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0318-Last-ditch-grid-size-limit-for-Inertia.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0318-Last-ditch-grid-size-limit-for-Inertia.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,30 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 00:04:59 +0000 +Subject: [PATCH 318/389] Last-ditch grid-size limit for Inertia +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=98724b90936c46e457234a0189bb09242fc727d1 +Bug-Debian: https://bugs.debian.org/1028986 + +At least prevent integer overflow when constructing the grid. +--- + inertia.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/inertia.c ++++ b/inertia.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -202,6 +203,8 @@ static const char *validate_params(const + */ + if (params->w < 2 || params->h < 2) + return "Width and height must both be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + /* + * The grid construction algorithm creates 1/5 as many gems as diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0319-Last-ditch-maximum-size-limit-for-Light-Up.patch sgt-puzzles-20191231.79a5378/debian/patches/0319-Last-ditch-maximum-size-limit-for-Light-Up.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0319-Last-ditch-maximum-size-limit-for-Light-Up.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0319-Last-ditch-maximum-size-limit-for-Light-Up.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:31:10 +0000 +Subject: [PATCH 319/389] Last-ditch maximum size limit for Light Up +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=fcda12f4b73e69841fd8957b8e33930c584093e5 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + lightup.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/lightup.c ++++ b/lightup.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -346,6 +347,8 @@ static const char *validate_params(const + { + if (params->w < 2 || params->h < 2) + return "Width and height must be at least 2"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (full) { + if (params->blackpc < 5 || params->blackpc > 100) + return "Percentage of black squares must be between 5% and 100%"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0320-Limit-maximum-grid-size-in-Loopy.patch sgt-puzzles-20191231.79a5378/debian/patches/0320-Limit-maximum-grid-size-in-Loopy.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0320-Limit-maximum-grid-size-in-Loopy.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0320-Limit-maximum-grid-size-in-Loopy.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,373 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 23:11:46 +0000 +Subject: [PATCH 320/389] Limit maximum grid size in Loopy +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d71bba1a17d6b228e7dd8b437dccbd3f6bc4698c +Bug-Debian: https://bugs.debian.org/1028986 + +Every grid shape has its own limit, so this involved adding a new +interface between loopy.c and grid.c. The limits are based on ensuring +that the co-ordinate system of the grid doesn't overflow INT_MAX and +neither do the lengths of the face and dot arrays. + +Though now I come to look at it I think the actual limits of grid.c are +much lower. Hmm. + +[benh: Backported to 20191231: Drop the change to compassdodecagonal grid + which isn't implemented here.] +--- + grid.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- + grid.h | 2 + + loopy.c | 3 + + 3 files changed, 210 insertions(+), 1 deletion(-) + +--- a/grid.c ++++ b/grid.c +@@ -11,8 +11,9 @@ + #include + #include + #include +-#include + #include ++#include ++#include + + #include "puzzles.h" + #include "tree234.h" +@@ -1388,6 +1389,15 @@ void grid_find_incentre(grid_face *f) + + #define SQUARE_TILESIZE 20 + ++static const char *grid_validate_params_square(int width, int height) ++{ ++ if (width > INT_MAX / SQUARE_TILESIZE || /* xextent */ ++ height > INT_MAX / SQUARE_TILESIZE || /* yextent */ ++ width + 1 > INT_MAX / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_square(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -1450,6 +1460,18 @@ static grid *grid_new_square(int width, + #define HONEY_A 15 + #define HONEY_B 26 + ++static const char *grid_validate_params_honeycomb(int width, int height) ++{ ++ int a = HONEY_A; ++ int b = HONEY_B; ++ ++ if (width - 1 > (INT_MAX - 4*a) / (3 * a) || /* xextent */ ++ height - 1 > (INT_MAX - 3*b) / (2 * b) || /* yextent */ ++ width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_honeycomb(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -1519,6 +1541,18 @@ static grid *grid_new_honeycomb(int widt + #define TRIANGLE_VEC_X 15 + #define TRIANGLE_VEC_Y 26 + ++static const char *grid_validate_params_triangular(int width, int height) ++{ ++ int vec_x = TRIANGLE_VEC_X; ++ int vec_y = TRIANGLE_VEC_Y; ++ ++ if (width > INT_MAX / (2 * vec_x) - 1 || /* xextent */ ++ height > INT_MAX / vec_y || /* yextent */ ++ width + 1 > INT_MAX / 4 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_triangular(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -1716,6 +1750,19 @@ static grid *grid_new_triangular(int wid + #define SNUBSQUARE_A 15 + #define SNUBSQUARE_B 26 + ++static const char *grid_validate_params_snubsquare(int width, int height) ++{ ++ int a = SNUBSQUARE_A; ++ int b = SNUBSQUARE_B; ++ ++ if (width-1 > (INT_MAX - (a + b)) / (a+b) || /* xextent */ ++ height > (INT_MAX - (a + b)) / (a+b) || /* yextent */ ++ width > INT_MAX / 3 / height || /* max_faces */ ++ width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_snubsquare(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -1830,6 +1877,18 @@ static grid *grid_new_snubsquare(int wid + #define CAIRO_A 14 + #define CAIRO_B 31 + ++static const char *grid_validate_params_cairo(int width, int height) ++{ ++ int b = CAIRO_B; /* a unused in determining grid size. */ ++ ++ if (width - 1 > (INT_MAX - 2*b) / (2*b) || /* xextent */ ++ height - 1 > (INT_MAX - 2*b) / (2*b) || /* yextent */ ++ width > INT_MAX / 2 / height || /* max_faces */ ++ width + 1 > INT_MAX / 3 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_cairo(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -1936,6 +1995,18 @@ static grid *grid_new_cairo(int width, i + #define GREATHEX_A 15 + #define GREATHEX_B 26 + ++static const char *grid_validate_params_greathexagonal(int width, int height) ++{ ++ int a = GREATHEX_A; ++ int b = GREATHEX_B; ++ ++ if (width-1 > (INT_MAX - 4*a) / (3*a + b) || /* xextent */ ++ height-1 > (INT_MAX - (3*b + a)) / (2*a + 2*b) || /* yextent */ ++ width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_greathexagonal(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2066,6 +2137,18 @@ static grid *grid_new_greathexagonal(int + #define KAGOME_A 15 + #define KAGOME_B 26 + ++static const char *grid_validate_params_kagome(int width, int height) ++{ ++ int a = KAGOME_A; ++ int b = KAGOME_B; ++ ++ if (width-1 > (INT_MAX - 6*a) / (4*a) || /* xextent */ ++ height-1 > (INT_MAX - 2*b) / (2*b) || /* yextent */ ++ width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_kagome(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2162,6 +2245,18 @@ static grid *grid_new_kagome(int width, + #define OCTAGONAL_A 29 + #define OCTAGONAL_B 41 + ++static const char *grid_validate_params_octagonal(int width, int height) ++{ ++ int a = OCTAGONAL_A; ++ int b = OCTAGONAL_B; ++ ++ if (width > INT_MAX / (2*a + b) || /* xextent */ ++ height > INT_MAX / (2*a + b) || /* yextent */ ++ height + 1 > INT_MAX / 4 / (width + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_octagonal(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2245,6 +2340,18 @@ static grid *grid_new_octagonal(int widt + #define KITE_A 15 + #define KITE_B 26 + ++static const char *grid_validate_params_kites(int width, int height) ++{ ++ int a = KITE_A; ++ int b = KITE_B; ++ ++ if (width > (INT_MAX - 2*b) / (4*b) || /* xextent */ ++ height - 1 > (INT_MAX - 8*a) / (6*a) || /* yextent */ ++ width + 1 > INT_MAX / 6 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_kites(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2367,6 +2474,20 @@ static grid *grid_new_kites(int width, i + #define FLORET_PX 75 + #define FLORET_PY -26 + ++static const char *grid_validate_params_floret(int width, int height) ++{ ++ int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ ++ int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ ++ int ry = qy-py; ++ /* rx unused in determining grid size. */ ++ ++ if (width - 1 > (INT_MAX - (4*qx + 2*px)) / ((6*px+3*qx)/2) ||/* xextent */ ++ height - 1 > (INT_MAX - (4*qy + 2*ry)) / (5*qy-4*py) || /* yextent */ ++ width + 1 > INT_MAX / 9 / (height + 1)) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_floret(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2474,6 +2595,18 @@ static grid *grid_new_floret(int width, + #define DODEC_A 15 + #define DODEC_B 26 + ++static const char *grid_validate_params_dodecagonal(int width, int height) ++{ ++ int a = DODEC_A; ++ int b = DODEC_B; ++ ++ if (width - 1 > (INT_MAX - 3*(2*a + b)) / (4*a + 2*b) || /* xextent */ ++ height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 2*b) || /* yextent */ ++ width > INT_MAX / 14 / height) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_dodecagonal(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2554,6 +2687,18 @@ static grid *grid_new_dodecagonal(int wi + return g; + } + ++static const char *grid_validate_params_greatdodecagonal(int width, int height) ++{ ++ int a = DODEC_A; ++ int b = DODEC_B; ++ ++ if (width - 1 > (INT_MAX - (2*(2*a + b) + 3*a + b)) / (6*a + 2*b) || ++ height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 3*b) || /* yextent */ ++ width > INT_MAX / 200 / height) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_greatdodecagonal(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2668,6 +2813,19 @@ static grid *grid_new_greatdodecagonal(i + return g; + } + ++static const char *grid_validate_params_greatgreatdodecagonal( ++ int width, int height) ++{ ++ int a = DODEC_A; ++ int b = DODEC_B; ++ ++ if (width-1 > (INT_MAX - (2*(2*a + b) + 2*a + 2*b)) / (4*a + 4*b) || ++ height-1 > (INT_MAX - 2*(2*a + b)) / (6*a + 2*b) || /* yextent */ ++ width > INT_MAX / 300 / height) /* max_dots */ ++ return "Grid size must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_greatgreatdodecagonal(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -2887,6 +3045,17 @@ static int set_faces(penrose_state *stat + + #define PENROSE_TILESIZE 100 + ++static const char *grid_validate_params_penrose(int width, int height) ++{ ++ int l = PENROSE_TILESIZE; ++ ++ if (width > INT_MAX / l || /* xextent */ ++ height > INT_MAX / l || /* yextent */ ++ width > INT_MAX / (3 * 3 * 4 * height)) /* max_dots */ ++ return "Grid must not be unreasonably large"; ++ return NULL; ++} ++ + static void grid_size_penrose(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -3089,6 +3258,16 @@ static grid *grid_new_penrose(int width, + return g; + } + ++static const char *grid_validate_params_penrose_p2_kite(int width, int height) ++{ ++ return grid_validate_params_penrose(width, height); ++} ++ ++static const char *grid_validate_params_penrose_p3_thick(int width, int height) ++{ ++ return grid_validate_params_penrose(width, height); ++} ++ + static void grid_size_penrose_p2_kite(int width, int height, + int *tilesize, int *xextent, int *yextent) + { +@@ -3113,12 +3292,24 @@ static grid *grid_new_penrose_p3_thick(i + + /* ----------- End of grid generators ------------- */ + ++#define FNVAL(upper,lower) &grid_validate_params_ ## lower, + #define FNNEW(upper,lower) &grid_new_ ## lower, + #define FNSZ(upper,lower) &grid_size_ ## lower, + ++static const char *(*(grid_validate_paramses[]))(int, int) = ++ { GRIDGEN_LIST(FNVAL) }; + static grid *(*(grid_news[]))(int, int, const char*) = { GRIDGEN_LIST(FNNEW) }; + static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) }; + ++/* Work out if a grid can be made, and complain if not. */ ++ ++const char *grid_validate_params(grid_type type, int width, int height) ++{ ++ if (width <= 0 || height <= 0) ++ return "Width and height must both be positive"; ++ return grid_validate_paramses[type](width, height); ++} ++ + char *grid_new_desc(grid_type type, int width, int height, random_state *rs) + { + if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { +--- a/grid.h ++++ b/grid.h +@@ -114,6 +114,8 @@ typedef struct grid { + typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type; + #undef ENUM + ++const char *grid_validate_params(grid_type type, int width, int height); ++ + /* Free directly after use if non-NULL. Will never contain an underscore + * (so clients can safely use that as a separator). */ + char *grid_new_desc(grid_type type, int width, int height, random_state *rs); +--- a/loopy.c ++++ b/loopy.c +@@ -681,6 +681,7 @@ static game_params *custom_params(const + + static const char *validate_params(const game_params *params, bool full) + { ++ const char *err; + if (params->type < 0 || params->type >= NUM_GRID_TYPES) + return "Illegal grid type"; + if (params->w < grid_size_limits[params->type].amin || +@@ -689,6 +690,8 @@ static const char *validate_params(const + if (params->w < grid_size_limits[params->type].omin && + params->h < grid_size_limits[params->type].omin) + return grid_size_limits[params->type].oerr; ++ err = grid_validate_params(grid_types[params->type], params->w, params->h); ++ if (err != NULL) return err; + + /* + * This shouldn't be able to happen at all, since decode_params diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0321-Last-ditch-maximum-size-limit-for-Magnets.patch sgt-puzzles-20191231.79a5378/debian/patches/0321-Last-ditch-maximum-size-limit-for-Magnets.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0321-Last-ditch-maximum-size-limit-for-Magnets.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0321-Last-ditch-maximum-size-limit-for-Magnets.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 09:43:01 +0000 +Subject: [PATCH 321/389] Last-ditch maximum size limit for Magnets +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=261a9568faeeb7acc6e56bd67147917c5109ac8a +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + magnets.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/magnets.c ++++ b/magnets.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -232,6 +233,8 @@ static const char *validate_params(const + { + if (params->w < 2) return "Width must be at least two"; + if (params->h < 2) return "Height must be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->diff >= DIFF_TRICKY) { + if (params->w < 5 && params->h < 5) + return "Either width or height must be at least five for Tricky"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0322-Last-ditch-maximum-size-limit-for-Map.patch sgt-puzzles-20191231.79a5378/debian/patches/0322-Last-ditch-maximum-size-limit-for-Map.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0322-Last-ditch-maximum-size-limit-for-Map.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0322-Last-ditch-maximum-size-limit-for-Map.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,43 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:19:02 +0000 +Subject: [PATCH 322/389] Last-ditch maximum size limit for Map +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ed75535fc24217c51f900d42385309c8c8b36cc3 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. Also a similar check in decode_params when defaulting the +number of regions. +--- + map.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/map.c ++++ b/map.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -180,7 +181,9 @@ static void decode_params(game_params *p + params->n = atoi(p); + while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; + } else { +- params->n = params->w * params->h / 8; ++ if (params->h > 0 && params->w > 0 && ++ params->w <= INT_MAX / params->h) ++ params->n = params->w * params->h / 8; + } + if (*p == 'd') { + int i; +@@ -252,6 +255,8 @@ static const char *validate_params(const + { + if (params->w < 2 || params->h < 2) + return "Width and height must be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->n < 5) + return "Must have at least five regions"; + if (params->n > params->w * params->h) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0323-Last-ditch-maximum-size-limit-for-Mines.patch sgt-puzzles-20191231.79a5378/debian/patches/0323-Last-ditch-maximum-size-limit-for-Mines.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0323-Last-ditch-maximum-size-limit-for-Mines.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0323-Last-ditch-maximum-size-limit-for-Mines.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,43 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:20:36 +0000 +Subject: [PATCH 323/389] Last-ditch maximum size limit for Mines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5cc9bfb811854b66c4a570e8100b8a1aad037f0e +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. Also a similar check in decode_params when defaulting the +number of mines. +--- + mines.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/mines.c ++++ b/mines.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + + #include "tree234.h" +@@ -162,7 +163,9 @@ static void decode_params(game_params *p + params->n = atoi(p); + while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; + } else { +- params->n = params->w * params->h / 10; ++ if (params->h > 0 && params->w > 0 && ++ params->w <= INT_MAX / params->h) ++ params->n = params->w * params->h / 10; + } + + while (*p) { +@@ -258,6 +261,8 @@ static const char *validate_params(const + */ + if (full && params->unique && (params->w <= 2 || params->h <= 2)) + return "Width and height must both be greater than two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->n < 0) + return "Mine count may not be negative"; + if (params->n > params->w * params->h - 9) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0324-Also-check-for-tiny-grids-in-Mines.patch sgt-puzzles-20191231.79a5378/debian/patches/0324-Also-check-for-tiny-grids-in-Mines.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0324-Also-check-for-tiny-grids-in-Mines.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0324-Also-check-for-tiny-grids-in-Mines.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,23 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:22:57 +0000 +Subject: [PATCH 324/389] Also check for tiny grids in Mines +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=9e2e0692ed087dbe0d5f4abbddf3aebd6a11b30e +Bug-Debian: https://bugs.debian.org/1028986 + +A zero-size grid isn't acceptable even if someone has generated it for +us. +--- + mines.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -261,6 +261,8 @@ static const char *validate_params(const + */ + if (full && params->unique && (params->w <= 2 || params->h <= 2)) + return "Width and height must both be greater than two"; ++ if (params->w < 1 || params->h < 1) ++ return "Width and height must both be at least one"; + if (params->w > INT_MAX / params->h) + return "Width times height must not be unreasonably large"; + if (params->n < 0) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0326-Last-ditch-maximum-size-limit-for-Net.patch sgt-puzzles-20191231.79a5378/debian/patches/0326-Last-ditch-maximum-size-limit-for-Net.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0326-Last-ditch-maximum-size-limit-for-Net.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0326-Last-ditch-maximum-size-limit-for-Net.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:24:49 +0000 +Subject: [PATCH 326/389] Last-ditch maximum size limit for Net +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=051357bb24c0f05c291d6f9e6b460839847923b4 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + net.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net.c ++++ b/net.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -313,6 +314,8 @@ static const char *validate_params(const + return "Width and height must both be greater than zero"; + if (params->width <= 1 && params->height <= 1) + return "At least one of width and height must be greater than one"; ++ if (params->width > INT_MAX / params->height) ++ return "Width times height must not be unreasonably large"; + if (params->barrier_probability < 0) + return "Barrier probability may not be negative"; + if (params->barrier_probability > 1) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0327-Last-ditch-maximum-size-limit-for-Netslide.patch sgt-puzzles-20191231.79a5378/debian/patches/0327-Last-ditch-maximum-size-limit-for-Netslide.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0327-Last-ditch-maximum-size-limit-for-Netslide.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0327-Last-ditch-maximum-size-limit-for-Netslide.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:25:52 +0000 +Subject: [PATCH 327/389] Last-ditch maximum size limit for Netslide +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=40ec3aaf09824face187218f899494aef429a9c6 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + netslide.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/netslide.c ++++ b/netslide.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -307,6 +308,8 @@ static const char *validate_params(const + { + if (params->width <= 1 || params->height <= 1) + return "Width and height must both be greater than one"; ++ if (params->width > INT_MAX / params->height) ++ return "Width times height must not be unreasonably large"; + if (params->barrier_probability < 0) + return "Barrier probability may not be negative"; + if (params->barrier_probability > 1) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0328-Integer-overflow-protection-in-Pattern.patch sgt-puzzles-20191231.79a5378/debian/patches/0328-Integer-overflow-protection-in-Pattern.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0328-Integer-overflow-protection-in-Pattern.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0328-Integer-overflow-protection-in-Pattern.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,40 @@ +From: Ben Harris +Date: Wed, 11 Jan 2023 23:15:44 +0000 +Subject: [PATCH 328/389] Integer overflow protection in Pattern +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=dd00e9c532abc7517bd7ca72c8e4db91bb2da821 +Bug-Debian: https://bugs.debian.org/1028986 + +Both for grid sizes and for clue values. +--- + pattern.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/pattern.c ++++ b/pattern.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -175,6 +176,9 @@ static const char *validate_params(const + { + if (params->w <= 0 || params->h <= 0) + return "Width and height must both be greater than zero"; ++ if (params->w > INT_MAX - 1 || params->h > INT_MAX - 1 || ++ params->w > INT_MAX / params->h) ++ return "Puzzle must not be unreasonably large"; + return NULL; + } + +@@ -908,6 +912,8 @@ static const char *validate_desc(const g + p = desc; + while (*desc && isdigit((unsigned char)*desc)) desc++; + n = atoi(p); ++ if (n > INT_MAX - 1) ++ return "at least one clue is grossly excessive"; + rowspace -= n+1; + + if (rowspace < 0) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0329-Last-ditch-maximum-size-limit-for-Palisade.patch sgt-puzzles-20191231.79a5378/debian/patches/0329-Last-ditch-maximum-size-limit-for-Palisade.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0329-Last-ditch-maximum-size-limit-for-Palisade.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0329-Last-ditch-maximum-size-limit-for-Palisade.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,40 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:28:09 +0000 +Subject: [PATCH 329/389] Last-ditch maximum size limit for Palisade +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=91c0fac1dc98be2ecc074d83368df74f9f755641 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + palisade.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/palisade.c ++++ b/palisade.c +@@ -17,6 +17,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -156,13 +157,15 @@ static game_params *custom_params(const + + static const char *validate_params(const game_params *params, bool full) + { +- int w = params->w, h = params->h, k = params->k, wh = w * h; ++ int w = params->w, h = params->h, k = params->k, wh; + + if (k < 1) return "Region size must be at least one"; + if (w < 1) return "Width must be at least one"; + if (h < 1) return "Height must be at least one"; ++ if (w > INT_MAX / h) ++ return "Width times height must not be unreasonably large"; ++ wh = w * h; + if (wh % k) return "Region size must divide grid area"; +- + if (!full) return NULL; /* succeed partial validation */ + + /* MAYBE FIXME: we (just?) don't have the UI for winning these. */ diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0330-Last-ditch-maximum-size-limit-for-Pearl.patch sgt-puzzles-20191231.79a5378/debian/patches/0330-Last-ditch-maximum-size-limit-for-Pearl.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0330-Last-ditch-maximum-size-limit-for-Pearl.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0330-Last-ditch-maximum-size-limit-for-Pearl.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:39:57 +0000 +Subject: [PATCH 330/389] Last-ditch maximum size limit for Pearl +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=8a3fb82e230c5cf18b82f54687c2a56f53875a38 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + pearl.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/pearl.c ++++ b/pearl.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -272,6 +273,8 @@ static const char *validate_params(const + { + if (params->w < 5) return "Width must be at least five"; + if (params->h < 5) return "Height must be at least five"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT) + return "Unknown difficulty level"; + if (params->difficulty >= DIFF_TRICKY && params->w + params->h < 11) diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0331-Last-ditch-maximum-size-limit-for-Pegs.patch sgt-puzzles-20191231.79a5378/debian/patches/0331-Last-ditch-maximum-size-limit-for-Pegs.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0331-Last-ditch-maximum-size-limit-for-Pegs.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0331-Last-ditch-maximum-size-limit-for-Pegs.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,42 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:30:48 +0000 +Subject: [PATCH 331/389] Last-ditch maximum size limit for Pegs +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=6e40605f1ed4ecce400faae5b41c03995e7f862c +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + pegs.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/pegs.c ++++ b/pegs.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -182,6 +183,8 @@ static const char *validate_params(const + { + if (full && (params->w <= 3 || params->h <= 3)) + return "Width and height must both be greater than three"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + /* + * It might be possible to implement generalisations of Cross +@@ -658,7 +661,9 @@ static char *new_game_desc(const game_pa + + static const char *validate_desc(const game_params *params, const char *desc) + { +- int len = params->w * params->h; ++ int len; ++ ++ len = params->w * params->h; + + if (len != strlen(desc)) + return "Game description is wrong length"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch sgt-puzzles-20191231.79a5378/debian/patches/0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,22 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 00:32:25 +0000 +Subject: [PATCH 332/389] Also limit Pegs to at least 1x1 even when not doing + full validation +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b090c82df1527dcf348c96765f10ab5736c68c29 +Bug-Debian: https://bugs.debian.org/1028986 + +--- + pegs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/pegs.c ++++ b/pegs.c +@@ -183,6 +183,8 @@ static const char *validate_params(const + { + if (full && (params->w <= 3 || params->h <= 3)) + return "Width and height must both be greater than three"; ++ if (params->w < 1 || params->h < 1) ++ return "Width and height must both be at least one"; + if (params->w > INT_MAX / params->h) + return "Width times height must not be unreasonably large"; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0333-Last-ditch-maximum-size-limit-for-Same-Game.patch sgt-puzzles-20191231.79a5378/debian/patches/0333-Last-ditch-maximum-size-limit-for-Same-Game.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0333-Last-ditch-maximum-size-limit-for-Same-Game.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0333-Last-ditch-maximum-size-limit-for-Same-Game.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 10:54:37 +0000 +Subject: [PATCH 333/389] Last-ditch maximum size limit for Same Game +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d5ec2758ee3b7a8934475a1122813ad2312dc850 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + samegame.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/samegame.c ++++ b/samegame.c +@@ -67,6 +67,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -285,6 +286,8 @@ static const char *validate_params(const + { + if (params->w < 1 || params->h < 1) + return "Width and height must both be positive"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + if (params->ncols > 9) + return "Maximum of 9 colours"; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0334-Last-ditch-maximum-size-limit-for-Signpost.patch sgt-puzzles-20191231.79a5378/debian/patches/0334-Last-ditch-maximum-size-limit-for-Signpost.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0334-Last-ditch-maximum-size-limit-for-Signpost.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0334-Last-ditch-maximum-size-limit-for-Signpost.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:41:24 +0000 +Subject: [PATCH 334/389] Last-ditch maximum size limit for Signpost +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5c36e1536a05abf514b09476813cf71bc9dc1e31 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + signpost.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/signpost.c ++++ b/signpost.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -421,6 +422,8 @@ static const char *validate_params(const + { + if (params->w < 1) return "Width must be at least one"; + if (params->h < 1) return "Height must be at least one"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + if (full && params->w == 1 && params->h == 1) + /* The UI doesn't let us move these from unsolved to solved, + * so we disallow generating (but not playing) them. */ diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0335-Last-ditch-maximum-size-limit-for-Sixteen.patch sgt-puzzles-20191231.79a5378/debian/patches/0335-Last-ditch-maximum-size-limit-for-Sixteen.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0335-Last-ditch-maximum-size-limit-for-Sixteen.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0335-Last-ditch-maximum-size-limit-for-Sixteen.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:24:59 +0000 +Subject: [PATCH 335/389] Last-ditch maximum size limit for Sixteen +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=91d96fa0bc133c8d967f3c4b01804e7773de8504 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + sixteen.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sixteen.c ++++ b/sixteen.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -173,6 +174,8 @@ static const char *validate_params(const + { + if (params->w < 2 || params->h < 2) + return "Width and height must both be at least two"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch sgt-puzzles-20191231.79a5378/debian/patches/0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,30 @@ +From: Ben Harris +Date: Thu, 12 Jan 2023 14:34:14 +0000 +Subject: [PATCH 336/389] Limit size of puzzle in Tents to avoid integer + overflow +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=07999443c24414602cf046fefc84d1d17b5afd69 +Bug-Debian: https://bugs.debian.org/1028986 + +--- + tents.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/tents.c ++++ b/tents.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -408,6 +409,8 @@ static const char *validate_params(const + */ + if (params->w < 4 || params->h < 4) + return "Width and height must both be at least four"; ++ if (params->w > (INT_MAX - 1) / params->h) ++ return "Width times height must not be unreasonably large"; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0337-Last-ditch-maximum-size-limit-for-Tracks.patch sgt-puzzles-20191231.79a5378/debian/patches/0337-Last-ditch-maximum-size-limit-for-Tracks.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0337-Last-ditch-maximum-size-limit-for-Tracks.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0337-Last-ditch-maximum-size-limit-for-Tracks.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:39:06 +0000 +Subject: [PATCH 337/389] Last-ditch maximum size limit for Tracks +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c53e0d386793840ad84b8bbcb4760cfb2b6897d4 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + tracks.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/tracks.c ++++ b/tracks.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -191,6 +192,8 @@ static const char *validate_params(const + */ + if (params->w < 4 || params->h < 4) + return "Width and height must both be at least four"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0338-Last-ditch-maximum-size-limit-for-Twiddle.patch sgt-puzzles-20191231.79a5378/debian/patches/0338-Last-ditch-maximum-size-limit-for-Twiddle.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0338-Last-ditch-maximum-size-limit-for-Twiddle.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0338-Last-ditch-maximum-size-limit-for-Twiddle.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:28:19 +0000 +Subject: [PATCH 338/389] Last-ditch maximum size limit for Twiddle +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=51dcf4add6e046568557cee2fa01975f14716889 +Bug-Debian: https://bugs.debian.org/1028986 + +This makes sure that width * height <= INT_MAX, which it rather needs +to be. +--- + twiddle.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/twiddle.c ++++ b/twiddle.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -210,6 +211,8 @@ static const char *validate_params(const + return "Width must be at least the rotating block size"; + if (params->h < params->n) + return "Height must be at least the rotating block size"; ++ if (params->w > INT_MAX / params->h) ++ return "Width times height must not be unreasonably large"; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch sgt-puzzles-20191231.79a5378/debian/patches/0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,23 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:34:06 +0000 +Subject: [PATCH 339/389] Adjust Undead upper grid-size limit to avoid overflow +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=85ccdf2f75e3ea55d5e92d9790e50394e1bec089 +Bug-Debian: https://bugs.debian.org/1028986 + +--- + undead.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/undead.c ++++ b/undead.c +@@ -193,9 +193,9 @@ static game_params *custom_params(const + + static const char *validate_params(const game_params *params, bool full) + { +- if ((params->w * params->h ) > 54) return "Grid is too big"; + if (params->w < 3) return "Width must be at least 3"; + if (params->h < 3) return "Height must be at least 3"; ++ if (params->w > 54 / params->h) return "Grid is too big"; + if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; + return NULL; + } diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0340-Last-ditch-point-count-limit-for-Untangle.patch sgt-puzzles-20191231.79a5378/debian/patches/0340-Last-ditch-point-count-limit-for-Untangle.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0340-Last-ditch-point-count-limit-for-Untangle.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0340-Last-ditch-point-count-limit-for-Untangle.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,31 @@ +From: Ben Harris +Date: Tue, 10 Jan 2023 20:46:24 +0000 +Subject: [PATCH 340/389] Last-ditch point-count limit for Untangle +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d5b8a20def7634d4df79800fe54d8e34c6353974 +Bug-Debian: https://bugs.debian.org/1028986 + +Anything over INT_MAX/3 will cause an integer overflow, so put the +limit there for now. +--- + untangle.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/untangle.c ++++ b/untangle.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + + #include "puzzles.h" +@@ -206,6 +207,8 @@ static const char *validate_params(const + { + if (params->n < 4) + return "Number of points must be at least four"; ++ if (params->n > INT_MAX / 3) ++ return "Number of points must not be unreasonably large"; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch sgt-puzzles-20191231.79a5378/debian/patches/0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,28 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 10:03:10 +0000 +Subject: [PATCH 341/389] Black Box: correct order of validation checks for "F" + commands +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=c2eedeedfe3c48f3f013fb1308f61d7ef94e8b2c +Bug-Debian: https://bugs.debian.org/1028986 + +It doesn't do much good to range-check an argument after using it as +an array index. +--- + blackbox.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/blackbox.c ++++ b/blackbox.c +@@ -1032,10 +1032,10 @@ static game_state *execute_move(const ga + + case 'F': + sscanf(move+1, "%d", &rangeno); +- if (ret->exits[rangeno] != LASER_EMPTY) +- goto badmove; + if (!RANGECHECK(ret, rangeno)) + goto badmove; ++ if (ret->exits[rangeno] != LASER_EMPTY) ++ goto badmove; + fire_laser(ret, rangeno); + break; + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0342-Palisade-don-t-leak-memory-on-a-bad-move.patch sgt-puzzles-20191231.79a5378/debian/patches/0342-Palisade-don-t-leak-memory-on-a-bad-move.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0342-Palisade-don-t-leak-memory-on-a-bad-move.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0342-Palisade-don-t-leak-memory-on-a-bad-move.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,41 @@ +From: Ben Harris +Date: Thu, 12 Jan 2023 21:00:22 +0000 +Subject: [PATCH 342/389] Palisade: don't leak memory on a bad move +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=38cf1955e5861f67d385ede006c5b5d1701aca8d +Bug-Debian: https://bugs.debian.org/1028986 + +Invalid moves can turn up in corrupted save files, and puzzles +shouldn't leak memory when failing to load a corrupted save file. +--- + palisade.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/palisade.c ++++ b/palisade.c +@@ -1018,7 +1018,7 @@ static game_state *execute_move(const ga + for (i = 0; i < wh && move[i]; ++i) + ret->borders[i] = + (move[i] & BORDER_MASK) | DISABLED(~move[i] & BORDER_MASK); +- if (i < wh || move[i]) return NULL; /* leaks `ret', then we die */ ++ if (i < wh || move[i]) goto badmove; + ret->cheated = ret->completed = true; + return ret; + } +@@ -1034,7 +1034,7 @@ static game_state *execute_move(const ga + ret->borders[y*w + x] ^= flag; + } + +- if (*move) return NULL; /* leaks `ret', then we die */ ++ if (*move) goto badmove; + + if (!ret->completed) + ret->completed = is_solved(&ret->shared->params, ret->shared->clues, +@@ -1043,7 +1043,7 @@ static game_state *execute_move(const ga + return ret; + + badmove: +- sfree(ret); ++ free_game(ret); + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0343-Don-t-allow-negative-clues-in-Pattern.patch sgt-puzzles-20191231.79a5378/debian/patches/0343-Don-t-allow-negative-clues-in-Pattern.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0343-Don-t-allow-negative-clues-in-Pattern.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0343-Don-t-allow-negative-clues-in-Pattern.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,21 @@ +From: Ben Harris +Date: Thu, 12 Jan 2023 21:09:39 +0000 +Subject: [PATCH 343/389] Don't allow negative clues in Pattern +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=e5d106eb279c12d2454802421e723873e4bae6c2 +Bug-Debian: https://bugs.debian.org/1028986 + +--- + pattern.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/pattern.c ++++ b/pattern.c +@@ -912,6 +912,8 @@ static const char *validate_desc(const g + p = desc; + while (*desc && isdigit((unsigned char)*desc)) desc++; + n = atoi(p); ++ if (n < 0) ++ return "at least one clue is negative"; + if (n > INT_MAX - 1) + return "at least one clue is grossly excessive"; + rowspace -= n+1; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch sgt-puzzles-20191231.79a5378/debian/patches/0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,24 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 19:06:51 +0000 +Subject: [PATCH 344/389] When loading, don't decode_ui unless we have a UI +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=68f9fae973e2ffb6c0b9ed1e0761d3a0768455ad +Bug-Debian: https://bugs.debian.org/1028986 + +If the save file doesn't have a UI line, it's not sensible to try to +decode it. +--- + midend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/midend.c ++++ b/midend.c +@@ -2386,7 +2386,8 @@ static const char *midend_deserialise_in + } + + data.ui = me->ourgame->new_ui(data.states[0].state); +- me->ourgame->decode_ui(data.ui, data.uistr); ++ if (data.uistr) ++ me->ourgame->decode_ui(data.ui, data.uistr); + + /* + * Run the externally provided check function, and abort if it diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0346-Palisade-remove-assertion-from-decode_ui.patch sgt-puzzles-20191231.79a5378/debian/patches/0346-Palisade-remove-assertion-from-decode_ui.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0346-Palisade-remove-assertion-from-decode_ui.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0346-Palisade-remove-assertion-from-decode_ui.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,24 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 22:29:17 +0000 +Subject: [PATCH 346/389] Palisade: remove assertion from decode_ui() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0dbbd52935b8b17b3b3ab3d9ae6271cde891f70b +Bug-Debian: https://bugs.debian.org/1028986 + +Other games tolerate receiving an encoded game_ui even if they can +never generate one. This is sensible, since it means that if a new +version starts saving UI state, old versions can load save files +generated by those newer versions. +--- + palisade.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/palisade.c ++++ b/palisade.c +@@ -892,7 +892,6 @@ static char *encode_ui(const game_ui *ui + + static void decode_ui(game_ui *ui, const char *encoding) + { +- assert (encoding == NULL); + } + + static void game_changed_state(game_ui *ui, const game_state *oldstate, diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0347-Same-Game-reject-moves-with-unexpected-characters-in.patch sgt-puzzles-20191231.79a5378/debian/patches/0347-Same-Game-reject-moves-with-unexpected-characters-in.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0347-Same-Game-reject-moves-with-unexpected-characters-in.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0347-Same-Game-reject-moves-with-unexpected-characters-in.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,26 @@ +From: Ben Harris +Date: Sat, 7 Jan 2023 23:24:39 +0000 +Subject: [PATCH 347/389] Same Game: reject moves with unexpected characters in +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=8c5279cf75e41f1ae75b2daf0d06c883a5ae0bca +Bug-Debian: https://bugs.debian.org/1028986 + +Previously if a move string starting with "M" contained anything else +other than a digit or a comma, execute_move() would spin trying to +parse it. Now it returns NULL. +--- + samegame.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/samegame.c ++++ b/samegame.c +@@ -1327,6 +1327,10 @@ static game_state *execute_move(const ga + move++; + + while (*move) { ++ if (!isdigit((unsigned char)*move)) { ++ free_game(ret); ++ return NULL; ++ } + i = atoi(move); + if (i < 0 || i >= ret->n) { + free_game(ret); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0349-Filling-validate-length-of-auto-solve-move-strings.patch sgt-puzzles-20191231.79a5378/debian/patches/0349-Filling-validate-length-of-auto-solve-move-strings.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0349-Filling-validate-length-of-auto-solve-move-strings.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0349-Filling-validate-length-of-auto-solve-move-strings.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,33 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 09:57:53 +0000 +Subject: [PATCH 349/389] Filling: validate length of auto-solve move strings +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=8a06ff26fc6abd77a4b4a08b839943f588d92dcf +Bug-Debian: https://bugs.debian.org/1028986 + +Without this, execute_move() can end up reading off the end of the +move string, which isn't very friendly. Also remove the comment +saying that the move string doesn't have to be null-terminated, +because now it does. +--- + filling.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/filling.c ++++ b/filling.c +@@ -1105,8 +1105,6 @@ static bool solver(const int *orig, int + **solution = 's'; + for (i = 0; i < sz; ++i) (*solution)[i + 1] = ss.board[i] + '0'; + (*solution)[sz + 1] = '\0'; +- /* We don't need the \0 for execute_move (the only user) +- * I'm just being printf-friendly in case I wanna print */ + } + + sfree(ss.dsf); +@@ -1567,6 +1565,7 @@ static game_state *execute_move(const ga + + if (*move == 's') { + int i = 0; ++ if (strlen(move) != sz + 1) return NULL; + new_state = dup_game(state); + for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0'; + new_state->cheated = true; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0350-Tighten-Bridges-validate_desc.patch sgt-puzzles-20191231.79a5378/debian/patches/0350-Tighten-Bridges-validate_desc.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0350-Tighten-Bridges-validate_desc.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0350-Tighten-Bridges-validate_desc.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,29 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 10:42:45 +0000 +Subject: [PATCH 350/389] Tighten Bridges' validate_desc() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=ba944f9f95238d0b820e63d9b6c2d83efc09b8a2 +Bug-Debian: https://bugs.debian.org/1028986 + +It allowed V, W, X, Y, H, I, J, and K to appear in game descriptions +even though new_game() didn't ascribe any meaning to those letters and +would fail an assertion if they ever occurred. As far as I can tell, +those letters have never done anything, so I've just removed the +checks for them from validate_desc(). +--- + bridges.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/bridges.c ++++ b/bridges.c +@@ -2016,11 +2016,6 @@ static const char *validate_desc(const g + i += *desc - 'a'; /* plus the i++ */ + else if (*desc >= 'A' && *desc <= 'G') + /* OK */; +- else if (*desc == 'V' || *desc == 'W' || +- *desc == 'X' || *desc == 'Y' || +- *desc == 'H' || *desc == 'I' || +- *desc == 'J' || *desc == 'K') +- /* OK */; + else if (!*desc) + return "Game description shorter than expected"; + else diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch sgt-puzzles-20191231.79a5378/debian/patches/0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,24 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 12:34:57 +0000 +Subject: [PATCH 351/389] Untangle: forbid descriptions that connect a node to + itself +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=d3290195da55beae04d1bb86f811b6f8dd6b0663 +Bug-Debian: https://bugs.debian.org/1028986 + +These cause an assertion failure in new_game(), so they should be +rejected by validate_desc(). +--- + untangle.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/untangle.c ++++ b/untangle.c +@@ -755,6 +755,8 @@ static const char *validate_desc(const g + return "Expected ',' after number in game description"; + desc++; /* eat comma */ + } ++ if (a == b) ++ return "Node linked to itself in game description"; + } + + return NULL; diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0352-Mines-No-moving-once-you-re-dead.patch sgt-puzzles-20191231.79a5378/debian/patches/0352-Mines-No-moving-once-you-re-dead.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0352-Mines-No-moving-once-you-re-dead.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0352-Mines-No-moving-once-you-re-dead.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,26 @@ +From: Ben Harris +Date: Sun, 8 Jan 2023 21:59:27 +0000 +Subject: [PATCH 352/389] Mines: No moving once you're dead! +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5bd02f982a878312065b4d81d05a90bc41a98c6c +Bug-Debian: https://bugs.debian.org/1028986 + +If a Mines save file contains a move after the player has already +died, this can lead to an assertion failure once there are more mines +that covered squares. Better to just reject any move after the +player's died. +--- + mines.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/mines.c ++++ b/mines.c +@@ -2661,6 +2661,9 @@ static game_state *execute_move(const ga + + return ret; + } else { ++ /* Dead players should stop trying to move. */ ++ if (from->dead) ++ return NULL; + ret = dup_game(from); + + while (*move) { diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0353-Towers-reject-descriptions-with-odd-characters-at-th.patch sgt-puzzles-20191231.79a5378/debian/patches/0353-Towers-reject-descriptions-with-odd-characters-at-th.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0353-Towers-reject-descriptions-with-odd-characters-at-th.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0353-Towers-reject-descriptions-with-odd-characters-at-th.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,27 @@ +From: Ben Harris +Date: Mon, 9 Jan 2023 15:07:24 +0000 +Subject: [PATCH 353/389] Towers: reject descriptions with odd characters at + the end +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=15974d06bbaad287382c6eeb8deb7c6f3a627278 +Bug-Debian: https://bugs.debian.org/1028986 + +Towers' new_game() causes an assertion failure on game description +strings that contain spurious characters after a valid description, so +validate_desc() should also refuse such a description. The problem +could be demonstrated by editing the game description in the +"Specific" dialogue box to add a '!' at the end, which caused +"new_game: Assertion `!*p' failed.". +--- + towers.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/towers.c ++++ b/towers.c +@@ -861,6 +861,7 @@ static const char *validate_desc(const g + return "Too much data to fit in grid"; + } + ++ if (*p) return "Rubbish at end of game description"; + return NULL; + } + diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch sgt-puzzles-20191231.79a5378/debian/patches/0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,37 @@ +From: Ben Harris +Date: Mon, 9 Jan 2023 20:24:15 +0000 +Subject: [PATCH 354/389] Tracks: make sure moves are valid in execute_move() +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=5782e29db43034574763b1d10c48486c3e95f0d2 +Bug-Debian: https://bugs.debian.org/1028986 + +Tracks allowed moves in execute_move() that shouldn't have been allowed, +like changing the state of the edges of the board. This moves couldn't +be generated by interpret_move(), but could be loaded from a save file. +Now execute_move() uses the same ui_can_flip_*() functions as +interpret_move() to decide whether a particular move is allowed. This +should prevent some assertion failures when loading corrupted save +files. +--- + tracks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/tracks.c ++++ b/tracks.c +@@ -2078,6 +2078,8 @@ static game_state *execute_move(const ga + f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK; + + if (d == 'S') { ++ if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK)) ++ goto badmove; + if (c == 'T' || c == 'N') + ret->sflags[y*w+x] |= f; + else +@@ -2087,6 +2089,8 @@ static game_state *execute_move(const ga + unsigned df = 1< +Date: Wed, 18 Jan 2023 20:58:31 +0000 +Subject: [PATCH 360/389] Tracks: let solve make illegal moves +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b5e02b0b9c1b35b0b907bf6d63e62b9fafd9cb7e +Bug-Debian: https://bugs.debian.org/1028986 + +Not only does it set the outer edges to NOTRACK, but it may also overwrite +any mistakes the user has previously made elsewhere. Otherwise, the entire +solve is rejected ("Solve unavailable" error on Android) if the user has +made a single mistake, which is inconsistent with the other games. + +This may be giving a free pass to corrupted moves that occur after a solve, +so this may still want tightening up in some way, but it's still limited to +squares within the grid, so I agree with Ben's assessment that this is +likely not to be exploitable. + +Fixes #584 + +(cherry picked from Android port, commit +33bd14fb6f7cd760e7218fffd90f3a266b1f4123) +--- + tracks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/tracks.c ++++ b/tracks.c +@@ -2078,7 +2078,7 @@ static game_state *execute_move(const ga + f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK; + + if (d == 'S') { +- if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK)) ++ if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK) && !ret->used_solve) + goto badmove; + if (c == 'T' || c == 'N') + ret->sflags[y*w+x] |= f; +@@ -2089,7 +2089,7 @@ static game_state *execute_move(const ga + unsigned df = 1<used_solve) + goto badmove; + if (c == 'T' || c == 'N') + S_E_SET(ret, x, y, df, f); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch sgt-puzzles-20191231.79a5378/debian/patches/0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,55 @@ +From: Simon Tatham +Date: Thu, 19 Jan 2023 12:47:55 +0000 +Subject: [PATCH 361/389] Tracks: tighten up the 'illegal solve submoves' fix. +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=b4aaa11943fb72b09fe173bc97bd9313ff94738c +Bug-Debian: https://bugs.debian.org/1028986 + +Chris mentioned in the commit message that there was a risk that +illegal moves might be permitted when playing on after a solve. So +I've changed the condition so that it depends only on whether the move +_currently being executed_ is a solve, rather than whether there was a +solve action anywhere in the undo history. + +(Also, wrapped overlong lines while I was here.) +--- + tracks.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/tracks.c ++++ b/tracks.c +@@ -2057,6 +2057,7 @@ static game_state *execute_move(const ga + int w = state->p.w, x, y, n, i; + char c, d; + unsigned f; ++ bool move_is_solve = false; + game_state *ret = dup_game(state); + + /* this is breaking the bank on GTK, which vsprintf's into a fixed-size buffer +@@ -2067,6 +2068,7 @@ static game_state *execute_move(const ga + c = *move; + if (c == 'S') { + ret->used_solve = true; ++ move_is_solve = true; + move++; + } else if (c == 'T' || c == 't' || c == 'N' || c == 'n') { + /* set track, clear track; set notrack, clear notrack */ +@@ -2078,7 +2080,8 @@ static game_state *execute_move(const ga + f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK; + + if (d == 'S') { +- if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK) && !ret->used_solve) ++ if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK) && ++ !move_is_solve) + goto badmove; + if (c == 'T' || c == 'N') + ret->sflags[y*w+x] |= f; +@@ -2089,7 +2092,8 @@ static game_state *execute_move(const ga + unsigned df = 1<used_solve) ++ if (!ui_can_flip_edge(ret, x, y, df, f == S_NOTRACK) && ++ !move_is_solve) + goto badmove; + if (c == 'T' || c == 'N') + S_E_SET(ret, x, y, df, f); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/0362-Allow-repeated-solve-operations-in-Guess.patch sgt-puzzles-20191231.79a5378/debian/patches/0362-Allow-repeated-solve-operations-in-Guess.patch --- sgt-puzzles-20191231.79a5378/debian/patches/0362-Allow-repeated-solve-operations-in-Guess.patch 1970-01-01 00:00:00.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/0362-Allow-repeated-solve-operations-in-Guess.patch 2023-04-23 19:12:49.000000000 +0000 @@ -0,0 +1,37 @@ +From: Ben Harris +Date: Thu, 19 Jan 2023 20:26:23 +0000 +Subject: [PATCH 362/389] Allow repeated "solve" operations in Guess +Origin: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=27c97c0ffdda0b91fecf155f3bc29b32ed806bb2 +Bug-Debian: https://bugs.debian.org/1028986 + +Since using the "solve" option doesn't consume a guess, it's safe to +allow it to occur multiple times. Without this, selecting "solve" a +second time causes an assertion failure because solve() returns a move +string that's rejected by execute_move(). + +Possible solve() could instead refuse to solve an already-solved +puzzle, but that seems needlessly pedantic. + +[fixes c84af670b52f09e9e47587584c0559c508d4a37d] +--- + guess.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/guess.c ++++ b/guess.c +@@ -924,13 +924,13 @@ static game_state *execute_move(const ga + game_state *ret; + const char *p; + +- /* No moves are allowed once the game is solved. */ +- if (from->solved) return NULL; + if (!strcmp(move, "S")) { + ret = dup_game(from); + ret->solved = -1; + return ret; + } else if (move[0] == 'G') { ++ /* No guesses are allowed once the game is solved. */ ++ if (from->solved) return NULL; + p = move+1; + + ret = dup_game(from); diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/102_fix-pearl-min-dimensions.diff sgt-puzzles-20191231.79a5378/debian/patches/102_fix-pearl-min-dimensions.diff --- sgt-puzzles-20191231.79a5378/debian/patches/102_fix-pearl-min-dimensions.diff 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/102_fix-pearl-min-dimensions.diff 2023-04-23 19:12:52.000000000 +0000 @@ -1,8 +1,8 @@ From: Ben Hutchings Date: Fri, 10 Aug 2018 07:00:06 +0100 Subject: pearl: Require width or height to be at least 6 for Tricky - Bug-Debian: https://bugs.debian.org/667963 +Applied-Upstream: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=49dbf1f60dc5c6bcb6b3ffadf89e7e0c14106638 Josh Triplett reported: > If I ask pearl to generate a 5x5 tricky puzzle, it runs forever. diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/fix-ftbfs-with-gcc-6.patch sgt-puzzles-20191231.79a5378/debian/patches/fix-ftbfs-with-gcc-6.patch --- sgt-puzzles-20191231.79a5378/debian/patches/fix-ftbfs-with-gcc-6.patch 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/fix-ftbfs-with-gcc-6.patch 2023-04-23 19:12:52.000000000 +0000 @@ -1,8 +1,8 @@ From: Ben Hutchings Date: Thu, 30 Jun 2016 14:43:16 +0200 Subject: Fix FTBFS with gcc 6 - Bug-Debian: https://bugs.debian.org/811577 +Applied-Upstream: https://git.tartarus.org/?p=simon/puzzles.git;a=commitdiff;h=0dc46506ca85eb49299fc62a4362c8a4a655e320 gcc 6 warns about statements that are indented as if they were meant to be part of a preceding conditional block. In this case I don't think that was diff -Nru sgt-puzzles-20191231.79a5378/debian/patches/series sgt-puzzles-20191231.79a5378/debian/patches/series --- sgt-puzzles-20191231.79a5378/debian/patches/series 2020-02-02 14:30:23.000000000 +0000 +++ sgt-puzzles-20191231.79a5378/debian/patches/series 2023-04-23 19:12:52.000000000 +0000 @@ -13,3 +13,132 @@ 0013-bridges-Fix-off-by-one-in-WITHIN.patch 0014-pattern-Fix-build-failure-with-fortify-and-gcc-9-on-.patch 0015-Update-German-translation-thanks-to-Helge-Kreutzmann.patch +0007-Mines-add-validation-for-negative-mine-count.patch +0023-Galaxies-fix-assertion-failure-when-adding-out-of-bo.patch +0028-Filling-fix-assertion-failure-in-3x1-game-generation.patch +0081-Map-add-missing-sresize-in-new_game_desc.patch +0114-Add-more-validation-to-midend-deserialisation-routin.patch +0115-Correct-and-enable-the-range-check-on-statepos-when-.patch +0121-Add-an-assertion-to-check-the-format-of-encoded-para.patch +0122-Add-assertions-that-game-descriptions-consist-only-o.patch +0123-Hex-encode-non-ASCII-random-seeds-in-save-files.patch +0124-Assert-that-everything-written-to-a-save-file-is-pri.patch +0129-Build-fix-take-declarations-out-of-for-loops.patch +0246-galaxies-Use-the-same-code-for-handling-all-dropped-.patch +0263-magnets-Area-constraints-fix-message.patch +0266-lightup-Ban-2x2-with-either-4-way-type.patch +0267-Remove-_-introduced-from-Android-port.patch +0269-Solo-Set-max-difficulty-for-small-jigsaw-puzzles.patch +0285-Add-a-macro-of-an-upper-bound-on-the-formatted-lengt.patch +0299-Guess-Don-t-allow-any-moves-once-the-game-is-solved.patch +0300-Guess-validate-peg-colours-in-decode_ui.patch +0302-Netslide-Reject-moves-wider-than-the-grid.patch +0303-Sixteen-limit-length-of-moves.patch +0304-Undead-check-for-valid-commands-in-execute_move.patch +0305-Undead-fix-buffer-overrun-in-M-command.patch +0306-Correct-RANGECHECK-macro-in-Black-Box.patch +0307-Range-check-normal-moves-in-Undead.patch +0308-Range-check-record-lengths-when-deserialising-games.patch +0309-Don-t-load-too-many-states-just-because-there-s-no-S.patch +0310-Palisade-forbid-moves-that-remove-grid-edges.patch +0311-Last-ditch-maximum-size-limit-for-Bridges.patch +0312-Last-ditch-grid-size-limit-for-Dominosa.patch +0313-Last-ditch-grid-size-limit-for-Galaxies.patch +0314-Last-ditch-grid-size-limit-for-Fifteen.patch +0315-Last-ditch-maximum-size-limit-for-Flip.patch +0316-Last-ditch-grid-size-limit-for-Flood.patch +0317-Insist-that-Flood-grids-must-have-non-zero-size.patch +0318-Last-ditch-grid-size-limit-for-Inertia.patch +0319-Last-ditch-maximum-size-limit-for-Light-Up.patch +0320-Limit-maximum-grid-size-in-Loopy.patch +0321-Last-ditch-maximum-size-limit-for-Magnets.patch +0322-Last-ditch-maximum-size-limit-for-Map.patch +0323-Last-ditch-maximum-size-limit-for-Mines.patch +0324-Also-check-for-tiny-grids-in-Mines.patch +0326-Last-ditch-maximum-size-limit-for-Net.patch +0327-Last-ditch-maximum-size-limit-for-Netslide.patch +0328-Integer-overflow-protection-in-Pattern.patch +0329-Last-ditch-maximum-size-limit-for-Palisade.patch +0330-Last-ditch-maximum-size-limit-for-Pearl.patch +0331-Last-ditch-maximum-size-limit-for-Pegs.patch +0332-Also-limit-Pegs-to-at-least-1x1-even-when-not-doing-.patch +0333-Last-ditch-maximum-size-limit-for-Same-Game.patch +0334-Last-ditch-maximum-size-limit-for-Signpost.patch +0335-Last-ditch-maximum-size-limit-for-Sixteen.patch +0336-Limit-size-of-puzzle-in-Tents-to-avoid-integer-overf.patch +0337-Last-ditch-maximum-size-limit-for-Tracks.patch +0338-Last-ditch-maximum-size-limit-for-Twiddle.patch +0339-Adjust-Undead-upper-grid-size-limit-to-avoid-overflo.patch +0340-Last-ditch-point-count-limit-for-Untangle.patch +0341-Black-Box-correct-order-of-validation-checks-for-F-c.patch +0342-Palisade-don-t-leak-memory-on-a-bad-move.patch +0343-Don-t-allow-negative-clues-in-Pattern.patch +0344-When-loading-don-t-decode_ui-unless-we-have-a-UI.patch +0346-Palisade-remove-assertion-from-decode_ui.patch +0347-Same-Game-reject-moves-with-unexpected-characters-in.patch +0349-Filling-validate-length-of-auto-solve-move-strings.patch +0350-Tighten-Bridges-validate_desc.patch +0351-Untangle-forbid-descriptions-that-connect-a-node-to-.patch +0352-Mines-No-moving-once-you-re-dead.patch +0353-Towers-reject-descriptions-with-odd-characters-at-th.patch +0354-Tracks-make-sure-moves-are-valid-in-execute_move.patch +0360-Tracks-let-solve-make-illegal-moves.patch +0361-Tracks-tighten-up-the-illegal-solve-submoves-fix.patch +0362-Allow-repeated-solve-operations-in-Guess.patch +0001-Black-Box-reject-negative-ball-counts-in-game_params.patch +0002-Add-validate_params-bounds-checks-in-a-few-more-game.patch +0006-Don-t-allow-Bridges-games-with-2-islands.patch +0007-Forbid-moves-that-fill-with-the-current-colour-in-Fl.patch +0008-Cleanly-reject-ill-formed-solve-moves-in-Flood.patch +0009-Don-t-segfault-on-premature-solve-moves-in-Mines.patch +0010-Limit-number-of-mines-in-Mines-game-description.patch +0011-Validate-the-number-of-pegs-and-holes-in-a-Pegs-game.patch +0017-Mines-forbid-moves-that-flag-or-unflag-an-exposed-sq.patch +0018-Mines-Don-t-check-if-the-player-has-won-if-they-ve-a.patch +0019-Avoid-invalid-moves-when-solving-Tracks.patch +0020-Fix-move-validation-in-Netslide.patch +0021-Tighten-validation-of-Tents-game-descriptions.patch +0022-Dominosa-require-the-two-halves-of-a-domino-to-be-ad.patch +0023-Forbid-lines-off-the-grid-in-Pearl.patch +0024-Tolerate-incorrect-solutions-in-Inertia.patch +0025-Palisade-replace-dfs_dsf-with-a-simple-iteration.patch +0026-latin_solver_alloc-handle-clashing-numbers-in-input-.patch +0027-Pearl-fix-assertion-failure-on-bad-puzzle.patch +0028-Pearl-fix-bounds-check-in-previous-commit.patch +0029-Unequal-Don-t-insist-that-solve-moves-must-actually-.patch +0030-Range-Don-t-fail-an-assertion-on-an-all-black-board.patch +0031-Limit-width-and-height-to-SHRT_MAX-in-Mines.patch +0032-Mines-Add-assertions-to-range-check-conversions-to-s.patch +0033-Unequal-fix-sense-error-in-latin_solver_alloc-fix.patch +0034-Forbid-impossible-moves-in-Bridges.patch +0035-Forbid-game-descriptions-with-joined-islands-in-Brid.patch +0037-Check-state-is-valid-at-the-end-of-a-move-in-Pearl.patch +0038-Cleanly-reject-more-ill-formed-solve-moves-in-Flood.patch +0039-Don-t-allow-moves-that-change-the-constraints-in-Une.patch +0041-Fix-memory-leaks-in-Keen-s-validate_desc.patch +0043-Don-t-leak-grids-in-Loopy-s-validate_desc.patch +0044-Remember-to-free-the-to_draw-member-from-Net-s-draws.patch +0045-Undead-check-the-return-value-of-sscanf-in-execute_m.patch +0046-Don-t-leak-duplicate-edges-in-Untangle.patch +0047-Remember-to-free-the-numcolours-array-from-Pattern-s.patch +0049-Twiddle-don-t-read-off-the-end-of-parameter-strings-.patch +0050-Loopy-free-the-grid-description-string-if-it-s-inval.patch +0052-Avoid-division-by-zero-in-Cube-grid-size-checks.patch +0055-Validate-that-save-file-values-are-ASCII-mostly.patch +0056-More-validation-of-solve-moves-in-Flood.patch +0058-Make-sure-that-moves-in-Flood-use-only-valid-colours.patch +0059-Tighten-grid-size-limit-in-Mines.patch +0061-Solo-cope-with-pencil-marks-when-tilesize-1.patch +0065-Tracks-set-drag_s-x-y-even-if-starting-off-grid.patch +0080-Undead-be-a-bit-more-careful-about-sprintf-buffer-si.patch +0090-Fix-memory-leak-in-midend_game_id_int.patch +0092-Flood-don-t-read-off-the-end-of-some-parameter-strin.patch +0101-Be-more-careful-with-type-of-left-operand-of.patch +0102-Map-reduce-maximum-size.patch +0103-Correctly-handle-some-short-save-files.patch +0104-Inertia-insist-that-solutions-must-be-non-empty.patch +0115-Galaxies-fix-recursion-depth-limit-in-solver.patch +0138-Correct-a-range-check-in-Magnets-layout-verification.patch +0139-Magnets-add-a-check-that-magnets-don-t-wrap-between-.patch +0155-Net-assert-that-cx-and-cy-are-in-range-in-compute_ac.patch +0159-Don-t-allow-zero-clues-in-Pattern.patch