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