summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2016-09-20 22:17:59 +0000
committerKostya Kortchinsky <kostyak@google.com>2016-09-20 22:17:59 +0000
commit1da3ea561ac631c158ab759954d3b5810cb0af91 (patch)
tree03dfb2cf76dcb8f3b3c7a84b1befb7909fe11e14
parent4c5506a64dd57c787147e7c449b740ffd894c4cc (diff)
downloadbcm5719-llvm-1da3ea561ac631c158ab759954d3b5810cb0af91.tar.gz
bcm5719-llvm-1da3ea561ac631c158ab759954d3b5810cb0af91.zip
[scudo] Fix a bug in the new Secondary Allocator
Summary: GetActuallyAllocatedSize() was not accounting for the last page of the mapping being a guard page, and was returning the wrong number of actually allocated bytes, which in turn would mess up with the realloc logic. Current tests didn't find this as the size exercised was only serviced by the Primary. Correct the issue by subtracting PageSize, and update the realloc test to exercise paths in both the Primary and the Secondary. Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D24787 llvm-svn: 282030
-rw-r--r--compiler-rt/lib/scudo/scudo_allocator_secondary.h5
-rw-r--r--compiler-rt/test/scudo/realloc.cpp89
2 files changed, 50 insertions, 44 deletions
diff --git a/compiler-rt/lib/scudo/scudo_allocator_secondary.h b/compiler-rt/lib/scudo/scudo_allocator_secondary.h
index 450d212d5a0..a961a868d38 100644
--- a/compiler-rt/lib/scudo/scudo_allocator_secondary.h
+++ b/compiler-rt/lib/scudo/scudo_allocator_secondary.h
@@ -42,7 +42,7 @@ class ScudoLargeMmapAllocator {
uptr Ptr = MapBeg + sizeof(SecondaryHeader);
// TODO(kostyak): add a random offset to Ptr.
CHECK_GT(Ptr + Size, MapBeg);
- CHECK_LE(Ptr + Size, MapEnd);
+ CHECK_LT(Ptr + Size, MapEnd);
SecondaryHeader *Header = getHeader(Ptr);
Header->MapBeg = MapBeg - PageSize;
Header->MapSize = MapSize + 2 * PageSize;
@@ -78,7 +78,8 @@ class ScudoLargeMmapAllocator {
uptr GetActuallyAllocatedSize(void *Ptr) {
SecondaryHeader *Header = getHeader(Ptr);
- uptr MapEnd = Header->MapBeg + Header->MapSize;
+ // Deduct PageSize as MapEnd includes the trailing guard page.
+ uptr MapEnd = Header->MapBeg + Header->MapSize - PageSize;
return MapEnd - reinterpret_cast<uptr>(Ptr);
}
diff --git a/compiler-rt/test/scudo/realloc.cpp b/compiler-rt/test/scudo/realloc.cpp
index 2a7d5b69f5f..34734702ea8 100644
--- a/compiler-rt/test/scudo/realloc.cpp
+++ b/compiler-rt/test/scudo/realloc.cpp
@@ -14,54 +14,59 @@
#include <malloc.h>
#include <string.h>
+#include <vector>
+
int main(int argc, char **argv)
{
void *p, *old_p;
- size_t size = 32;
+ // Those sizes will exercise both allocators (Primary & Secondary).
+ std::vector<size_t> sizes{1 << 5, 1 << 17};
assert(argc == 2);
- if (!strcmp(argv[1], "pointers")) {
- old_p = p = realloc(nullptr, size);
- if (!p)
- return 1;
- size = malloc_usable_size(p);
- // Our realloc implementation will return the same pointer if the size
- // requested is lower or equal to the usable size of the associated chunk.
- p = realloc(p, size - 1);
- if (p != old_p)
- return 1;
- p = realloc(p, size);
- if (p != old_p)
- return 1;
- // And a new one if the size is greater.
- p = realloc(p, size + 1);
- if (p == old_p)
- return 1;
- // A size of 0 will free the chunk and return nullptr.
- p = realloc(p, 0);
- if (p)
- return 1;
- old_p = nullptr;
- }
- if (!strcmp(argv[1], "contents")) {
- p = realloc(nullptr, size);
- if (!p)
- return 1;
- for (int i = 0; i < size; i++)
- reinterpret_cast<char *>(p)[i] = 'A';
- p = realloc(p, size + 1);
- // The contents of the reallocated chunk must match the original one.
- for (int i = 0; i < size; i++)
- if (reinterpret_cast<char *>(p)[i] != 'A')
+ for (size_t size : sizes) {
+ if (!strcmp(argv[1], "pointers")) {
+ old_p = p = realloc(nullptr, size);
+ if (!p)
return 1;
- }
- if (!strcmp(argv[1], "memalign")) {
- // A chunk coming from memalign cannot be reallocated.
- p = memalign(16, size);
- if (!p)
- return 1;
- p = realloc(p, size);
- free(p);
+ size = malloc_usable_size(p);
+ // Our realloc implementation will return the same pointer if the size
+ // requested is lower or equal to the usable size of the associated chunk.
+ p = realloc(p, size - 1);
+ if (p != old_p)
+ return 1;
+ p = realloc(p, size);
+ if (p != old_p)
+ return 1;
+ // And a new one if the size is greater.
+ p = realloc(p, size + 1);
+ if (p == old_p)
+ return 1;
+ // A size of 0 will free the chunk and return nullptr.
+ p = realloc(p, 0);
+ if (p)
+ return 1;
+ old_p = nullptr;
+ }
+ if (!strcmp(argv[1], "contents")) {
+ p = realloc(nullptr, size);
+ if (!p)
+ return 1;
+ for (int i = 0; i < size; i++)
+ reinterpret_cast<char *>(p)[i] = 'A';
+ p = realloc(p, size + 1);
+ // The contents of the reallocated chunk must match the original one.
+ for (int i = 0; i < size; i++)
+ if (reinterpret_cast<char *>(p)[i] != 'A')
+ return 1;
+ }
+ if (!strcmp(argv[1], "memalign")) {
+ // A chunk coming from memalign cannot be reallocated.
+ p = memalign(16, size);
+ if (!p)
+ return 1;
+ p = realloc(p, size);
+ free(p);
+ }
}
return 0;
}
OpenPOWER on IntegriCloud