void RunMallocHooks(const void *ptr, uptr size);
void RunFreeHooks(const void *ptr);
+class ReservedAddressRange {
+ public:
+ uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0);
+ uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false);
+ void Unmap(uptr addr, uptr size);
+ void *base() const { return base_; }
+ uptr size() const { return size_; }
+
+ private:
+ void* base_;
+ uptr size_;
+ const char* name_;
+};
+
typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
/*out*/uptr *stats, uptr stats_size);
return DoAnonymousMmapOrDie(size, mem_type, false, false);
}
+uptr ReservedAddressRange::Init(uptr init_size, const char* name,
+ uptr fixed_addr) {
+ base_ = MmapNoAccess(init_size);
+ size_ = init_size;
+ name_ = name;
+ return reinterpret_cast<uptr>(base_);
+}
+
+// Uses fixed_addr for now.
+// Will use offset instead once we've implemented this function for real.
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
+ bool tolerate_enomem) {
+ return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, map_size));
+}
+
+void ReservedAddressRange::Unmap(uptr addr, uptr size) {
+ void* addr_as_void = reinterpret_cast<void*>(addr);
+ uptr base_as_uptr = reinterpret_cast<uptr>(base_);
+ // Only unmap at the beginning or end of the range.
+ CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_))
+ CHECK_LE(size, size_);
+ UnmapOrDie(reinterpret_cast<void*>(addr), size);
+}
+
// MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator.
// Instead of doing exactly what they say, we make MmapNoAccess actually
// just allocate a VMAR to reserve the address space. Then MmapFixedOrDie
return (void *)p;
}
+uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {
+ if (fixed_addr) {
+ base_ = MmapFixedNoAccess(fixed_addr, size, name);
+ } else {
+ base_ = MmapNoAccess(size);
+ }
+ size_ = size;
+ name_ = name;
+ return reinterpret_cast<uptr>(base_);
+}
+
+// Uses fixed_addr for now.
+// Will use offset instead once we've implemented this function for real.
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size,
+ bool tolerate_enomem) {
+ if (tolerate_enomem) {
+ return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
+ }
+ return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size));
+}
+
+void ReservedAddressRange::Unmap(uptr addr, uptr size) {
+ void* addr_as_void = reinterpret_cast<void*>(addr);
+ uptr base_as_uptr = reinterpret_cast<uptr>(base_);
+ // Only unmap at the beginning or end of the range.
+ CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_));
+ CHECK_LE(size, size_);
+ UnmapOrDie(reinterpret_cast<void*>(addr), size);
+}
+
void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
int fd = name ? GetNamedMappingFd(name, size) : -1;
unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE;
return p;
}
+// Uses fixed_addr for now.
+// Will use offset instead once we've implemented this function for real.
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size,
+ bool tolerate_enomem) {
+ if (tolerate_enomem) {
+ return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
+ }
+ return reinterpret_cast<uptr>(MmapFixedOrDie(uptr fixed_addr, uptr size));
+}
+
+void ReservedAddressRange::Unmap(uptr addr, uptr size) {
+ void* addr_as_void = reinterpret_cast<void*>(addr);
+ uptr base_as_uptr = reinterpret_cast<uptr>(base_);
+ // Only unmap if it covers the entire range.
+ CHECK((addr_as_void == base_) && (size == size_));
+ UnmapOrDie(reinterpret_cast<void*>(addr), size);
+}
+
void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
void *p = VirtualAlloc((LPVOID)fixed_addr, size,
MEM_COMMIT, PAGE_READWRITE);
return MmapOrDie(size, mem_type);
}
+uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {
+ if (fixed_addr) {
+ base_ = MmapFixedNoAccess(fixed_addr, size, name);
+ } else {
+ base_ = MmapNoAccess(size);
+ }
+ size_ = size;
+ name_ = name;
+ return reinterpret_cast<uptr>(base_);
+}
+
+
void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
(void)name; // unsupported
void *res = VirtualAlloc((LPVOID)fixed_addr, size,
}
#endif
+TEST(SanitizerCommon, ReservedAddressRangeInit) {
+ uptr init_size = 0xffff;
+ ReservedAddressRange address_range;
+ uptr res = address_range.Init(init_size);
+ CHECK_NE(res, (void*)-1);
+ UnmapOrDie((void*)res, init_size);
+ // Should be able to map into the same space now.
+ ReservedAddressRange address_range2;
+ uptr res2 = address_range2.Init(init_size, nullptr, res);
+ CHECK_EQ(res, res2);
+
+ // TODO(flowerhack): Once this is switched to the "real" implementation
+ // (rather than passing through to MmapNoAccess*), enforce and test "no
+ // double initializations allowed"
+}
+
+TEST(SanitizerCommon, ReservedAddressRangeMap) {
+ constexpr uptr init_size = 0xffff;
+ ReservedAddressRange address_range;
+ uptr res = address_range.Init(init_size);
+ CHECK_NE(res, (void*) -1);
+
+ // Valid mappings should succeed.
+ CHECK_EQ(res, address_range.Map(res, init_size));
+
+ // Valid mappings should be readable.
+ unsigned char buffer[init_size];
+ memcpy(buffer, reinterpret_cast<void *>(res), init_size);
+
+ // Invalid mappings should fail.
+ EXPECT_DEATH(address_range.Map(res, 0), ".*");
+
+ // TODO(flowerhack): Once this is switched to the "real" implementation, make
+ // sure you can only mmap into offsets in the Init range.
+}
+
+TEST(SanitizerCommon, ReservedAddressRangeUnmap) {
+ uptr PageSize = GetPageSizeCached();
+ uptr init_size = PageSize * 4;
+ ReservedAddressRange address_range;
+ uptr base_addr = address_range.Init(init_size);
+ CHECK_NE(base_addr, (void*)-1);
+ CHECK_EQ(base_addr, address_range.Map(base_addr, init_size));
+
+ // Unmapping the entire range should succeed.
+ address_range.Unmap(base_addr, PageSize * 4);
+
+ // Remap that range in.
+ CHECK_EQ(base_addr, address_range.Map(base_addr, init_size));
+
+ // Windows doesn't allow partial unmappings.
+ #if !SANITIZER_WINDOWS
+
+ // Unmapping at the beginning should succeed.
+ address_range.Unmap(base_addr, PageSize);
+
+ // Unmapping at the end should succeed.
+ uptr new_start = reinterpret_cast<uptr>(address_range.base()) +
+ address_range.size() - PageSize;
+ address_range.Unmap(new_start, PageSize);
+
+ #endif
+
+ // Unmapping in the middle of the ReservedAddressRange should fail.
+ EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*");
+}
+
} // namespace __sanitizer