diff --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp --- a/compiler-rt/lib/dfsan/dfsan.cpp +++ b/compiler-rt/lib/dfsan/dfsan.cpp @@ -274,9 +274,9 @@ return label; } -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __dfsan_set_label(dfsan_label label, void *addr, uptr size) { - for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) { +static void __dfsan_set_label_at_shadow_space(dfsan_label label, + dfsan_label *labelp, uptr size) { + for (; size != 0; --size, ++labelp) { // Don't write the label if it is already the value we need it to be. // In a program where most addresses are not labeled, it is common that // a page of shadow memory is entirely zeroed. The Linux copy-on-write @@ -292,6 +292,37 @@ } } +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label( + dfsan_label label, void *addr, uptr size) { + const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr); + + if (0 != label) { + __dfsan_set_label_at_shadow_space(label, (dfsan_label *)beg_shadow_addr, + size); + return; + } + + // If label is 0, releases the pages within the shadow address range, and sets + // the shadow addresses not on the pages to be 0. + const void *end_addr = (void *)((uptr)addr + size); + const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr); + const uptr page_size = GetPageSizeCached(); + const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size); + const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size); + + // When the entire shadow address range is on one page, it is not possible to + // release the page. + if (beg_aligned >= end_aligned) + return __dfsan_set_label_at_shadow_space( + label, (dfsan_label *)beg_shadow_addr, size); + + __dfsan_set_label_at_shadow_space(label, (dfsan_label *)beg_shadow_addr, + beg_aligned - beg_shadow_addr); + ReleaseMemoryPagesToOS(beg_aligned, end_aligned); + __dfsan_set_label_at_shadow_space(label, (dfsan_label *)end_aligned, + end_shadow_addr - end_aligned); +} + SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label(dfsan_label label, void *addr, uptr size) { __dfsan_set_label(label, addr, size); 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 @@ -20,19 +20,7 @@ using namespace __sanitizer; -namespace { - -bool interceptors_initialized; - -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 +static bool interceptors_initialized; INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { @@ -46,7 +34,7 @@ res = REAL(mmap)(addr, length, prot, flags, fd, offset); if (res != (void *)-1) - ReleaseShadowMemoryPagesToOS(res, length); + dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); return res; } @@ -54,15 +42,14 @@ int fd, OFF64_T offset) { void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); if (res != (void *)-1) - ReleaseShadowMemoryPagesToOS(res, length); + dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); return res; } INTERCEPTOR(int, munmap, void *addr, SIZE_T length) { int res = REAL(munmap)(addr, length); - if (res != -1) { - ReleaseShadowMemoryPagesToOS(addr, length); - } + if (res != -1) + dfsan_set_label(0, addr, RoundUpTo(length, GetPageSizeCached())); return res; }