From 7005b9284066f810d00932dfd6da7ae0eb9b4252 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Mon, 3 Apr 2023 12:47:55 -0700 Subject: [PATCH] Sanitize allocations in the Game Boy emulator (#1105) This adds checks for every allocation failure in the core Game Boy emulator. In addition, this replaces some magic values defined constant expressions and removes an unused function. This also removes asserts for failed allocations in GB.cpp, they now report a failure to the caller. --- src/common/sizes.h | 29 ++++ src/gb/GB.cpp | 304 +++++++++++++++++++++++------------------- src/gb/gbCartData.cpp | 4 + src/gb/gbGlobals.cpp | 14 +- 4 files changed, 205 insertions(+), 146 deletions(-) diff --git a/src/common/sizes.h b/src/common/sizes.h index 1f7f3815..56068332 100644 --- a/src/common/sizes.h +++ b/src/common/sizes.h @@ -21,4 +21,33 @@ constexpr size_t k2MiB = 2 * k1MiB; constexpr size_t k4MiB = 2 * k2MiB; constexpr size_t k8MiB = 2 * k4MiB; +// Game Boy BIOS Sizes. +constexpr size_t kGBBiosSize = k256B; +constexpr size_t kCGBBiosSize = k2KiB + k256B; + +// Size of the buffer containing the BIOS, we alawys use the larger size. +constexpr size_t kGBBiosBufferSize = kCGBBiosSize; + +// Game Boy-related screen sizes. +constexpr size_t kGBWidth = 160; +constexpr size_t kGBHeight = 144; +constexpr size_t kSGBWidth = 256; +constexpr size_t kSGBHeight = 224; +#ifdef __LIBRETRO__ +constexpr size_t kGBPixSize = 4 * kSGBWidth * kSGBHeight; +#else +// Some of the filters and interframe blenders write beyond the end of the line +// or the screen, so we allocate extra space here. +constexpr size_t kGBPixSize = 4 * (kSGBWidth + 1) * (kSGBHeight + 2); +#endif + +// Game Boy VRAM is 16 KiB. +constexpr size_t kGBVRamSize = k16KiB; + +// Game Boy WRAM is 32 KiB. +constexpr size_t kGBWRamSize = k32KiB; + +// A Game Boy line buffer size is the width of the screen at 2 bytes per pizel. +constexpr size_t kGBLineBufferSize = kGBWidth * 2; + #endif // VBAM_COMMON_SIZES_H_ diff --git a/src/gb/GB.cpp b/src/gb/GB.cpp index e7dd3461..1972b4b6 100644 --- a/src/gb/GB.cpp +++ b/src/gb/GB.cpp @@ -114,6 +114,7 @@ bool gbInitializeRom(size_t romSize) { switch (g_gbCartData.validity()) { case gbCartData::Validity::kValid: case gbCartData::Validity::kUninitialized: + // Unreachable. assert(false); break; case gbCartData::Validity::kSizeTooSmall: @@ -157,7 +158,6 @@ bool gbInitializeRom(size_t romSize) { if (romSize < romHeaderSize) { uint8_t* gbRomNew = (uint8_t*)realloc(gbRom, romHeaderSize); if (!gbRomNew) { - assert(false); return false; }; gbRom = gbRomNew; @@ -227,9 +227,12 @@ bool gbInitializeRom(size_t romSize) { } gbRamFill = 0x00; - if (gbTAMA5ram == nullptr) - gbTAMA5ram = (uint8_t*)malloc(kTama5RamSize); - memset(gbTAMA5ram, 0x0, kTama5RamSize); + if (gbTAMA5ram == nullptr) { + gbTAMA5ram = (uint8_t*)calloc(1, kTama5RamSize); + if (gbTAMA5ram == nullptr) { + return false; + } + } g_mapperRAM = mapperTAMA5RAM; g_mapperReadRAM = mapperTAMA5ReadRAM; @@ -253,6 +256,9 @@ bool gbInitializeRom(size_t romSize) { const size_t ramSize = g_gbCartData.ram_size(); if (ramSize > 0) { gbRam = (uint8_t*)malloc(ramSize); + if (gbRam == nullptr) { + return false; + } memset(gbRam, gbRamFill, ramSize); } @@ -261,14 +267,19 @@ bool gbInitializeRom(size_t romSize) { setColorizerHack(false); gbMemory = (uint8_t*)malloc(65536); + if (gbMemory == nullptr) { + return false; + } -#ifdef __LIBRETRO__ - pix = (uint8_t*)calloc(1, 4 * 256 * 224); -#else - pix = (uint8_t*)calloc(1, 4 * 257 * 226); -#endif + pix = (uint8_t*)calloc(1, kGBPixSize); + if (pix == nullptr) { + return false; + } - gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t)); + gbLineBuffer = (uint16_t*)malloc(kGBLineBufferSize); + if (gbLineBuffer == nullptr) { + return false; + } return true; } @@ -281,7 +292,7 @@ bool inBios = false; bool memorydebug = false; char gbBuffer[2048]; -extern uint16_t gbLineMix[160]; +extern uint16_t gbLineMix[kGBWidth]; // registers gbRegister PC; @@ -1436,7 +1447,7 @@ void gbWriteMemory(uint16_t address, uint8_t value) // systemDrawScreen(); - gbRegisterLYLCDCOffOn = (register_LY + 144) % 154; + gbRegisterLYLCDCOffOn = (register_LY + kGBHeight) % 154; gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1); gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0); @@ -1683,7 +1694,7 @@ void gbWriteMemory(uint16_t address, uint8_t value) // WY case 0x4a: gbMemory[0xff4a] = register_WY = value; - if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine >= 144))) { + if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine >= (int)kGBHeight))) { gbWindowLine = -1; oldRegister_WY = register_WY; } @@ -2356,7 +2367,7 @@ void gbCPUInit(const char* biosFileName, bool useBiosFile) coreOptions.useBios = false; if (useBiosFile) { - int expectedSize = (gbHardware & 2) ? 0x900 : 0x100; + int expectedSize = (gbHardware & 2) ? kCGBBiosSize : kGBBiosSize; int size = expectedSize; if (utilLoad(biosFileName, CPUIsGBBios, @@ -2494,21 +2505,28 @@ void gbReset() oldRegister_WY = 146; gbInterruptLaunched = 0; - if (gbCgbMode == 1) { - if (gbVram == NULL) - gbVram = (uint8_t*)malloc(0x4000); - if (gbWram == NULL) - gbWram = (uint8_t*)malloc(0x8000); - memset(gbVram, 0, 0x4000); - memset(gbPalette, 0, 2 * 128); - } else { - if (gbVram != NULL) { - free(gbVram); - gbVram = NULL; + if (gbCgbMode) { + if (gbVram == nullptr) { + gbVram = (uint8_t*)calloc(1, kGBVRamSize); + if (gbVram == nullptr) { + return; + } } - if (gbWram != NULL) { + if (gbWram == nullptr) { + gbWram = (uint8_t*)malloc(kGBWRamSize); + if (gbWram == nullptr) { + return; + } + } + memset(gbPalette, 0, sizeof(gbPalette)); + } else { + if (gbVram != nullptr) { + free(gbVram); + gbVram = nullptr; + } + if (gbWram != nullptr) { free(gbWram); - gbWram = NULL; + gbWram = nullptr; } } @@ -2526,7 +2544,7 @@ void gbReset() // In all cases, most of the 2nd bank is filled with 00s. // The starting data are important for some 'buggy' games, like Buster Brothers or // Karamuchou ha Oosawagi!. - if (gbMemory != NULL) { + if (gbMemory != nullptr) { memset(gbMemory, 0xff, 65536); for (int temp = 0xC000; temp < 0xE000; temp++) if ((temp & 0x8) ^ ((temp & 0x800) >> 8)) { @@ -2552,14 +2570,17 @@ void gbReset() } // clean LineBuffer - if (gbLineBuffer != NULL) - memset(gbLineBuffer, 0, sizeof(*gbLineBuffer)); + if (gbLineBuffer != nullptr) { + memset(gbLineBuffer, 0, kGBLineBufferSize); + } // clean Pix - if (pix != NULL) - memset(pix, 0, sizeof(*pix)); + if (pix != nullptr) { + memset(pix, 0, kGBPixSize); + } // clean Vram - if (gbVram != NULL) - memset(gbVram, 0, 0x4000); + if (gbVram != nullptr) { + memset(gbVram, 0, kGBVRamSize); + } // clean Wram 2 // This kinda emulates the startup state of Wram on GBC (not very accurate, // but way closer to the reality than filling it with 00es or FFes). @@ -2567,7 +2588,7 @@ void gbReset() // In all cases, most of the 2nd bank is filled with 00s. // The starting data are important for some 'buggy' games, like Buster Brothers or // Karamuchou ha Oosawagi! - if (gbWram != NULL) { + if (gbWram != nullptr) { for (int i = 0; i < 8; i++) if (i != 2) memcpy((uint16_t*)(gbWram + i * 0x1000), (uint16_t*)(gbMemory + 0xC000), 0x1000); @@ -2732,9 +2753,9 @@ void gbReset() if ((gbHardware & 7) && (bios != NULL) && coreOptions.useBios && !coreOptions.skipBios) { if (gbHardware & 5) { memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000); - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize); } else { - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize); memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100); } gbWhiteScreen = 0; @@ -3541,26 +3562,7 @@ bool gbReadSaveMMM01(const char* name) } else return false; } -#endif // !__LIBRETRO__ -void gbInit() -{ - gbGenFilter(); - gbSgbInit(); - setColorizerHack(false); - - gbMemory = (uint8_t*)malloc(65536); - -#ifdef __LIBRETRO__ - pix = (uint8_t*)calloc(1, 4 * 256 * 224); -#else - pix = (uint8_t*)calloc(1, 4 * 257 * 226); -#endif - - gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t)); -} - -#ifndef __LIBRETRO__ bool gbWriteBatteryFile(const char* file, bool extendedSave) { if (gbBattery) { @@ -3870,7 +3872,7 @@ static bool gbWriteSaveState(gzFile gzFile) utilGzWrite(gzFile, gbTAMA5ram, kTama5RamSize); utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); - utilGzWrite(gzFile, gbPalette, 128 * sizeof(uint16_t)); + utilGzWrite(gzFile, gbPalette, sizeof(gbPalette)); utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); @@ -3880,8 +3882,8 @@ static bool gbWriteSaveState(gzFile gzFile) } if (gbCgbMode) { - utilGzWrite(gzFile, gbVram, 0x4000); - utilGzWrite(gzFile, gbWram, 0x8000); + utilGzWrite(gzFile, gbVram, kGBVRamSize); + utilGzWrite(gzFile, gbWram, kGBWRamSize); } gbSoundSaveGame(gzFile); @@ -3983,22 +3985,29 @@ static bool gbReadSaveState(gzFile gzFile) utilReadData(gzFile, gbSaveGameStruct); // Correct crash when loading color gameboy save in regular gameboy type. - if (!gbCgbMode) { - if (gbVram != NULL) { - free(gbVram); - gbVram = NULL; + if (gbCgbMode) { + if (gbVram == nullptr) { + gbVram = (uint8_t*)calloc(1, kGBVRamSize); + if (gbVram == nullptr) { + return false; + } } - if (gbWram != NULL) { - free(gbWram); - gbWram = NULL; + if (gbWram == nullptr) { + gbWram = (uint8_t*)malloc(kGBWRamSize); + if (gbWram == nullptr) { + return false; + } } + memset(gbPalette, 0, sizeof(gbPalette)); } else { - if (gbVram == NULL) - gbVram = (uint8_t*)malloc(0x4000); - if (gbWram == NULL) - gbWram = (uint8_t*)malloc(0x8000); - memset(gbVram, 0, 0x4000); - memset(gbPalette, 0, 2 * 128); + if (gbVram != nullptr) { + free(gbVram); + gbVram = nullptr; + } + if (gbWram != nullptr) { + free(gbWram); + gbWram = nullptr; + } } if (version >= GBSAVE_GAME_VERSION_7) { @@ -4034,7 +4043,7 @@ static bool gbReadSaveState(gzFile gzFile) if (version < GBSAVE_GAME_VERSION_5) { utilGzRead(gzFile, pix, 256 * 224 * sizeof(uint16_t)); } - memset(pix, 0, 257 * 226 * sizeof(uint32_t)); + memset(pix, 0, kGBPixSize); if (version < GBSAVE_GAME_VERSION_6) { utilGzRead(gzFile, gbPalette, 64 * sizeof(uint16_t)); @@ -4080,9 +4089,9 @@ static bool gbReadSaveState(gzFile gzFile) gbMemoryMap[0x00] = &gbMemory[0x0000]; if (gbHardware & 5) { memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000); - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize); } else if (gbHardware & 2) { - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize); memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100); } @@ -4166,8 +4175,8 @@ static bool gbReadSaveState(gzFile gzFile) } if (gbCgbMode) { - utilGzRead(gzFile, gbVram, 0x4000); - utilGzRead(gzFile, gbWram, 0x8000); + utilGzRead(gzFile, gbVram, kGBVRamSize); + utilGzRead(gzFile, gbWram, kGBWRamSize); int value = register_SVBK; if (value == 0) @@ -4275,8 +4284,10 @@ static bool gbReadSaveState(gzFile gzFile) systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - if (version >= 12 && utilReadInt(gzFile) != 0x12345678) - assert(false); // fails if something read too much/little from file + if (version >= 12 && utilReadInt(gzFile) != 0x12345678) { + // fails if something read too much/little from file + return false; + } return true; } @@ -4310,65 +4321,65 @@ bool gbReadSaveState(const char* name) bool gbWritePNGFile(const char* fileName) { if (gbBorderOn) - return utilWritePNGFile(fileName, 256, 224, pix); - return utilWritePNGFile(fileName, 160, 144, pix); + return utilWritePNGFile(fileName, kSGBWidth, kSGBHeight, pix); + return utilWritePNGFile(fileName, kGBWidth, kGBHeight, pix); } bool gbWriteBMPFile(const char* fileName) { if (gbBorderOn) - return utilWriteBMPFile(fileName, 256, 224, pix); - return utilWriteBMPFile(fileName, 160, 144, pix); + return utilWriteBMPFile(fileName, kSGBWidth, kSGBHeight, pix); + return utilWriteBMPFile(fileName, kGBWidth, kGBHeight, pix); } #endif // !__LIBRETRO__ void gbCleanUp() { - if (gbRam != NULL) { + if (gbRam != nullptr) { free(gbRam); - gbRam = NULL; + gbRam = nullptr; } - if (gbRom != NULL) { + if (gbRom != nullptr) { free(gbRom); - gbRom = NULL; + gbRom = nullptr; } - if (bios != NULL) { + if (bios != nullptr) { free(bios); - bios = NULL; + bios = nullptr; } - if (gbMemory != NULL) { + if (gbMemory != nullptr) { free(gbMemory); - gbMemory = NULL; + gbMemory = nullptr; } - if (gbLineBuffer != NULL) { + if (gbLineBuffer != nullptr) { free(gbLineBuffer); - gbLineBuffer = NULL; + gbLineBuffer = nullptr; } - if (pix != NULL) { + if (pix != nullptr) { free(pix); - pix = NULL; + pix = nullptr; } gbSgbShutdown(); - if (gbVram != NULL) { + if (gbVram != nullptr) { free(gbVram); - gbVram = NULL; + gbVram = nullptr; } - if (gbWram != NULL) { + if (gbWram != nullptr) { free(gbWram); - gbWram = NULL; + gbWram = nullptr; } - if (gbTAMA5ram != NULL) { + if (gbTAMA5ram != nullptr) { free(gbTAMA5ram); - gbTAMA5ram = NULL; + gbTAMA5ram = nullptr; } g_gbCartData = gbCartData(); @@ -4398,7 +4409,10 @@ bool gbLoadRom(const char* filename) { free(bios); bios = nullptr; } - bios = (uint8_t*)calloc(1, 0x900); + bios = (uint8_t*)calloc(1, kGBBiosBufferSize); + if (bios == nullptr) { + return false; + } return gbInitializeRom(romSize); } @@ -4445,7 +4459,7 @@ void gbDrawLine() uint16_t* dest = (uint16_t*)pix + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) + gbBorderColumnSkip; #endif - for (int x = 0; x < 160;) { + for (size_t x = 0; x < kGBWidth;) { *dest++ = systemColorMap16[gbLineMix[x++]]; *dest++ = systemColorMap16[gbLineMix[x++]]; *dest++ = systemColorMap16[gbLineMix[x++]]; @@ -4475,7 +4489,7 @@ void gbDrawLine() case 24: { uint8_t* dest = (uint8_t*)pix + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + gbBorderColumnSkip); - for (int x = 0; x < 160;) { + for (size_t x = 0; x < kGBWidth;) { *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; dest += 3; *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; @@ -4522,7 +4536,7 @@ void gbDrawLine() uint32_t* dest = (uint32_t*)pix + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) + gbBorderColumnSkip; #endif - for (int x = 0; x < 160;) { + for (size_t x = 0; x < kGBWidth;) { *dest++ = systemColorMap32[gbLineMix[x++]]; *dest++ = systemColorMap32[gbLineMix[x++]]; *dest++ = systemColorMap32[gbLineMix[x++]]; @@ -4770,7 +4784,7 @@ void gbEmulate(int ticksToStop) case 0: { // H-Blank // check if we reached the V-Blank period - if (register_LY == 144) { + if (register_LY == kGBHeight) { // Yes, V-Blank // set the LY increment counter if (gbHardware & 0x5) { @@ -4845,7 +4859,7 @@ void gbEmulate(int ticksToStop) int tempinUseRegister_WY = inUseRegister_WY; int tempgbWindowLine = gbWindowLine; - if ((tempgbWindowLine == -1) || (tempgbWindowLine > 144)) { + if ((tempgbWindowLine == -1) || (tempgbWindowLine > (int)kGBHeight)) { tempinUseRegister_WY = oldRegister_WY; if (register_LY > oldRegister_WY) tempgbWindowLine = 146; @@ -4952,7 +4966,7 @@ void gbEmulate(int ticksToStop) if (gbWindowLine < 0) oldRegister_WY = register_WY; // check if we reached the V-Blank period - if (register_LY == 144) { + if (register_LY == kGBHeight) { // Yes, V-Blank // set the LY increment counter @@ -5054,7 +5068,7 @@ void gbEmulate(int ticksToStop) // OAM and VRAM in use // next mode is H-Blank - if ((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) { + if ((register_LY < kGBHeight) && (register_LCDC & 0x80) && gbScreenOn) { if (!gbSgbMask) { if (gbFrameSkipCount >= framesToSkip) { if (!gbBlackScreen) { @@ -5064,7 +5078,7 @@ void gbEmulate(int ticksToStop) uint16_t color = gbColorOption ? gbColorFilter[0] : 0; if (!gbCgbMode) color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : gbPalette[3] & 0x7FFF; - for (int i = 0; i < 160; i++) { + for (size_t i = 0; i < kGBWidth; i++) { gbLineMix[i] = color; gbLineBuffer[i] = 0; } @@ -5129,7 +5143,7 @@ void gbEmulate(int ticksToStop) uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; if (!gbCgbMode) color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; - for (int i = 0; i < 160; i++) { + for (size_t i = 0; i < kGBWidth; i++) { gbLineMix[i] = color; gbLineBuffer[i] = 0; } @@ -5145,17 +5159,17 @@ void gbEmulate(int ticksToStop) while (gbLcdLYIncrementTicks <= 0) { register_LY = ((register_LY + 1) % 154); gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - if (register_LY < 144) { + if (register_LY < kGBHeight) { uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; if (!gbCgbMode) color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; - for (int i = 0; i < 160; i++) { + for (size_t i = 0; i < kGBWidth; i++) { gbLineMix[i] = color; gbLineBuffer[i] = 0; } gbDrawLine(); - } else if ((register_LY == 144) && (!systemFrameSkip)) { + } else if ((register_LY == kGBHeight) && (!systemFrameSkip)) { int framesToSkip = systemFrameSkip; //if (coreOptions.speedup) // framesToSkip = 9; // try 6 FPS during speedup @@ -5457,7 +5471,7 @@ bool gbLoadRomData(const char* data, size_t size) { gbRom = (uint8_t*)calloc(1, size); if (gbRom == nullptr) { - return 0; + return false; } memcpy(gbRom, data, size); @@ -5469,7 +5483,10 @@ bool gbLoadRomData(const char* data, size_t size) { bios = nullptr; } - bios = (uint8_t*)calloc(1, 0x900); + bios = (uint8_t*)calloc(1, kGBBiosBufferSize); + if (bios == nullptr) { + return false; + } return gbInitializeRom(size); } @@ -5524,7 +5541,7 @@ unsigned int gbWriteSaveState(uint8_t* data) utilWriteMem(data, gbTAMA5ram, kTama5RamSize); utilWriteMem(data, &gbDataMMM01, sizeof(gbDataMMM01)); - utilWriteMem(data, gbPalette, 128 * sizeof(uint16_t)); + utilWriteMem(data, gbPalette, sizeof(gbPalette)); utilWriteMem(data, &gbMemory[0x8000], 0x8000); @@ -5534,8 +5551,8 @@ unsigned int gbWriteSaveState(uint8_t* data) } if (gbCgbMode) { - utilWriteMem(data, gbVram, 0x4000); - utilWriteMem(data, gbWram, 0x8000); + utilWriteMem(data, gbVram, kGBVRamSize); + utilWriteMem(data, gbWram, kGBWRamSize); } gbSoundSaveGame(data); @@ -5604,22 +5621,29 @@ bool gbReadSaveState(const uint8_t* data) utilReadDataMem(data, gbSaveGameStruct); // Correct crash when loading color gameboy save in regular gameboy type. - if (!gbCgbMode) { - if (gbVram != NULL) { - free(gbVram); - gbVram = NULL; + if (gbCgbMode) { + if (gbVram == nullptr) { + gbVram = (uint8_t*)calloc(1, kGBVRamSize); + if (gbVram == nullptr) { + return false; + } } - if (gbWram != NULL) { - free(gbWram); - gbWram = NULL; + if (gbWram == nullptr) { + gbWram = (uint8_t*)malloc(kGBWRamSize); + if (gbWram == nullptr) { + return false; + } } + memset(gbPalette, 0, sizeof(gbPalette)); } else { - if (gbVram == NULL) - gbVram = (uint8_t*)malloc(0x4000); - if (gbWram == NULL) - gbWram = (uint8_t*)malloc(0x8000); - memset(gbVram, 0, 0x4000); - memset(gbPalette, 0, 2 * 128); + if (gbVram != nullptr) { + free(gbVram); + gbVram = nullptr; + } + if (gbWram != nullptr) { + free(gbWram); + gbWram = nullptr; + } } utilReadMem(&IFF, data, 2); @@ -5644,7 +5668,7 @@ bool gbReadSaveState(const uint8_t* data) } utilReadMem(&gbDataMMM01, data, sizeof(gbDataMMM01)); - utilReadMem(gbPalette, data, 128 * sizeof(uint16_t)); + utilReadMem(gbPalette, data, sizeof(gbPalette)); utilReadMem(&gbMemory[0x8000], data, 0x8000); @@ -5666,9 +5690,9 @@ bool gbReadSaveState(const uint8_t* data) gbMemoryMap[0x00] = &gbMemory[0x0000]; if (gbHardware & 5) { memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000); - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize); } else if (gbHardware & 2) { - memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize); memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100); } @@ -5754,8 +5778,8 @@ bool gbReadSaveState(const uint8_t* data) } if (gbCgbMode) { - utilReadMem(gbVram, data, 0x4000); - utilReadMem(gbWram, data, 0x8000); + utilReadMem(gbVram, data, kGBVRamSize); + utilReadMem(gbWram, data, kGBWRamSize); int value = register_SVBK; if (value == 0) @@ -5795,8 +5819,10 @@ bool gbReadSaveState(const uint8_t* data) systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - if (version >= 12 && utilReadIntMem(data) != 0x12345678) - assert(false); // fails if something read too much/little from file + if (version >= 12 && utilReadIntMem(data) != 0x12345678) { + // fails if something read too much/little from file + return false; + } return true; } diff --git a/src/gb/gbCartData.cpp b/src/gb/gbCartData.cpp index 9abb511d..3704c502 100644 --- a/src/gb/gbCartData.cpp +++ b/src/gb/gbCartData.cpp @@ -391,6 +391,10 @@ gbCartData::gbCartData(const uint8_t* romData, size_t romDataSize) { ram_size_ = k128KiB; break; case 0x05: + // Technically, this refers to a 1 Mbit (128 KiB) RAM chip, but + // this is only used in Pocket Monsters Crystal JP, which has a + // mapper chip referred as "MBC30". This mapper can only address + // half of the RAM chip. So, we set the size to 64 KiB. ram_size_ = k64KiB; break; default: diff --git a/src/gb/gbGlobals.cpp b/src/gb/gbGlobals.cpp index 42d5edfc..2564ba71 100644 --- a/src/gb/gbGlobals.cpp +++ b/src/gb/gbGlobals.cpp @@ -8,13 +8,13 @@ int gbRomSize = 0; int gbRamSizeMask = 0; int gbRamSize = 0; -uint8_t* gbMemory = NULL; -uint8_t* gbVram = NULL; -uint8_t* gbRom = NULL; -uint8_t* gbRam = NULL; -uint8_t* gbWram = NULL; -uint16_t* gbLineBuffer = NULL; -uint8_t* gbTAMA5ram = NULL; +uint8_t* gbMemory = nullptr; +uint8_t* gbVram = nullptr; +uint8_t* gbRom = nullptr; +uint8_t* gbRam = nullptr; +uint8_t* gbWram = nullptr; +uint16_t* gbLineBuffer = nullptr; +uint8_t* gbTAMA5ram = nullptr; uint16_t gbPalette[128]; uint8_t gbBgp[4] = { 0, 1, 2, 3 };