From 7fcc801d0183f89934ec230c2782591bdd5b285c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Wed, 28 Oct 2015 22:41:17 +0100 Subject: [PATCH] Cleanup allocated segments on disposal --- src/openrct2.c | 70 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/src/openrct2.c b/src/openrct2.c index 02243a2530..8271397a2f 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -58,6 +58,12 @@ bool gOpenRCT2Headless = false; bool gOpenRCT2ShowChangelog; +#if defined(__linux__) +void *gDataSegment; +void *gTextSegment; +int gExeFd; +#endif // defined(__linux__) + /** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to 0. */ int _finished; @@ -66,6 +72,7 @@ static struct { sint16 x, y, z; } _spritelocations1[MAX_SPRITES], _spritelocatio static void openrct2_loop(); static bool openrct2_setup_rct2_segment(); +static bool openrct2_release_rct2_segment(); static void openrct2_setup_rct2_hooks(); static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 *newDirectory, const utf8 *extension) @@ -308,6 +315,7 @@ void openrct2_dispose() network_close(); http_dispose(); language_close_all(); + openrct2_release_rct2_segment(); platform_free(); } @@ -465,8 +473,8 @@ static bool openrct2_setup_rct2_segment() #define DATA_OFFSET 0x004A4000 const char *exepath = "openrct2.exe"; - int fd = open(exepath, O_RDONLY); - if (fd < 0) { + gExeFd = open(exepath, O_RDONLY); + if (gExeFd < 0) { log_fatal("failed to open %s, errno = %d", exepath, errno); exit(1); } @@ -503,23 +511,22 @@ static bool openrct2_setup_rct2_segment() int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB // section: rw data - void *base = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, 0, 0); - log_warning("base = %x, 0x01423b40 >= base == %i, 0x01423b40 < base + len == %i", base, (void *)0x01423b40 >= base, (void *)0x01423b40 < base + len); - if (base == MAP_FAILED) { - log_warning("errno = %i", errno); + gDataSegment = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, 0, 0); + if (gDataSegment != (void *)0x8a4000) { + log_fatal("mmap failed to get required offset for data segment! got %p, expected %p, errno = %d", gDataSegment, (void *)(0x8a4000), errno); exit(1); } len = 0x004A3000; // section: text - void *base2 = mmap((void *)(0x401000), len, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, fd, 0x1000); - if (base2 != (void *)(0x401000)) + gTextSegment = mmap((void *)(0x401000), len, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, gExeFd, 0x1000); + if (gTextSegment != (void *)(0x401000)) { - log_fatal("mmap failed to get required offset! got %p, expected %p, errno = %d", base2, (void *)(0x401000), errno); + log_fatal("mmap failed to get required offset for text segment! got %p, expected %p, errno = %d", gTextSegment, (void *)(0x401000), errno); exit(1); } - void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0); + void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, gExeFd, 0); int err = errno; log_warning("mmapped file to %p", fbase); if (fbase == MAP_FAILED) @@ -529,7 +536,13 @@ static bool openrct2_setup_rct2_segment() } // .rdata and real part of .data // 0x9e2000 - 0x8a4000 = 0x13e000 - memcpy(base, fbase + DATA_OFFSET, 0x13e000); + memcpy(gDataSegment, fbase + DATA_OFFSET, 0x13e000); + err = munmap(fbase, file_size); + if (err != 0) + { + err = errno; + log_error("Failed to unmap file! errno = %d", err); + } #endif // __linux__ // Check that the expected data is at various addresses. @@ -546,6 +559,41 @@ static bool openrct2_setup_rct2_segment() return true; } +/** + * Releases segments created with @ref openrct2_setup_rct2_segment, if any. + */ +static bool openrct2_release_rct2_segment() +{ + bool result = true; +#if defined(__linux__) + int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB + int err; + err = munmap(gDataSegment, len); + if (err != 0) + { + err = errno; + log_error("Failed to unmap data segment! errno = %d", err); + result = false; + } + len = 0x004A3000; + err = munmap(gTextSegment, len); + if (err != 0) + { + err = errno; + log_error("Failed to unmap text segment! errno = %d", err); + result = false; + } + err = close(gExeFd); + if (err != 0) + { + err = errno; + log_error("Failed to close file! errno = %d", err); + result = false; + } +#endif // defined(__linux__) + return result; +} + /** * Setup hooks to allow RCT2 to call OpenRCT2 functions instead. */