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 GIF view not allowing manual filename entry
- Util: Fix crash reading invalid ELFs
- VFS: Fix handle leak when double-mapping (fixes mgba.io/i/1659)
Misc:
- FFmpeg: Add more presets
- 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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -14,11 +14,23 @@
#include <windows.h>
#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 VFile d;
int fd;
#ifdef _WIN32
HANDLE hMap;
struct HandleMappingList handles;
#endif
};
@ -74,12 +86,23 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.truncate = _vfdTruncate;
vfd->d.size = _vfdSize;
vfd->d.sync = _vfdSync;
#ifdef _WIN32
HandleMappingListInit(&vfd->handles, 4);
#endif
return &vfd->d;
}
bool _vfdClose(struct VFile* 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) {
return false;
}
@ -134,16 +157,25 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
if (size > fileSize) {
size = fileSize;
}
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
struct HandleMappingTuple tuple = {0};
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) {
UNUSED(size);
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);
CloseHandle(vfd->hMap);
vfd->hMap = 0;
}
#endif