Skip to content

Commit 23bf354

Browse files
committed
Fix XEX loader crash on a full-bank block
1 parent edf4a19 commit 23bf354

2 files changed

Lines changed: 27 additions & 26 deletions

File tree

ext/firmware

src/systems/x65.c

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ bool x65_quickload_xex(x65_t* sys, chips_range_t data) {
531531
return false;
532532
}
533533
const uint8_t* ptr = (uint8_t*)data.ptr;
534+
const uint8_t* const end = ptr + data.size;
534535

535536
bool reset_lo_loaded = false;
536537
bool reset_hi_loaded = false;
@@ -543,50 +544,50 @@ bool x65_quickload_xex(x65_t* sys, chips_range_t data) {
543544
return false;
544545
}
545546

546-
while (ptr < ((uint8_t*)data.ptr + data.size)) {
547-
size_t data_left = (uint8_t*)data.ptr + data.size - ptr;
548-
if (data_left < 4) {
547+
while (ptr < end) {
548+
if ((size_t)(end - ptr) >= 2 && ptr[0] == 0xff && ptr[1] == 0xff) {
549+
// optional block header marker
550+
ptr += 2;
551+
}
552+
if ((size_t)(end - ptr) < 4) {
549553
LOG_ERROR("File truncated");
550554
return false;
551555
}
552-
if (ptr[0] == 0xff && ptr[1] == 0xff) {
553-
// skip header
554-
ptr += 2;
555-
data_left -= 2;
556-
if (data_left < 4) {
557-
LOG_ERROR("File truncated");
558-
return false;
559-
}
560-
}
561556

562557
const uint16_t start_addr = ptr[1] << 8 | ptr[0];
563558
ptr += 2;
564559
const uint16_t end_addr = ptr[1] << 8 | ptr[0];
565560
ptr += 2;
566561

567-
const bool skip_chunk = start_addr == 0xFC00 && load_bank == 0x00;
568-
LOG_INFO("%s block: $%04X-$%04X", skip_chunk ? "Skipping" : "Loading", start_addr, end_addr);
569-
570-
data_left = (uint8_t*)data.ptr + data.size - ptr;
571-
if (data_left < (end_addr - start_addr + 1) || start_addr > end_addr) {
562+
if (start_addr > end_addr) {
563+
LOG_ERROR("Invalid block header: $%04X-$%04X", start_addr, end_addr);
564+
return false;
565+
}
566+
// compare against the delta, never the length: a $0000-$FFFF block is 0x10000 bytes long,
567+
// which does not fit a 16-bit count, but end_addr - start_addr always does
568+
if ((size_t)(end - ptr) <= (size_t)(end_addr - start_addr)) {
572569
LOG_ERROR("Block truncated");
573570
return false;
574571
}
572+
575573
if (start_addr == end_addr && start_addr == 0xFFFE) {
576574
load_bank = *ptr++;
577575
LOG_INFO("Loading to bank: $%02X", load_bank);
576+
continue;
578577
}
579-
else if (skip_chunk) {
580-
ptr += (end_addr - start_addr + 1);
581-
}
582-
else {
583-
uint16_t addr = start_addr;
584-
while (addr <= end_addr && addr >= start_addr) {
578+
579+
const bool skip_chunk = start_addr == 0xFC00 && load_bank == 0x00;
580+
LOG_INFO("%s block: $%04X-$%04X", skip_chunk ? "Skipping" : "Loading", start_addr, end_addr);
581+
582+
uint16_t addr = start_addr;
583+
do {
584+
const uint8_t value = *ptr++;
585+
if (!skip_chunk) {
585586
if (addr == 0xfffc) reset_lo_loaded = true;
586587
if (addr == 0xfffd) reset_hi_loaded = true;
587-
mem_wr(sys, load_bank, addr++, *ptr++);
588+
mem_wr(sys, load_bank, addr, value);
588589
}
589-
}
590+
} while (addr++ < end_addr);
590591
}
591592

592593
if (reset_lo_loaded && reset_hi_loaded) {

0 commit comments

Comments
 (0)