Introduce a new data structure to manage the allocated pages from the
system. This is meant to deprecate certain memory system call wrappers
in Scudo, e.g., map()/unmap(). Besides, we would like to make
MapPlatformData to be appeared in platform specific data structure only.
Given that there are several allocators in Scudo and each of them has
different way of page management. The deprecation will be done in
several CLs. In this commit, we start from SizeClassAllocator64.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
So far I call it RFC but it's a formal CL as well. There are still many places we can simplify. In order to make the review process easier, I'll do the simplification in coming CLs.
compiler-rt/lib/scudo/standalone/release.h | ||
---|---|---|
50 | Note:This will be deprecated as well. |
compiler-rt/lib/scudo/standalone/mem_map.h | ||
---|---|---|
76 | Per discussion, this may not be a good name. It may lead some confusion. I'm considering to make it either ReservedMemory or change it to has-a relation. |
- Rename MapReserver to ReservedMap.
- Add more comments on why ReservedMap still derives from MemMapBase
- Leave the unused functions in ReservedMap unimplemented (which were having default implementations which does nothing)
compiler-rt/lib/scudo/standalone/mem_map.h | ||
---|---|---|
81 | Will be rephrased as `ReservedMap` is a special MemMap which still manages a contiguous pages |
compiler-rt/lib/scudo/standalone/mem_map.h | ||
---|---|---|
68 | We may consider having two versions of this operation,
The reason for this is these two operations have performance difference on some platforms and in Scudo, not all releasePagesToOS calls reply on the zero-fill property. Will update the CL with this change |
Move some stuff to mem_map_base.h so that it will make the use of platform MemMap easier.
Also add more comments and checks
compiler-rt/lib/scudo/standalone/mem_map.cpp | ||
---|---|---|
42 | Should you verify that Addr is within the actual map? | |
47 | Similar to above, should you verify that this is within the actual map? | |
compiler-rt/lib/scudo/standalone/mem_map.h | ||
58 | This is slightly confusing. Perhaps reworded something like: The following functions correspond to the Impl functions from MemMapBase. | |
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
18 ↗ | (On Diff #507135) | this |
19–20 ↗ | (On Diff #507135) | Do you mean before the operation is executed? The wording is a bit confusing. |
22 ↗ | (On Diff #507135) | A class derived from |
22 ↗ | (On Diff #507135) | handle contiguous pages |
23 ↗ | (On Diff #507135) | derived class uses. |
28–29 ↗ | (On Diff #507135) | it has to implement all of the 'Impl' named functions. |
34 ↗ | (On Diff #507135) | set of pages |
35 ↗ | (On Diff #507135) | any |
58 ↗ | (On Diff #507135) | set of physical |
85 ↗ | (On Diff #507135) | a set of contiguous pages |
86 ↗ | (On Diff #507135) | a set of contiguous pages |
97 ↗ | (On Diff #507135) | functions are not used and should not be defined in |
98 ↗ | (On Diff #507135) | following |
99 ↗ | (On Diff #507135) | that a derived class has to implement. |
Address review comment
compiler-rt/lib/scudo/standalone/mem_map.cpp | ||
---|---|---|
42 | The basic invariant of the API is verified in the base class (mem_map_base.h), For example, bool remap(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { DCHECK(isAllocated()); DCHECK((Addr >= getMapBase()) || (Addr + Size <= getMapBase() + getMapCapacity())); return static_cast<Derived *>(this)->remapImpl(Addr, Size, Name, Flags); } | |
47 | Same as above. | |
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
19–20 ↗ | (On Diff #507135) | Yes, reworded a little bit. |
86 ↗ | (On Diff #507135) | The suggestion is a little bit different from above. I follow the suggestion here (suppose the above didn't mark the right range to update) |
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
---|---|---|
45 ↗ | (On Diff #507215) | I'm wrapping this ugly cast as Fabio suggested |
Rename ReservedMap to ReservedMemory and untangle it with MemMap
Change the names of some APIs
Hi @Chia-hungDuan, thank you for bringing this new design forward!
I've left some notes on specific APIs, and I also have some other general suggestions:
- It would be useful to document what flags are acceptable in a comment next to each method.
- As you know, Fuchsia doesn't accept addresses and sizes that are not page-aligned, so I suggest to add page-alignment checks to all the arguments.
- I am slightly confused by the fact that some arguments are called Size but the corresponding property is called Capacity. Is there any specific reason why you didn't use Size everywhere?
compiler-rt/lib/scudo/standalone/mem_map.h | ||
---|---|---|
35–37 | Since these methods are only called by the wrappers in MemMapBase and they always pass a Flags value, I suggest to remove the default values here | |
60–61 | Same suggestion as above on the Flags. | |
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
22 ↗ | (On Diff #507936) | I assume that the contract is that the ctor creates an object such that !isAllocated(). Should we also have a dtor that automatically unmaps if still isAllocated()? |
24–25 ↗ | (On Diff #507936) | If Addr is only a suggestion, I suggest to remove it completely from this API. For carefully-placed memory ranges, clients will use ReservedMemory and dispatch |
26–27 ↗ | (On Diff #507936) | Are you referring to Trusty? I would move this comment to unmap |
29 ↗ | (On Diff #507936) | Should this also check that !isAllocated() as a precondition? |
34 ↗ | (On Diff #507936) | I think we do not need Flags for unmap in this new design. Is there any specific flag that you have in mind? From a quick look, it seems to me that we can safely get rid of the UNMAP_ALL flag if we add explicit alignment control to cover primary32.h's special case. Also, Fuchsia does not have a syscall to shrink a VMO from the beginning. Would it be a problem if we only allowed to shrink from the end? |
40–42 ↗ | (On Diff #507936) | I would separate resizing and changing permissions into different methods (even on Linux, mremap and mprotect are separate syscalls).
|
49–51 ↗ | (On Diff #507936) | What do "physical" and "virtual" mean in this context? (maybe this a stale comment from the previous revision of this CL) |
59 ↗ | (On Diff #507936) | The distinction between releasePagesToOS and releaseAndZeroPagesToOS does not currently exist in Scudo, right? Can we add it as a new feature in a later CL? |
86 ↗ | (On Diff #507936) | Similar to above, I assume that the ctor creates an object such that !isCreated(). Should we also have a dtor that automatically releases if still isCreated()? |
91 ↗ | (On Diff #507936) | Should this also check that !isCreated() as a precondition? |
95 ↗ | (On Diff #507936) | Similarly, I think we do not need Flags for release either. |
Address review comment
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
---|---|---|
22 ↗ | (On Diff #507936) | These two are supposed to be lazy initialized so the creation needs to be done explicitly. The order of destructing allocator fields is tricky. Especially we have the thread local cache. Given that tearing down the allocator only happens at program exit, we just make them being released naturally. Therefore, the creation/deletion are done explicitly. We have been thinking to make it more elegantly but that depends on too many stuff (e.g., libc). Besides, this CL is supposed to do the abstraction transition only, I prefer to do further logic changes in the later CLs. |
24–25 ↗ | (On Diff #507936) | I prefer to keep this suggestion because it can still benefit some contexts (like some cache management stuff we will have in the future). It's a different case than ReservedMemory supposed to cover. |
34 ↗ | (On Diff #507936) | Like the release one, the only case I was thinking is the UNMAP_ALL for Fuchsia, if you think it's fine to remove it. I'm happy to do that :) is there any alternative way to achieve this? Like create a new VMO ? |
40–42 ↗ | (On Diff #507936) | The MemMap is a handle of range of virtual address and it's supposed to do the supported operations in the range. So it can remap part of the virtual address. For example, the RegionBeg is unlikely to be equal to Region base address. That's why we have this Addr argument here (For future function it'll be useful as well). If a platform doesn't allow this, then we just do the valid operation in that platform to fulfill their constraint. BTW, we have setMemoryPermission (which is added in the follow up CL) |
49–51 ↗ | (On Diff #507936) | It means virtual memory and physical memory. |
59 ↗ | (On Diff #507936) | In general, yes, we may consider adding this in a separate CL. The reason I do it here is that we are revising API contract and try to reduce ambiguity. For example, the arguments of releasePagesToOS was confusing. And then we found that the zero-page stuff is ambiguous as well. That's why I bring it in this CL. |
86 ↗ | (On Diff #507936) | Same as above. |
91 ↗ | (On Diff #507936) | This is intended to make it implementation defined behavior. In some case we may want few reserved spaces. |
95 ↗ | (On Diff #507936) | I was hesitating this before and the only case is UNMAP_ALL used by Fuchsia. If you agree that we can get rid of it. I'm happy with that :) Done. |
compiler-rt/lib/scudo/standalone/mem_map_base.h | ||
---|---|---|
91 ↗ | (On Diff #507936) | Oops, please ignore this wrong reply. |
Make ReservedMemory::create return boolean to indicate if the creation succeeds.
This makes the page allocation have the consistent style of API
compiler-rt/lib/scudo/standalone/primary64.h | ||
---|---|---|
736–748 | This used to be a grow operation for a memory region that always started at RegionBeg. Now we are dispatching at getRegionBaseByClassId(ClassId) and then resizing starting from RegionBeg. Can we directly dispatch at RegionBeg instead? |
compiler-rt/lib/scudo/standalone/primary64.h | ||
---|---|---|
736–748 | Because it's a region's base, I tended to think it's still part of a region. To make it work before transition to each platform specific implementation. I agree that we can dispatch the reserved memory from RegionBeg and fix it back later |
Since these methods are only called by the wrappers in MemMapBase and they always pass a Flags value, I suggest to remove the default values here