paavohtl Claude Opus 4.6 commited on
Commit
eb1677d
·
1 Parent(s): c60058c

fix: bounds-check palette cache instead of relying on overflow

Browse files

Skip the cache write when cache_count >= 256 rather than overflowing
into the dirty field. The dirty field is set to 1 immediately after,
so the overflow had no observable effect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

crates/openwa-core/src/render/palette.rs CHANGED
@@ -56,8 +56,10 @@ pub unsafe fn palette_map_color(ctx: *mut PaletteContext, rgb: u32) -> u32 {
56
 
57
  let cache_count = *(p.add(0x606) as *const i16);
58
 
59
- // Search cache for matching RGB (24-bit compare)
60
- for i in 0..cache_count as usize {
 
 
61
  let idx = *p.add(0x608 + i) as usize;
62
  if idx != 0 && (*(p.add(0x04 + idx * 4) as *const u32) ^ rgb) & 0xFF_FFFF == 0 {
63
  return idx as u32;
@@ -75,9 +77,12 @@ pub unsafe fn palette_map_color(ctx: *mut PaletteContext, rgb: u32) -> u32 {
75
  let slot = *p.add(0x506 + new_free_count as usize);
76
  let slot_idx = slot as usize;
77
 
78
- // Add to cache (may overflow into dirty field at +0x708 when cache is full —
79
- // matches WA behavior, and dirty is set to 1 immediately after anyway)
80
- *p.add(0x608 + cache_count as usize) = slot;
 
 
 
81
  *(p.add(0x606) as *mut i16) = cache_count + 1;
82
 
83
  // Store RGB and mark in-use
 
56
 
57
  let cache_count = *(p.add(0x606) as *const i16);
58
 
59
+ // Search cache for matching RGB (24-bit compare).
60
+ // Clamp to 256 — WA doesn't bounds-check cache_count.
61
+ let search_len = (cache_count as usize).min(256);
62
+ for i in 0..search_len {
63
  let idx = *p.add(0x608 + i) as usize;
64
  if idx != 0 && (*(p.add(0x04 + idx * 4) as *const u32) ^ rgb) & 0xFF_FFFF == 0 {
65
  return idx as u32;
 
77
  let slot = *p.add(0x506 + new_free_count as usize);
78
  let slot_idx = slot as usize;
79
 
80
+ // Add to cache. WA doesn't bounds-check: when cache_count == 256 it writes
81
+ // past cache[] into the dirty field, which is set to 1 immediately after.
82
+ // We just skip the write instead.
83
+ if (cache_count as usize) < 256 {
84
+ *p.add(0x608 + cache_count as usize) = slot;
85
+ }
86
  *(p.add(0x606) as *mut i16) = cache_count + 1;
87
 
88
  // Store RGB and mark in-use