Fix bogus math in object allocation.
When a size_t is convert from a very large number to ptrdiff_t, it
becomes negative causing the existing block to be used instead of
allocating a new block.
BUG=chromium:744109
Change-Id: I0bf98e3fb924851c162f6eca43d29a3f40dc9eaa
Reviewed-on: https://skia-review.googlesource.com/34541
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkArenaAlloc.h b/src/core/SkArenaAlloc.h
index 414e8c1..9e97161 100644
--- a/src/core/SkArenaAlloc.h
+++ b/src/core/SkArenaAlloc.h
@@ -156,12 +156,16 @@
char* allocObject(uint32_t size, uint32_t alignment) {
uintptr_t mask = alignment - 1;
- char* objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask);
- if ((ptrdiff_t)size > fEnd - objStart) {
- this->ensureSpace(size, alignment);
- objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask);
+ uintptr_t alignedOffset = (~reinterpret_cast<uintptr_t>(fCursor) + 1) & mask;
+ uintptr_t totalSize = size + alignedOffset;
+ if (totalSize < size) {
+ SK_ABORT("The total size of allocation overflowed uintptr_t.");
}
- return objStart;
+ if (totalSize > static_cast<uintptr_t>(fEnd - fCursor)) {
+ this->ensureSpace(size, alignment);
+ alignedOffset = (~reinterpret_cast<uintptr_t>(fCursor) + 1) & mask;
+ }
+ return fCursor + alignedOffset;
}
char* allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment);
diff --git a/tests/ArenaAllocTest.cpp b/tests/ArenaAllocTest.cpp
index 137e60e..b565095 100644
--- a/tests/ArenaAllocTest.cpp
+++ b/tests/ArenaAllocTest.cpp
@@ -181,3 +181,12 @@
REPORTER_ASSERT(r, created == 1);
REPORTER_ASSERT(r, destroyed == 1);
}
+
+// Chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=744109
+// Must be compiled with target_cpu = "x86" to fail with segfault.
+DEF_TEST(ArenaAllocReallyBigAlloc, r) {
+ SkSTArenaAlloc<64> arena;
+ using T = struct {int f[1<<28];};
+ auto a = arena.makeArrayDefault<T>(3);
+ a[2].f[(1<<28) - 1] = 0;
+}