xref: /llvm-project/compiler-rt/test/sanitizer_common/TestCases/Linux/release_to_os_test.cpp (revision 75b0a99668cef7abaf36e09c41bb1eb91234bbf3)
1 // RUN: %clangxx %s -o %t
2 // RUN: env %tool_options=allocator_release_to_os_interval_ms=-1 %run %t
3 
4 // Temporarily disable test
5 // UNSUPPORTED: tsan
6 // UNSUPPORTED: target={{(powerpc64|loongarch64).*}}
7 
8 // Not needed, no allocator.
9 // UNSUPPORTED: ubsan
10 
11 // FIXME: This mode uses 32bit allocator without purge.
12 // UNSUPPORTED: hwasan-aliasing
13 
14 #include <algorithm>
15 #include <assert.h>
16 #include <fcntl.h>
17 #include <random>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/mman.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <sanitizer/allocator_interface.h>
28 
29 const size_t kPageSize = 4096;
30 
sync_rss()31 void sync_rss() {
32   char *page =
33       (char *)mmap((void *)&sync_rss, kPageSize, PROT_READ | PROT_WRITE,
34                    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
35   // Linux kernel updates RSS counters after a set number of page faults.
36   for (int i = 0; i < 10000; ++i) {
37     page[0] = 42;
38     madvise(page, kPageSize, MADV_DONTNEED);
39   }
40   munmap(page, kPageSize);
41 }
42 
current_rss()43 size_t current_rss() {
44   sync_rss();
45   int statm_fd = open("/proc/self/statm", O_RDONLY);
46   assert(statm_fd >= 0);
47 
48   char buf[100];
49   assert(read(statm_fd, &buf, sizeof(buf)) > 0);
50   size_t size, rss;
51   assert(sscanf(buf, "%zu %zu", &size, &rss) == 2);
52 
53   close(statm_fd);
54   return rss;
55 }
56 
MallocReleaseStress()57 size_t MallocReleaseStress() {
58   const size_t kNumChunks = 10000;
59   const size_t kAllocSize = 100;
60   const size_t kNumIter = 100;
61   uintptr_t *chunks[kNumChunks] = {0};
62   std::mt19937 r;
63 
64   for (size_t iter = 0; iter < kNumIter; iter++) {
65     std::shuffle(chunks, chunks + kNumChunks, r);
66     size_t to_replace = rand() % kNumChunks;
67     for (size_t i = 0; i < kNumChunks; i++) {
68       if (chunks[i])
69         assert(chunks[i][0] == (uintptr_t)chunks[i]);
70       if (i < to_replace) {
71         delete[] chunks[i];
72         chunks[i] = new uintptr_t[kAllocSize];
73         chunks[i][0] = (uintptr_t)chunks[i];
74       }
75     }
76   }
77   fprintf(stderr, "before delete: %zu\n", current_rss());
78   for (auto p : chunks)
79     delete[] p;
80   return kNumChunks * kAllocSize * sizeof(uintptr_t);
81 }
82 
main(int argc,char ** argv)83 int main(int argc, char **argv) {
84   // 32bit asan allocator is unsupported.
85   if (sizeof(void *) < 8)
86     return 0;
87   auto a = current_rss();
88   auto total = MallocReleaseStress() >> 10;
89   auto b = current_rss();
90   __sanitizer_purge_allocator();
91   auto c = current_rss();
92   fprintf(stderr, "a:%zu b:%zu c:%zu total:%zu\n", a, b, c, total);
93   assert(a + total / 8 < b);
94   assert(c + total / 8 < b);
95 }
96