From 92aa43fe913fd9f5255c0d872071075f70c54642 Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sun, 25 Aug 2019 15:09:28 +0100 Subject: [PATCH] cdvd: Fix end-of-disc issues (#3051) * cdvd: Fix off-by-one end of file checks * cdvd: Fix loading for games that attempt to read non-existent sectors Some games will hang when attempting to read non-existent sectors. Just do nothing when it occurs instead of erroring out. * cdvdgigaherz: Fix loading for games that attempt to read non-existent sectors Some games will hang when attempting to read non-existent sectors. Just do nothing when it occurs instead of erroring out. * cdvd: Don't write non-existent sectors to blockdump --- pcsx2/CDVD/CDVDaccess.cpp | 8 +++++- pcsx2/CDVD/CDVDisoReader.cpp | 3 +-- pcsx2/CDVD/InputIsoFile.cpp | 34 +++++++++++-------------- pcsx2/CDVD/IsoFileFormats.h | 2 +- pcsx2/PluginManager.cpp | 3 ++- plugins/cdvdGigaherz/src/CDVD.cpp | 13 ++++++++-- plugins/cdvdGigaherz/src/CDVD.h | 2 +- plugins/cdvdGigaherz/src/ReadThread.cpp | 8 +++--- 8 files changed, 41 insertions(+), 32 deletions(-) diff --git a/pcsx2/CDVD/CDVDaccess.cpp b/pcsx2/CDVD/CDVDaccess.cpp index ee76440a56..6b310608be 100644 --- a/pcsx2/CDVD/CDVDaccess.cpp +++ b/pcsx2/CDVD/CDVDaccess.cpp @@ -56,7 +56,7 @@ static int diskTypeCached = -1; // used to bridge the gap between the old getBuffer api and the new getBuffer2 api. int lastReadSize; -int lastLSN; // needed for block dumping +u32 lastLSN; // needed for block dumping // Records last read block length for block dumping //static int plsn = 0; @@ -490,6 +490,12 @@ s32 DoCDVDgetBuffer(u8* buffer) if (ret == 0 && blockDumpFile.IsOpened()) { + cdvdTD td; + CDVD->getTD(0, &td); + + if (lastLSN >= td.lsn) + return 0; + if (blockDumpFile.GetBlockSize() == CD_FRAMESIZE_RAW && lastReadSize != 2352) { u8 blockDumpBuffer[CD_FRAMESIZE_RAW]; diff --git a/pcsx2/CDVD/CDVDisoReader.cpp b/pcsx2/CDVD/CDVDisoReader.cpp index 104a89ddf1..59cbb1206a 100644 --- a/pcsx2/CDVD/CDVDisoReader.cpp +++ b/pcsx2/CDVD/CDVDisoReader.cpp @@ -315,7 +315,7 @@ s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode) int _lsn = lsn; if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn; - if (lsn > iso.GetBlockCount()) return -1; + if (lsn >= iso.GetBlockCount()) return -1; if(mode == CDVD_MODE_2352) { @@ -362,7 +362,6 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode) int _lsn = lsn; if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn; - if (lsn > iso.GetBlockCount()) return -1; iso.BeginRead2(lsn); diff --git a/pcsx2/CDVD/InputIsoFile.cpp b/pcsx2/CDVD/InputIsoFile.cpp index cef7d9333f..3089f6560f 100644 --- a/pcsx2/CDVD/InputIsoFile.cpp +++ b/pcsx2/CDVD/InputIsoFile.cpp @@ -35,10 +35,10 @@ static const char* nameFromType(int type) int InputIsoFile::ReadSync(u8* dst, uint lsn) { - if (lsn > m_blocks) + if (lsn >= m_blocks) { FastFormatUnicode msg; - msg.Write("isoFile error: Block index is past the end of file! (%u > %u).", lsn, m_blocks); + msg.Write("isoFile error: Block index is past the end of file! (%u >= %u).", lsn, m_blocks); pxAssertDev(false, msg); Console.Error(msg.c_str()); @@ -50,23 +50,15 @@ int InputIsoFile::ReadSync(u8* dst, uint lsn) void InputIsoFile::BeginRead2(uint lsn) { - if (lsn > m_blocks) + m_current_lsn = lsn; + + if (lsn >= m_blocks) { - FastFormatUnicode msg; - msg.Write("isoFile error: Block index is past the end of file! (%u > %u).", lsn, m_blocks); - - pxAssertDev(false, msg); - Console.Error(msg.c_str()); - - // [TODO] : Throw exception? - // Typically an error like this is bad; indicating an invalid dump or corrupted - // iso file. - - m_current_lsn = -1; + // While this usually indicates that the ISO is corrupted, some games do attempt + // to read past the end of the disc, so don't error here. + DevCon.Warning("isoFile error: Block index is past the end of file! (%u >= %u).", lsn, m_blocks); return; } - - m_current_lsn = lsn; if(lsn >= m_read_lsn && lsn < (m_read_lsn+m_read_count)) { @@ -90,13 +82,17 @@ void InputIsoFile::BeginRead2(uint lsn) int InputIsoFile::FinishRead3(u8* dst, uint mode) { + // Do nothing for out of bounds disc sector reads. It prevents some games + // from hanging (All-Star Baseball 2005, Hello Kitty: Roller Rescue, + // Hot Wheels: Beat That! (NTSC), Ratchet & Clank 3 (PAL), + // Test Drive: Eve of Destruction, etc.). + if (m_current_lsn >= m_blocks) + return 0; + int _offset = 0; int length = 0; int ret = 0; - if(m_current_lsn < 0) - return -1; - if(m_read_inprogress) { ret = m_reader->FinishRead(); diff --git a/pcsx2/CDVD/IsoFileFormats.h b/pcsx2/CDVD/IsoFileFormats.h index 55daaeadba..a4c1f36cbd 100644 --- a/pcsx2/CDVD/IsoFileFormats.h +++ b/pcsx2/CDVD/IsoFileFormats.h @@ -48,7 +48,7 @@ protected: wxString m_filename; AsyncFileReader* m_reader; - s32 m_current_lsn; + u32 m_current_lsn; isoType m_type; u32 m_flags; diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index ffbb21dafa..99764c02a7 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -452,7 +452,8 @@ static const LegacyApi_OptMethod s_MethMessOpt_PAD[] = // ---------------------------------------------------------------------------- void CALLBACK CDVD_newDiskCB(void (*callback)()) {} -extern int lastReadSize, lastLSN; +extern int lastReadSize; +extern u32 lastLSN; static s32 CALLBACK CDVD_getBuffer2(u8* buffer) { // TEMP: until I fix all the plugins to use this function style diff --git a/plugins/cdvdGigaherz/src/CDVD.cpp b/plugins/cdvdGigaherz/src/CDVD.cpp index f519b198d6..8707272017 100644 --- a/plugins/cdvdGigaherz/src/CDVD.cpp +++ b/plugins/cdvdGigaherz/src/CDVD.cpp @@ -40,7 +40,7 @@ track tracks[100]; int curDiskType; int curTrayStatus; -int csector; +static u32 csector; int cmode; /////////////////////////////////////////////////////////////////////////////// @@ -252,7 +252,9 @@ EXPORT s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) return ret; } - return lsn < src->GetSectorCount() ? cdvdRequestSector(lsn, mode) : -1; + cdvdRequestSector(lsn, mode); + + return 0; } // return can be NULL (for async modes) @@ -269,6 +271,13 @@ EXPORT u8 *CALLBACK CDVDgetBuffer() // return can be NULL (for async modes) EXPORT int CALLBACK CDVDgetBuffer2(u8 *dest) { + // Do nothing for out of bounds disc sector reads. It prevents some games + // from hanging (All-Star Baseball 2005, Hello Kitty: Roller Rescue, + // Hot Wheels: Beat That! (NTSC), Ratchet & Clank 3 (PAL), + // Test Drive: Eve of Destruction, etc.). + if (csector >= src->GetSectorCount()) + return 0; + int csize = 2352; switch (cmode) { case CDVD_MODE_2048: diff --git a/plugins/cdvdGigaherz/src/CDVD.h b/plugins/cdvdGigaherz/src/CDVD.h index 904e05bc9e..8f6c050d64 100644 --- a/plugins/cdvdGigaherz/src/CDVD.h +++ b/plugins/cdvdGigaherz/src/CDVD.h @@ -113,7 +113,7 @@ extern void (*newDiscCB)(); bool cdvdStartThread(); void cdvdStopThread(); -s32 cdvdRequestSector(u32 sector, s32 mode); +void cdvdRequestSector(u32 sector, s32 mode); u8 *cdvdGetSector(u32 sector, s32 mode); s32 cdvdDirectReadSector(u32 sector, s32 mode, u8 *buffer); s32 cdvdGetMediaType(); diff --git a/plugins/cdvdGigaherz/src/ReadThread.cpp b/plugins/cdvdGigaherz/src/ReadThread.cpp index 57b88e572a..979e97f394 100644 --- a/plugins/cdvdGigaherz/src/ReadThread.cpp +++ b/plugins/cdvdGigaherz/src/ReadThread.cpp @@ -257,16 +257,16 @@ void cdvdStopThread() s_thread.join(); } -s32 cdvdRequestSector(u32 sector, s32 mode) +void cdvdRequestSector(u32 sector, s32 mode) { if (sector >= src->GetSectorCount()) - return -1; + return; // Align to cache block sector &= ~(sectors_per_read - 1); if (cdvdCacheCheck(sector)) - return 0; + return; { std::lock_guard guard(s_request_lock); @@ -274,8 +274,6 @@ s32 cdvdRequestSector(u32 sector, s32 mode) } s_notify_cv.notify_one(); - - return 0; } u8 *cdvdGetSector(u32 sector, s32 mode)