[sanitizer] fix an allocator bug where the allocated memory may overlap with the free array (kudos to Kostya Korcthinsky). Also make sure that the allocator does not mmap more than requested. Test both.

llvm-svn: 281103
This commit is contained in:
Kostya Serebryany 2016-09-09 21:42:33 +00:00
parent b1153848ff
commit 58560a05ad
2 changed files with 22 additions and 4 deletions

View File

@ -401,12 +401,12 @@ class SizeClassAllocator64 {
uptr beg_idx = region->allocated_user;
uptr end_idx = beg_idx + requested_count * size;
uptr region_beg = GetRegionBeginBySizeClass(class_id);
if (end_idx + size > region->mapped_user) {
if (end_idx > region->mapped_user) {
if (!kUsingConstantSpaceBeg && region->mapped_user == 0)
region->rand_state = static_cast<u32>(region_beg >> 12); // From ASLR.
// Do the mmap for the user memory.
uptr map_size = kUserMapSize;
while (end_idx + size > region->mapped_user + map_size)
while (end_idx > region->mapped_user + map_size)
map_size += kUserMapSize;
CHECK_GE(region->mapped_user + map_size, end_idx);
MapWithCallback(region_beg + region->mapped_user, map_size);
@ -441,7 +441,8 @@ class SizeClassAllocator64 {
region->mapped_meta += map_size;
}
CHECK_LE(region->allocated_meta, region->mapped_meta);
if (region->mapped_user + region->mapped_meta > kRegionSize) {
if (region->mapped_user + region->mapped_meta >
kRegionSize - kFreeArraySize) {
Printf("%s: Out of memory. Dying. ", SanitizerToolName);
Printf("The process has exhausted %zuMB for size class %zu.\n",
kRegionSize / 1024 / 1024, size);

View File

@ -931,16 +931,33 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
// ...one man is on a mission to overflow a region with a series of
// successive allocations.
const uptr kClassID = 107;
const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID);
const uptr kAllocationSize = SpecialSizeClassMap::Size(kClassID);
ASSERT_LT(2 * kAllocationSize, kRegionSize);
ASSERT_GT(3 * kAllocationSize, kRegionSize);
cache.Allocate(a, kClassID);
EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID),
"The process has exhausted");
const uptr Class2 = 100;
const uptr Size2 = SpecialSizeClassMap::Size(Class2);
ASSERT_EQ(Size2 * 8, kRegionSize);
char *p[7];
for (int i = 0; i < 7; i++) {
p[i] = (char*)cache.Allocate(a, Class2);
fprintf(stderr, "p[%d] %p s = %lx\n", i, (void*)p[i], Size2);
p[i][Size2 - 1] = 42;
if (i) ASSERT_LT(p[i - 1], p[i]);
}
EXPECT_DEATH(cache.Allocate(a, Class2), "The process has exhausted");
cache.Deallocate(a, Class2, p[0]);
cache.Drain(a);
ASSERT_EQ(p[6][Size2 - 1], 42);
a->TestOnlyUnmap();
delete a;
}
#endif
TEST(SanitizerCommon, TwoLevelByteMap) {