VFS: Fix handle leak when double-mapping (fixes #1659)

This commit is contained in:
Vicki Pfau 2020-02-05 04:15:43 +00:00
parent 6b12eddfba
commit baeb353694
2 changed files with 39 additions and 6 deletions

View File

@ -31,6 +31,7 @@ Other fixes:
- Qt: Fix window title not updating after shutting down game - Qt: Fix window title not updating after shutting down game
- Qt: Fix GIF view not allowing manual filename entry - Qt: Fix GIF view not allowing manual filename entry
- Util: Fix crash reading invalid ELFs - Util: Fix crash reading invalid ELFs
- VFS: Fix handle leak when double-mapping (fixes mgba.io/i/1659)
Misc: Misc:
- FFmpeg: Add more presets - FFmpeg: Add more presets
- Qt: Renderer can be changed while a game is running - Qt: Renderer can be changed while a game is running

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau /* Copyright (c) 2013-2020 Jeffrey Pfau
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -14,11 +14,23 @@
#include <windows.h> #include <windows.h>
#endif #endif
#include <mgba-util/vector.h>
#ifdef _WIN32
struct HandleMappingTuple {
HANDLE handle;
void* mapping;
};
DECLARE_VECTOR(HandleMappingList, struct HandleMappingTuple);
DEFINE_VECTOR(HandleMappingList, struct HandleMappingTuple);
#endif
struct VFileFD { struct VFileFD {
struct VFile d; struct VFile d;
int fd; int fd;
#ifdef _WIN32 #ifdef _WIN32
HANDLE hMap; struct HandleMappingList handles;
#endif #endif
}; };
@ -74,12 +86,23 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.truncate = _vfdTruncate; vfd->d.truncate = _vfdTruncate;
vfd->d.size = _vfdSize; vfd->d.size = _vfdSize;
vfd->d.sync = _vfdSync; vfd->d.sync = _vfdSync;
#ifdef _WIN32
HandleMappingListInit(&vfd->handles, 4);
#endif
return &vfd->d; return &vfd->d;
} }
bool _vfdClose(struct VFile* vf) { bool _vfdClose(struct VFile* vf) {
struct VFileFD* vfd = (struct VFileFD*) vf; struct VFileFD* vfd = (struct VFileFD*) vf;
#ifdef _WIN32
size_t i;
for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
UnmapViewOfFile(HandleMappingListGetPointer(&vfd->handles, i)->mapping);
CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
}
HandleMappingListDeinit(&vfd->handles);
#endif
if (close(vfd->fd) < 0) { if (close(vfd->fd) < 0) {
return false; return false;
} }
@ -134,16 +157,25 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
if (size > fileSize) { if (size > fileSize) {
size = fileSize; size = fileSize;
} }
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0); struct HandleMappingTuple tuple = {0};
return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size); tuple.handle = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
tuple.mapping = MapViewOfFile(tuple.handle, mapFiles, 0, 0, size);
*HandleMappingListAppend(&vfd->handles) = tuple;
return tuple.mapping;
} }
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) { static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
UNUSED(size); UNUSED(size);
struct VFileFD* vfd = (struct VFileFD*) vf; struct VFileFD* vfd = (struct VFileFD*) vf;
size_t i;
for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
if (HandleMappingListGetPointer(&vfd->handles, i)->mapping == memory) {
CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
HandleMappingListShift(&vfd->handles, i, 1);
break;
}
}
UnmapViewOfFile(memory); UnmapViewOfFile(memory);
CloseHandle(vfd->hMap);
vfd->hMap = 0;
} }
#endif #endif