When an application does a lot of pairs of mmap and munmap, if we did
not release shadoe memory used by mmap addresses, this would increase
memory usage.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Can we add a test that ensures RSS doesn't increase after a mmap + munmap pair?
compiler-rt/lib/dfsan/dfsan_interceptors.cpp | ||
---|---|---|
53 | Nit: GetPageSizeCached |
compiler-rt/test/dfsan/munmap_release_shadow.c | ||
---|---|---|
12 | Nit: get_rss_kb seems simpler | |
18 | Why ssize_t instead of size_t or long? | |
39 | Rather than returning errors from this function, can we simplify by asserting inline? | |
43 | I think the Linux kernel avoids reusing address space by default, so we don't need to give mmap hints. I think I'd prefer removing the hints to simplify the test. | |
69 | I'm not sure, but 4GB RSS might be too much on the buildbots. Can we simplify the test and reduce this by doing a single large mmap + munmap instead of many loops? |
compiler-rt/lib/dfsan/dfsan_interceptors.cpp | ||
---|---|---|
37 | With madvise by DONTNEED OR FREE (SANITIZER_MADVISE_DONTNEED) at munmap, is it possible to also remove these dfsan_set_labels ? Before the next access OS will zero-fill data. https://www.man7.org/linux/man-pages/man2/madvise.2.html says ... After a successful MADV_DONTNEED operation, the semantics of memory access in the specified region are changed: subsequent accesses of pages in the range will succeed, but will result in either ... or zero- fill-on-demand pages for anonymous private mappings. MADV_FREE (since Linux 4.5) ... Once pages in the range have been freed, the caller will see zero-fill-on-demand pages upon subsequent page references. """ | |
compiler-rt/test/dfsan/munmap_release_shadow.c | ||
43 | In our system, for some reason, the mmap likes to reuse the last address. Sometimes all returned addresses are the same from hundreds of runs. | |
69 | reduced to 50 loops. This reduced the max RSS below 500M. This also reduces its test time from 20s to 2-3s. |
compiler-rt/lib/dfsan/dfsan_interceptors.cpp | ||
---|---|---|
37 | Yes, it should work as an optimization. Happy to take a separate patch for it. | |
compiler-rt/test/dfsan/munmap_release_shadow.c | ||
43 | Ok. Then maybe let's make hint a static variable in mmap_track_and_munmap to simplify the logic. | |
69 | Do we need *any* loops at all? Isn't a single mmap + touch the memory + munmap enough to test that RSS increases then goes back down? The test seems overly complicated if it could be tested with something as simple as: const size_t map_size = 100 << 20; size_t before = get_rss_kb(); void *p = mmap(NULL, map_size, ...); memset(p, 0xff, map_size); size_t after_mmap = get_rss_kb(); munmap(p, map_size); size_t after_munmap = get_rss_kb(); assert(after_mmap >= before + 3 * map_size); assert(after_munmap <= after_mmap - 3 * map_size); |
compiler-rt/test/dfsan/munmap_release_shadow.c | ||
---|---|---|
28–31 |
I might be missing something, but if you release one of the shadow pages to the OS, couldn't it then accidentally use that page for one of the user anonymous mappings, thus breaking DFSan logic?
The mmap interceptions zero-out shadow spaces and anonymous mappings zero-fill mapped pages. So returning shadow pages at munmap equals to the existing behavior.
With madvise by DONTNEED OR FREE (SANITIZER_MADVISE_DONTNEED) at munmap, is it possible to also remove these dfsan_set_labels ? Before the next access OS will zero-fill data.
https://www.man7.org/linux/man-pages/man2/madvise.2.html says
"""
MADV_DONTNEED
MADV_FREE (since Linux 4.5)
"""