[sanitizers][Windows] Implement __sanitizer_purge_allocator for Win64
Windows' memory unmapping has to be explicit, there is no madvise.
Similarly, re-mapping memory has to be explicit as well. This patch
implements a basic method for remapping memory which was previously
returned to the OS on Windows.
Patch by Matthew G. McGovern and Jordyn Puryear
GitOrigin-RevId: 81b1d3da094c54ffd75e05c8d4683792edf17f4c
diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h
index 0a18b0c..21b0366 100644
--- a/lib/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h
@@ -144,6 +144,17 @@
CompactPtrT *free_array = GetFreeArray(region_beg);
BlockingMutexLock l(®ion->mutex);
+#if SANITIZER_WINDOWS
+ /* On Windows unmapping of memory during __sanitizer_purge_allocator is
+ explicit and immediate, so unmapped regions must be explicitly mapped back
+ in when they are accessed again. */
+ if (region->rtoi.last_released_bytes > 0) {
+ MmapFixedOrDie(region_beg, region->mapped_user,
+ "SizeClassAllocator: region data");
+ region->rtoi.n_freed_at_last_release = 0;
+ region->rtoi.last_released_bytes = 0;
+ }
+#endif
if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
n_chunks - region->num_freed_chunks)))
diff --git a/lib/sanitizer_common/sanitizer_win.cpp b/lib/sanitizer_common/sanitizer_win.cpp
index 1b591f1..99ecfd0 100644
--- a/lib/sanitizer_common/sanitizer_win.cpp
+++ b/lib/sanitizer_common/sanitizer_win.cpp
@@ -334,8 +334,12 @@
}
void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
- // This is almost useless on 32-bits.
- // FIXME: add madvise-analog when we move to 64-bits.
+ uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
+ end_aligned = RoundDownTo(end, GetPageSizeCached());
+ CHECK(beg < end); // make sure the region is sane
+ if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page;
+ return;
+ UnmapOrDie((void *)beg, end_aligned - beg_aligned);
}
void SetShadowRegionHugePageMode(uptr addr, uptr size) {
diff --git a/test/asan/TestCases/Windows/sanitizer_purge.cpp b/test/asan/TestCases/Windows/sanitizer_purge.cpp
new file mode 100644
index 0000000..e3c7bfe
--- /dev/null
+++ b/test/asan/TestCases/Windows/sanitizer_purge.cpp
@@ -0,0 +1,31 @@
+#include <Windows.h>
+#include <stdio.h>
+#include <sanitizer/allocator_interface.h>
+#include <psapi.h>
+
+// RUN: %clang_cl_asan -Od %s -Fe%t
+// RUN: %t
+// REQUIRES: asan-64-bits
+
+size_t GetRSS() {
+ PROCESS_MEMORY_COUNTERS counters;
+ if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)))
+ return 0;
+ return counters.WorkingSetSize;
+}
+
+int main(){
+ for (int i = 0; i < 1000; i++) {
+ void* a = malloc(1000);
+ free(a);
+ }
+ size_t rss_pre = GetRSS();
+ __sanitizer_purge_allocator();
+ size_t rss_post = GetRSS();
+
+ if (rss_pre <= rss_post){
+ return -1;
+ }
+
+ return 0;
+}
\ No newline at end of file