Util: Cap internal buffer size when unzipping files (fixes #3404)

This commit is contained in:
Vicki Pfau 2025-02-26 23:44:49 -08:00
parent 5fd0ba0d67
commit 9923d1b3a1
2 changed files with 48 additions and 14 deletions

View File

@ -37,6 +37,7 @@ Other fixes:
- Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560) - Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560)
- Qt: Fix potential crash when configuring shortcuts - Qt: Fix potential crash when configuring shortcuts
- Qt: Fix regression where loading BIOS creates a save file (fixes mgba.io/i/3359) - Qt: Fix regression where loading BIOS creates a save file (fixes mgba.io/i/3359)
- Wii: Fix crash on loading large ZIP files (fixes mgba.io/i/3404)
Misc: Misc:
- Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826) - Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826)
- Core: Improve rumble emulation by averaging state over entire frame (fixes mgba.io/i/3232) - Core: Improve rumble emulation by averaging state over entire frame (fixes mgba.io/i/3232)

View File

@ -11,6 +11,12 @@
#ifdef USE_LIBZIP #ifdef USE_LIBZIP
#include <zip.h> #include <zip.h>
#ifndef FIXED_ROM_BUFFER
#define MAX_BUFFER_SIZE 0x80000000
#else
#define MAX_BUFFER_SIZE 0x00200000
#endif
struct VDirEntryZip { struct VDirEntryZip {
struct VDirEntry d; struct VDirEntry d;
struct zip* z; struct zip* z;
@ -36,6 +42,7 @@ struct VFileZip {
size_t fileSize; size_t fileSize;
char* name; char* name;
bool write; bool write;
size_t bufferStart;
}; };
enum { enum {
@ -250,8 +257,9 @@ bool _vfzClose(struct VFile* vf) {
zip_source_free(source); zip_source_free(source);
return false; return false;
} }
free(vfz->name);
} }
free(vfz->name);
vfz->name = NULL;
if (vfz->zf && zip_fclose(vfz->zf) < 0) { if (vfz->zf && zip_fclose(vfz->zf) < 0) {
return false; return false;
} }
@ -286,6 +294,17 @@ off_t _vfzSeek(struct VFile* vf, off_t offset, int whence) {
return -1; return -1;
} }
if (position < vfz->bufferStart) {
if (zip_fclose(vfz->zf) < 0) {
return -1;
}
vfz->zf = zip_fopen(vfz->z, vfz->name, 0);
vfz->bufferStart = 0;
vfz->offset = 0;
vfz->readSize = 0;
vfz->writeSize = 0;
}
if (position <= vfz->offset) { if (position <= vfz->offset) {
vfz->offset = position; vfz->offset = position;
return position; return position;
@ -315,7 +334,7 @@ ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size) {
while (bytesRead < size) { while (bytesRead < size) {
if (vfz->offset < vfz->readSize) { if (vfz->offset < vfz->readSize) {
size_t diff = vfz->readSize - vfz->offset; size_t diff = vfz->readSize - vfz->offset;
void* start = &((uint8_t*) vfz->buffer)[vfz->offset]; void* start = &((uint8_t*) vfz->buffer)[vfz->offset - vfz->bufferStart];
if (diff > size - bytesRead) { if (diff > size - bytesRead) {
diff = size - bytesRead; diff = size - bytesRead;
} }
@ -330,16 +349,25 @@ ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size) {
} }
} }
// offset == readSize // offset == readSize
if (vfz->readSize == vfz->bufferSize) { if (vfz->readSize == vfz->bufferSize + vfz->bufferStart) {
vfz->bufferSize *= 2; size_t bufferSize = vfz->bufferSize * 2;
if (vfz->bufferSize > vfz->fileSize) { void* newBuffer = NULL;
vfz->bufferSize = vfz->fileSize; if (bufferSize <= MAX_BUFFER_SIZE) {
if (bufferSize > vfz->fileSize) {
bufferSize = vfz->fileSize;
}
newBuffer = realloc(vfz->buffer, bufferSize);
}
if (newBuffer) {
vfz->bufferSize = bufferSize;
vfz->buffer = newBuffer;
} else {
vfz->bufferStart += vfz->bufferSize;
} }
vfz->buffer = realloc(vfz->buffer, vfz->bufferSize);
} }
if (vfz->readSize < vfz->bufferSize) { if (vfz->readSize < vfz->bufferSize + vfz->bufferStart) {
void* start = &((uint8_t*) vfz->buffer)[vfz->readSize]; void* start = &((uint8_t*) vfz->buffer)[vfz->readSize - vfz->bufferStart];
size_t toRead = vfz->bufferSize - vfz->readSize; size_t toRead = vfz->bufferSize - vfz->readSize - vfz->bufferStart;
if (toRead > BLOCK_SIZE) { if (toRead > BLOCK_SIZE) {
toRead = BLOCK_SIZE; toRead = BLOCK_SIZE;
} }
@ -391,9 +419,16 @@ void* _vfzMap(struct VFile* vf, size_t size, int flags) {
struct VFileZip* vfz = (struct VFileZip*) vf; struct VFileZip* vfz = (struct VFileZip*) vf;
UNUSED(flags); UNUSED(flags);
if (size > vfz->fileSize) {
return NULL;
}
size_t start = vfz->bufferStart;
if (size > vfz->readSize) { if (size > vfz->readSize) {
vf->read(vf, 0, size - vfz->readSize); vf->read(vf, 0, size - vfz->readSize);
} }
if (vfz->bufferStart != start) {
return NULL;
}
return vfz->buffer; return vfz->buffer;
} }
@ -470,10 +505,8 @@ struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) {
vfz->zf = zf; vfz->zf = zf;
vfz->z = vdz->z; vfz->z = vdz->z;
vfz->fileSize = s.size; vfz->fileSize = s.size;
if ((mode & O_ACCMODE) == O_WRONLY) { vfz->name = strdup(path);
vfz->name = strdup(path); vfz->write = (mode & O_ACCMODE) == O_WRONLY;
vfz->write = true;
}
vfz->d.close = _vfzClose; vfz->d.close = _vfzClose;
vfz->d.seek = _vfzSeek; vfz->d.seek = _vfzSeek;