diff --git a/libmemory-patches/libmemory-patches.h b/libmemory-patches/libmemory-patches.h index 72c0ccc..0e890e1 100644 --- a/libmemory-patches/libmemory-patches.h +++ b/libmemory-patches/libmemory-patches.h @@ -40,6 +40,7 @@ struct current_memory_info LIBMEMORY_PATCHES_API extern struct current_memory_info get_current_memory_info(void); LIBMEMORY_PATCHES_API int overcommit_prevention_enabled(void); +LIBMEMORY_PATCHES_API int overcommit_prevention_exempt(void); LIBMEMORY_PATCHES_API BOOL memory_available_for_commit(size_t size); LIBMEMORY_PATCHES_API void touch_committed_pages(void* base, size_t size, uint32_t protect); LIBMEMORY_PATCHES_API BOOL has_write_flags(uint32_t protect); diff --git a/libmemory-patches/overcommit.c b/libmemory-patches/overcommit.c index 4271225..0a38d45 100644 --- a/libmemory-patches/overcommit.c +++ b/libmemory-patches/overcommit.c @@ -39,6 +39,90 @@ static const uint32_t page_writecopy_flags = PAGE_WRITECOPY; +/*********************************************************************** + * overcommit_prevention_exempt + * + * Determines if this process is exempt from overcommit prevention, but + * should still have it's writable memory mapped pages touched to ensure + * accurate memory tracking. + */ +int overcommit_prevention_exempt(void) +{ + static int overcommit_exempt = -1; + + if (overcommit_exempt == -1) + { + int exempt_debug; + { + const char *debug_env_var = getenv( "WINE_PREVENT_OVERCOMMIT_EXEMPT_DEBUG" ); + exempt_debug = debug_env_var && atoi(debug_env_var); + } + + const char *env_var = getenv( "WINE_PREVENT_OVERCOMMIT_EXEMPT" ); + if (env_var) + { + FILE *fp; + if (fp = fopen("/proc/self/cmdline", "r")) + { + char argument[1024]; + char buffer[1024]; + size_t arg_offset = 0; + if (exempt_debug) + { + puts("/proc/self/cmdline tolower:"); + } + size_t read; + do + { + read = fread(buffer, 1, sizeof buffer, fp); + for (size_t i = 0; i < read; i++) + { + if (arg_offset < (sizeof argument) - 1) + { + argument[arg_offset++] = tolower(buffer[i]); + } + else + { + argument[(sizeof argument) - 1] = '\0'; + } + + if (buffer[i] == '\0') + { + int non_empty_argument = arg_offset > 1; + arg_offset = 0; + + if (non_empty_argument && exempt_debug) + { + puts(argument); + } + + if (non_empty_argument && strstr(argument, env_var)) + { + if (exempt_debug) + { + printf( + "detected process name from WINE_PREVENT_OVERCOMMIT_EXEMPT '%s' is present in cmdline tolower argument '%s'. overcommit prevention will be turned off for this specific process.\n", + env_var, + argument); + } + overcommit_exempt = 1; + } + } + } + } while (read > 0); + fclose(fp); + } + } + + if (overcommit_exempt == -1) + { + overcommit_exempt = 0; + } + } + + return overcommit_exempt; +} + /*********************************************************************** * overcommit_prevention_enabled * @@ -48,6 +132,14 @@ int overcommit_prevention_enabled(void) { static int prevent_overcommit = -1; + if (prevent_overcommit == -1) + { + if (overcommit_prevention_exempt()) + { + prevent_overcommit = 0; + } + } + if (prevent_overcommit == -1) { const char *env_var = getenv( "WINE_PREVENT_OVERCOMMIT" ); diff --git a/patches/wine-overcommit-prevention-support.patch b/patches/wine-overcommit-prevention-support.patch index e668259..8733cad 100644 --- a/patches/wine-overcommit-prevention-support.patch +++ b/patches/wine-overcommit-prevention-support.patch @@ -241,7 +241,7 @@ index abe1b4dc4ec424c0864d18e726537e680d2ab883..e55d7e68d1b8d3967316f1101cb0ce9b VIRTUAL_DEBUG_DUMP_VIEW( view ); + + /* if overcommit prevention is enabled and we performed a commit, then touch the commited pages */ -+ if (write_consumes_memory && overcommit_prevention_enabled()) { ++ if (write_consumes_memory && (overcommit_prevention_enabled() || overcommit_prevention_exempt())) { + touch_committed_pages(view->base, size, protect); + } } @@ -267,7 +267,7 @@ index abe1b4dc4ec424c0864d18e726537e680d2ab883..e55d7e68d1b8d3967316f1101cb0ce9b *size_ptr = size; + + /* if overcommit prevention is enabled and we performed a commit, then touch the commited pages */ -+ if ((type & MEM_COMMIT) && overcommit_prevention_enabled()) { ++ if ((type & MEM_COMMIT) && (overcommit_prevention_enabled() || overcommit_prevention_exempt())) { + touch_committed_pages(base, size, protect); + } } @@ -295,7 +295,7 @@ index abe1b4dc4ec424c0864d18e726537e680d2ab883..e55d7e68d1b8d3967316f1101cb0ce9b status = set_protection( view, base, size, new_prot ); + + /* if overcommit prevention is enabled and write access was granted then touch the pages */ -+ if (overcommit_prevention_enabled() && write_or_copy_added) { ++ if ((overcommit_prevention_enabled() || overcommit_prevention_exempt()) && write_or_copy_added) { + touch_committed_pages(base, size, new_prot); + } }