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// Page size is hardcoded below, but test still fails even if not hardcoded.
15// REQUIRES: page-size-4096
16
17#include <algorithm>
18#include <assert.h>
19#include <fcntl.h>
20#include <random>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/mman.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <unistd.h>
29
30#include <sanitizer/allocator_interface.h>
31
32const size_t kPageSize = 4096;
33
34void sync_rss() {
35 char *page =
36 (char *)mmap(addr: (void *)&sync_rss, len: kPageSize, PROT_READ | PROT_WRITE,
37 MAP_PRIVATE | MAP_ANONYMOUS, fd: 0, offset: 0);
38 // Linux kernel updates RSS counters after a set number of page faults.
39 for (int i = 0; i < 10000; ++i) {
40 page[0] = 42;
41 madvise(addr: page, len: kPageSize, MADV_DONTNEED);
42 }
43 munmap(addr: page, len: kPageSize);
44}
45
46size_t current_rss() {
47 sync_rss();
48 int statm_fd = open(file: "/proc/self/statm", O_RDONLY);
49 assert(statm_fd >= 0);
50
51 char buf[100];
52 assert(read(statm_fd, &buf, sizeof(buf)) > 0);
53 size_t size, rss;
54 assert(sscanf(buf, "%zu %zu", &size, &rss) == 2);
55
56 close(fd: statm_fd);
57 return rss;
58}
59
60size_t MallocReleaseStress() {
61 const size_t kNumChunks = 10000;
62 const size_t kAllocSize = 100;
63 const size_t kNumIter = 100;
64 uintptr_t *chunks[kNumChunks] = {0};
65 std::mt19937 r;
66
67 for (size_t iter = 0; iter < kNumIter; iter++) {
68 std::shuffle(first: chunks, last: chunks + kNumChunks, g&: r);
69 size_t to_replace = rand() % kNumChunks;
70 for (size_t i = 0; i < kNumChunks; i++) {
71 if (chunks[i])
72 assert(chunks[i][0] == (uintptr_t)chunks[i]);
73 if (i < to_replace) {
74 delete[] chunks[i];
75 chunks[i] = new uintptr_t[kAllocSize];
76 chunks[i][0] = (uintptr_t)chunks[i];
77 }
78 }
79 }
80 fprintf(stderr, format: "before delete: %zu\n", current_rss());
81 for (auto p : chunks)
82 delete[] p;
83 return kNumChunks * kAllocSize * sizeof(uintptr_t);
84}
85
86int main(int argc, char **argv) {
87 // 32bit asan allocator is unsupported.
88 if (sizeof(void *) < 8)
89 return 0;
90 auto a = current_rss();
91 auto total = MallocReleaseStress() >> 10;
92 auto b = current_rss();
93 __sanitizer_purge_allocator();
94 auto c = current_rss();
95 fprintf(stderr, format: "a:%zu b:%zu c:%zu total:%zu\n", a, b, c, total);
96 assert(a + total / 8 < b);
97 assert(c + total / 8 < b);
98}
99

source code of compiler-rt/test/sanitizer_common/TestCases/Linux/release_to_os_test.cpp