// RUN: %clangxx %s -o %t
// RUN: env %tool_options=allocator_release_to_os_interval_ms=-1 %run %t
// Temporarily disable test
// UNSUPPORTED: tsan
// UNSUPPORTED: target={{(powerpc64|loongarch64).*}}
// Not needed, no allocator.
// UNSUPPORTED: ubsan
// FIXME: This mode uses 32bit allocator without purge.
// UNSUPPORTED: hwasan-aliasing
#include <algorithm>
#include <assert.h>
#include <fcntl.h>
#include <random>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sanitizer/allocator_interface.h>
const size_t kPageSize = 4096;
void sync_rss() {
char *page =
(char *)mmap((void *)&sync_rss, kPageSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
// Linux kernel updates RSS counters after a set number of page faults.
for (int i = 0; i < 10000; ++i) {
page[0] = 42;
madvise(page, kPageSize, MADV_DONTNEED);
}
munmap(page, kPageSize);
}
size_t current_rss() {
sync_rss();
int statm_fd = open("/proc/self/statm", O_RDONLY);
assert(statm_fd >= 0);
char buf[100];
assert(read(statm_fd, &buf, sizeof(buf)) > 0);
size_t size, rss;
assert(sscanf(buf, "%zu %zu", &size, &rss) == 2);
close(statm_fd);
return rss;
}
size_t MallocReleaseStress() {
const size_t kNumChunks = 10000;
const size_t kAllocSize = 100;
const size_t kNumIter = 100;
uintptr_t *chunks[kNumChunks] = {0};
std::mt19937 r;
for (size_t iter = 0; iter < kNumIter; iter++) {
std::shuffle(chunks, chunks + kNumChunks, r);
size_t to_replace = rand() % kNumChunks;
for (size_t i = 0; i < kNumChunks; i++) {
if (chunks[i])
assert(chunks[i][0] == (uintptr_t)chunks[i]);
if (i < to_replace) {
delete[] chunks[i];
chunks[i] = new uintptr_t[kAllocSize];
chunks[i][0] = (uintptr_t)chunks[i];
}
}
}
fprintf(stderr, "before delete: %zu\n", current_rss());
for (auto p : chunks)
delete[] p;
return kNumChunks * kAllocSize * sizeof(uintptr_t);
}
int main(int argc, char **argv) {
// 32bit asan allocator is unsupported.
if (sizeof(void *) < 8)
return 0;
auto a = current_rss();
auto total = MallocReleaseStress() >> 10;
auto b = current_rss();
__sanitizer_purge_allocator();
auto c = current_rss();
fprintf(stderr, "a:%zu b:%zu c:%zu total:%zu\n", a, b, c, total);
assert(a + total / 8 < b);
assert(c + total / 8 < b);
}