1// DFSAN_OPTIONS=no_huge_pages_for_shadow=false RUN: %clang_dfsan %s -o %t && %run %t
2// DFSAN_OPTIONS=no_huge_pages_for_shadow=true RUN: %clang_dfsan %s -o %t && %run %t
3// DFSAN_OPTIONS=no_huge_pages_for_shadow=false RUN: %clang_dfsan %s -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -o %t && %run %t
4// DFSAN_OPTIONS=no_huge_pages_for_shadow=true RUN: %clang_dfsan %s -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -o %t && %run %t
5
6#include <assert.h>
7#include <sanitizer/dfsan_interface.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <string.h>
11#include <sys/mman.h>
12#include <unistd.h>
13
14size_t get_rss_kb() {
15 size_t ret = 0;
16 pid_t pid = getpid();
17
18 char fname[256];
19 sprintf(s: fname, format: "/proc/%ld/task/%ld/smaps", (long)pid, (long)pid);
20 FILE *f = fopen(filename: fname, modes: "r");
21 assert(f);
22
23 char buf[256];
24 while (fgets(s: buf, n: sizeof(buf), stream: f) != NULL) {
25 int64_t rss;
26 if (sscanf(s: buf, format: "Rss: %ld kB", &rss) == 1)
27 ret += rss;
28 }
29 assert(feof(f));
30 fclose(stream: f);
31
32 return ret;
33}
34
35int main(int argc, char **argv) {
36 const size_t map_size = 100 << 20;
37 size_t before = get_rss_kb();
38
39 // mmap and touch all addresses. The overhead is 1x.
40 char *p = mmap(NULL, len: map_size, PROT_READ | PROT_WRITE,
41 MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0);
42 memset(s: p, c: 0xff, n: map_size);
43 size_t after_mmap = get_rss_kb();
44
45 // store labels to all addresses. The overhead is 2x.
46 const dfsan_label label = 8;
47 char val = 0xff;
48 dfsan_set_label(label, addr: &val, size: sizeof(val));
49 memset(s: p, c: val, n: map_size);
50 size_t after_mmap_and_set_label = get_rss_kb();
51
52 // fixed-mmap the same address. OS recyles pages and reinitializes data at the
53 // address. This should be the same to calling munmap.
54 p = mmap(addr: p, len: map_size, PROT_READ | PROT_WRITE,
55 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, fd: -1, offset: 0);
56 size_t after_fixed_mmap = get_rss_kb();
57
58 // store labels to all addresses.
59 memset(s: p, c: val, n: map_size);
60 size_t after_mmap_and_set_label2 = get_rss_kb();
61
62 // munmap the addresses.
63 munmap(addr: p, len: map_size);
64 size_t after_munmap = get_rss_kb();
65
66 fprintf(
67 stderr,
68 format: "RSS at start: %zu, after mmap: %zu, after mmap+set label: %zu, after "
69 "fixed map: %zu, after another mmap+set label: %zu, after munmap: %zu\n",
70 before, after_mmap, after_mmap_and_set_label, after_fixed_mmap,
71 after_mmap_and_set_label2, after_munmap);
72
73 const size_t mmap_cost_kb = map_size >> 10;
74 // Shadow space (1:1 with application memory)
75 const size_t mmap_shadow_cost_kb = sizeof(dfsan_label) * mmap_cost_kb;
76#ifdef ORIGIN_TRACKING
77 // Origin space (1:1 with application memory)
78 const size_t mmap_origin_cost_kb = mmap_cost_kb;
79#else
80 const size_t mmap_origin_cost_kb = 0;
81#endif
82 assert(after_mmap >= before + mmap_cost_kb);
83 assert(after_mmap_and_set_label >=
84 after_mmap + mmap_shadow_cost_kb + mmap_origin_cost_kb);
85 assert(after_mmap_and_set_label2 >=
86 before + mmap_cost_kb + mmap_shadow_cost_kb + mmap_origin_cost_kb);
87
88#ifdef ORIGIN_TRACKING
89 // This value is chosen based on observed difference.
90 const size_t mmap_origin_chain_kb = 4000;
91#else
92 const size_t mmap_origin_chain_kb = 0;
93#endif
94
95 // RSS may not change memory amount after munmap to the same level as the
96 // start of the program. The assert checks the memory up to a delta.
97 const size_t delta = 5000;
98 // Origin chains are not freed, even when the origin space which refers to
99 // them is freed, so mmap_origin_chain_kb is added to account for this.
100 assert(after_fixed_mmap <= before + delta + mmap_origin_chain_kb);
101 assert(after_munmap <= before + delta + mmap_origin_chain_kb);
102
103 return 0;
104}
105

source code of compiler-rt/test/dfsan/release_shadow_space.c