From 742b0edaa83156e3715bb8b711249cbe9c552310 Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sat, 27 May 2017 12:21:09 +0100 Subject: [PATCH] gsdx: Fix GS dump readback EOF handling An EOF only occurs after attempting to read past the end of the file. Account for this correctly, which fixes a potential infinite loop when reading back an xz compressed GS dump. --- plugins/GSdx/GS.cpp | 6 ++---- plugins/GSdx/GSLzma.cpp | 38 ++++++++++++++++++++++---------------- plugins/GSdx/GSLzma.h | 12 +++++------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 68b68fad7a..689b111cb3 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -1603,11 +1603,9 @@ EXPORT_C GSReplay(char* lpszCmdLine, int renderer) file->Read(regs, 0x2000); - while(!file->IsEof()) + uint8 type; + while(file->Read(&type, 1)) { - uint8 type; - file->Read(&type, 1); - Packet* p = new Packet(); p->type = type; diff --git a/plugins/GSdx/GSLzma.cpp b/plugins/GSdx/GSLzma.cpp index 8c897ebc6b..49ec535e2a 100644 --- a/plugins/GSdx/GSLzma.cpp +++ b/plugins/GSdx/GSLzma.cpp @@ -111,14 +111,14 @@ void GSDumpLzma::Decompress() { } bool GSDumpLzma::IsEof() { - return feof(m_fp) && (m_avail == 0); + return feof(m_fp) && m_avail == 0 && m_strm.avail_in == 0; } -void GSDumpLzma::Read(void* ptr, size_t size) { +bool GSDumpLzma::Read(void* ptr, size_t size) { size_t off = 0; uint8_t* dst = (uint8_t*)ptr; size_t full_size = size; - while (size) { + while (size && !IsEof()) { if (m_avail == 0) { Decompress(); } @@ -130,7 +130,13 @@ void GSDumpLzma::Read(void* ptr, size_t size) { m_start += l; off += l; } - Repack(ptr, full_size); + + if (size == 0) { + Repack(ptr, full_size); + return true; + } + + return false; } GSDumpLzma::~GSDumpLzma() { @@ -156,17 +162,17 @@ bool GSDumpRaw::IsEof() { return feof(m_fp); } -void GSDumpRaw::Read(void* ptr, size_t size) { - if (size == 1) { - // I don't know why but read of size 1 is not happy - int v = fgetc(m_fp); - memcpy(ptr, &v, 1); - } else { - size_t ret = fread(ptr, 1, size, m_fp); - if (ret != size) { - fprintf(stderr, "GSDumpRaw:: Read error (%zu/%zu)\n", ret, size); - throw "BAD"; // Just exit the program - } +bool GSDumpRaw::Read(void* ptr, size_t size) { + size_t ret = fread(ptr, 1, size, m_fp); + if (ret != size && ferror(m_fp)) { + fprintf(stderr, "GSDumpRaw:: Read error (%zu/%zu)\n", ret, size); + throw "BAD"; // Just exit the program } - Repack(ptr, size); + + if (ret == size) { + Repack(ptr, size); + return true; + } + + return false; } diff --git a/plugins/GSdx/GSLzma.h b/plugins/GSdx/GSLzma.h index 2e565f57e2..7b48575322 100644 --- a/plugins/GSdx/GSLzma.h +++ b/plugins/GSdx/GSLzma.h @@ -30,7 +30,7 @@ class GSDumpFile { public: virtual bool IsEof() = 0; - virtual void Read(void* ptr, size_t size) = 0; + virtual bool Read(void* ptr, size_t size) = 0; GSDumpFile(char* filename, const char* repack_filename); virtual ~GSDumpFile(); @@ -54,8 +54,8 @@ class GSDumpLzma : public GSDumpFile { GSDumpLzma(char* filename, const char* repack_filename); virtual ~GSDumpLzma(); - bool IsEof(); - void Read(void* ptr, size_t size); + bool IsEof() final; + bool Read(void* ptr, size_t size) final; }; class GSDumpRaw : public GSDumpFile { @@ -67,13 +67,11 @@ class GSDumpRaw : public GSDumpFile { size_t m_avail; size_t m_start; - void Decompress(); - public: GSDumpRaw(char* filename, const char* repack_filename); virtual ~GSDumpRaw() = default; - bool IsEof(); - void Read(void* ptr, size_t size); + bool IsEof() final; + bool Read(void* ptr, size_t size) final; };