From 83b637aa738fe6e06b50003fcc1a4ebdb899d25a Mon Sep 17 00:00:00 2001 From: "Marco Antonio J. Costa" Date: Thu, 23 Jul 2026 17:02:06 -0300 Subject: [PATCH] libsmacker: allow overlapping copies in the 0x40 palette opcode The color-shift opcode copies a run of palette entries from the previous frame's palette to the current one. libsmacker rejected the copy when the source and destination ranges overlapped, aborting the whole palette decode and leaving the palette half-updated -- so every frame from the first such opcode on rendered with a mix of the new and stale palette. The overlap check is bogus: the copy reads from oldPalette, a snapshot taken at the top of the function, and writes into s->palette, a separate buffer, so overlapping ranges are harmless (and it is a memmove regardless). ffmpeg and the original SMACKW32.DLL have no such check. Several of the videos that ship with the game (Rebel_cr, Omerta, Prague) use these overlapping copies, and showed washed-out colours with the previous frame's palette bleeding through. Drop the overlap clause, keep the real 256-entry bounds checks. Co-Authored-By: Claude Opus 4.8 --- ext/libsmacker/smacker.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ext/libsmacker/smacker.c b/ext/libsmacker/smacker.c index eef6e7b75..119f22503 100644 --- a/ext/libsmacker/smacker.c +++ b/ext/libsmacker/smacker.c @@ -1224,9 +1224,10 @@ static char smk_render_palette(struct smk_video_t * s, unsigned char * p, unsign p ++; size --; - /* overflow: see if we write/read beyond 256colors, or overwrite own palette */ - if (i + count > 256 || src + count > 256 || - (src < i && src + count > i)) { + /* overflow: see if we write/read beyond 256 colors. Overlap between + the src and dst ranges is fine: src reads from oldPalette, a + snapshot taken above, while we write into s->palette. */ + if (i + count > 256 || src + count > 256) { fprintf(stderr, "libsmacker::palette_render(s,p,size) - ERROR: overflow, 0x40 attempt to copy %d entries from %d to %d\n", count, src, i); goto error; }