diff --git a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp --- a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp +++ b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp @@ -22,6 +22,18 @@ static bool interceptors_initialized; +namespace { + +void ReleaseShadowMemoryPagesToOS(void *addr, SIZE_T length) { + uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr); + void *end_addr = + (void *)((uptr)addr + RoundUpTo(length, GetPageSizeCached())); + uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr); + ReleaseMemoryPagesToOS(beg_shadow_addr, end_shadow_addr); +} + +} // namespace + INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { void *res; @@ -34,7 +46,7 @@ res = REAL(mmap)(addr, length, prot, flags, fd, offset); if (res != (void *)-1) - dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); + ReleaseShadowMemoryPagesToOS(res, length); return res; } @@ -42,18 +54,14 @@ int fd, OFF64_T offset) { void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); if (res != (void *)-1) - dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); + ReleaseShadowMemoryPagesToOS(res, length); return res; } INTERCEPTOR(int, munmap, void *addr, SIZE_T length) { int res = REAL(munmap)(addr, length); if (res != -1) { - uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr); - void *end_addr = - (void *)((uptr)addr + RoundUpTo(length, GetPageSizeCached())); - uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr); - ReleaseMemoryPagesToOS(beg_shadow_addr, end_shadow_addr); + ReleaseShadowMemoryPagesToOS(addr, length); } return res; } diff --git a/compiler-rt/test/dfsan/munmap_release_shadow.c b/compiler-rt/test/dfsan/munmap_release_shadow.c deleted file mode 100644 --- a/compiler-rt/test/dfsan/munmap_release_shadow.c +++ /dev/null @@ -1,54 +0,0 @@ -// RUN: %clang_dfsan %s -o %t && %run %t - -#include -#include -#include -#include -#include -#include -#include - -size_t get_rss_kb() { - long rss = 0L; - FILE *f = NULL; - assert((f = fopen("/proc/self/statm", "r"))); - assert(fscanf(f, "%*s%ld", &rss) == 1); - fclose(f); - return ((size_t)rss * (size_t)sysconf(_SC_PAGESIZE)) >> 10; -} - -int main(int argc, char **argv) { - const size_t map_size = 100 << 20; - size_t before = get_rss_kb(); - - char *p = mmap(NULL, map_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - const dfsan_label label = dfsan_create_label("l", 0); - char val = 0xff; - dfsan_set_label(label, &val, sizeof(val)); - memset(p, val, map_size); - size_t after_mmap = get_rss_kb(); - - munmap(p, map_size); - size_t after_munmap = get_rss_kb(); - - p = mmap(NULL, map_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - dfsan_set_label(label, &val, sizeof(val)); - memset(p, val, map_size); - size_t after_mmap2 = get_rss_kb(); - - fprintf(stderr, "RSS at start: %td, after mmap: %td, after mumap: %td, after mmap2: %td\n", - before, after_mmap, after_munmap, after_mmap2); - - // The memory after mmap increases 3 times of map_size because the overhead of - // shadow memory is 2x. - const size_t mmap_cost_kb = 3 * (map_size >> 10); - assert(after_mmap >= before + mmap_cost_kb); - // OS does not release memory to the same level as the start of the program. - // The assert checks the memory after munmap up to a delta. - const size_t delta = 50000; - assert(after_mmap2 <= after_mmap + delta); - - return 0; -} diff --git a/compiler-rt/test/dfsan/release_shadow_space.c b/compiler-rt/test/dfsan/release_shadow_space.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/release_shadow_space.c @@ -0,0 +1,90 @@ +// RUN: %clang_dfsan %s -o %t && %run %t + +#include +#include +#include +#include +#include +#include +#include + +size_t get_rss_kb() { + long rss = 0L; + FILE *f = NULL; + assert((f = fopen("/proc/self/statm", "r"))); + assert(fscanf(f, "%*s%ld", &rss) == 1); + fclose(f); + return ((size_t)rss * (size_t)sysconf(_SC_PAGESIZE)) >> 10; +} + +int main(int argc, char **argv) { + const size_t map_size = 100 << 20; + size_t before = get_rss_kb(); + + // mmap and touch all addresses. The overhead is 1x. + char *p = mmap(NULL, map_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(p, 0xff, map_size); + size_t after_mmap = get_rss_kb(); + + // store labels to all addresses. The overhead is 2x. + const dfsan_label label = dfsan_create_label("l", 0); + char val = 0xff; + dfsan_set_label(label, &val, sizeof(val)); + memset(p, val, map_size); + size_t after_mmap_and_set_label = get_rss_kb(); + + // munmap the addresses. This releases all the 3x memory to OS. However, the + // RSS number after this may not be reduced to the amount before the first + // map. We can confirm that the memory is indeed released by requesting more + // memory from OS and measuring RSS does not increase too much. + munmap(p, map_size); + size_t after_munmap = get_rss_kb(); + + // mmap the same amount of memory and store labels. This confirms that + // although after the last munmap RSS is not increased, memory is already + // returned to OS. + p = mmap(NULL, map_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + dfsan_set_label(label, &val, sizeof(val)); + memset(p, val, map_size); + size_t after_mmap_and_set_label2 = get_rss_kb(); + + // fixed-mmap the same address. OS recyles pages and reinitializes data at the + // address. This should be the same to calling mumap. But, for the same + // reason, RSS after this may look unchanged. + p = mmap(p, map_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + size_t after_fixed_mmap = get_rss_kb(); + + // Store labels to all addresses. This confirms that although after the last + // fixed-mmap RSS is not increased, memory is already returned to OS. + dfsan_set_label(label, &val, sizeof(val)); + memset(p, val, map_size); + size_t after_mmap_and_set_label3 = get_rss_kb(); + + fprintf( + stderr, + "RSS at start: %td, after mmap: %td, after mmap+set label: %td, after " + "mumap: %td, after another mmap+set label: %td, after fixed map: %td, " + "after another set label: %td\n", + before, after_mmap, after_mmap_and_set_label, after_munmap, + after_mmap_and_set_label2, after_fixed_mmap, after_mmap_and_set_label3); + + // The memory after mmap increases 3 times of map_size because the overhead of + // shadow memory is 2x. + const size_t mmap_cost_kb = map_size >> 10; + const size_t mmap_shadow_cost_kb = 2 * mmap_cost_kb; + assert(after_mmap >= before + mmap_cost_kb); + assert(after_mmap_and_set_label >= after_mmap + mmap_shadow_cost_kb); + // RSS may not change memory amount after munmap to the same level as the + // start of the program. The assert checks the memory after another mmap up to + // a delta. + const size_t delta = 50000; + assert(after_mmap_and_set_label2 <= after_mmap_and_set_label + delta); + // RSS may not change memory amount after fixed-mmap. The assert checks the + // memory after another memset up to a delta. + assert(after_mmap_and_set_label3 <= after_mmap_and_set_label2 + delta); + + return 0; +}