| 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 | |
| 14 | size_t () { |
| 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 ; |
| 26 | // DFSan's sscanf is broken and doesn't check for ordinary characters in |
| 27 | // the format string, hence we use strstr as a secondary check |
| 28 | // (https://github.com/llvm/llvm-project/issues/94769). |
| 29 | if ((sscanf(s: buf, format: "Rss: %ld kB" , &rss) == 1) && |
| 30 | (strstr(haystack: buf, needle: "Rss: " ) != NULL)) |
| 31 | ret += rss; |
| 32 | } |
| 33 | assert(feof(f)); |
| 34 | fclose(stream: f); |
| 35 | |
| 36 | return ret; |
| 37 | } |
| 38 | |
| 39 | int main(int argc, char **argv) { |
| 40 | const size_t map_size = 100 << 20; |
| 41 | size_t before = get_rss_kb(); |
| 42 | |
| 43 | // mmap and touch all addresses. The overhead is 1x. |
| 44 | char *p = mmap(NULL, len: map_size, PROT_READ | PROT_WRITE, |
| 45 | MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0); |
| 46 | memset(s: p, c: 0xff, n: map_size); |
| 47 | size_t after_mmap = get_rss_kb(); |
| 48 | |
| 49 | // store labels to all addresses. The overhead is 2x. |
| 50 | const dfsan_label label = 8; |
| 51 | char val = 0xff; |
| 52 | dfsan_set_label(label, addr: &val, size: sizeof(val)); |
| 53 | memset(s: p, c: val, n: map_size); |
| 54 | size_t after_mmap_and_set_label = get_rss_kb(); |
| 55 | |
| 56 | // fixed-mmap the same address. OS recyles pages and reinitializes data at the |
| 57 | // address. This should be the same to calling munmap. |
| 58 | p = mmap(addr: p, len: map_size, PROT_READ | PROT_WRITE, |
| 59 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, fd: -1, offset: 0); |
| 60 | size_t after_fixed_mmap = get_rss_kb(); |
| 61 | |
| 62 | // store labels to all addresses. |
| 63 | memset(s: p, c: val, n: map_size); |
| 64 | size_t after_mmap_and_set_label2 = get_rss_kb(); |
| 65 | |
| 66 | // munmap the addresses. |
| 67 | munmap(addr: p, len: map_size); |
| 68 | size_t after_munmap = get_rss_kb(); |
| 69 | |
| 70 | fprintf( |
| 71 | stderr, |
| 72 | format: "RSS at start: %zu, after mmap: %zu, after mmap+set label: %zu, after " |
| 73 | "fixed map: %zu, after another mmap+set label: %zu, after munmap: %zu\n" , |
| 74 | before, after_mmap, after_mmap_and_set_label, after_fixed_mmap, |
| 75 | after_mmap_and_set_label2, after_munmap); |
| 76 | |
| 77 | // This is orders of magnitude larger than we expect (typically < 10,000KB). |
| 78 | // It is a quick check to ensure that the RSS calculation function isn't |
| 79 | // egregriously wrong. |
| 80 | assert(before < 1000000); |
| 81 | |
| 82 | const size_t mmap_cost_kb = map_size >> 10; |
| 83 | // Shadow space (1:1 with application memory) |
| 84 | const size_t mmap_shadow_cost_kb = sizeof(dfsan_label) * mmap_cost_kb; |
| 85 | #ifdef ORIGIN_TRACKING |
| 86 | // Origin space (1:1 with application memory) |
| 87 | const size_t mmap_origin_cost_kb = mmap_cost_kb; |
| 88 | #else |
| 89 | const size_t mmap_origin_cost_kb = 0; |
| 90 | #endif |
| 91 | assert(after_mmap >= before + mmap_cost_kb); |
| 92 | assert(after_mmap_and_set_label >= |
| 93 | after_mmap + mmap_shadow_cost_kb + mmap_origin_cost_kb); |
| 94 | assert(after_mmap_and_set_label2 >= |
| 95 | before + mmap_cost_kb + mmap_shadow_cost_kb + mmap_origin_cost_kb); |
| 96 | |
| 97 | #ifdef ORIGIN_TRACKING |
| 98 | // This value is chosen based on observed difference. |
| 99 | const size_t mmap_origin_chain_kb = 4000; |
| 100 | #else |
| 101 | const size_t mmap_origin_chain_kb = 0; |
| 102 | #endif |
| 103 | |
| 104 | // RSS may not change memory amount after munmap to the same level as the |
| 105 | // start of the program. The assert checks the memory up to a delta. |
| 106 | const size_t delta = 5000; |
| 107 | // Origin chains are not freed, even when the origin space which refers to |
| 108 | // them is freed, so mmap_origin_chain_kb is added to account for this. |
| 109 | assert(after_fixed_mmap <= before + delta + mmap_origin_chain_kb); |
| 110 | assert(after_munmap <= before + delta + mmap_origin_chain_kb); |
| 111 | |
| 112 | return 0; |
| 113 | } |
| 114 | |