skia2/tests/ArenaAllocTest.cpp
Herb Derby 0bc4d60fe0 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>
2017-08-15 20:40:27 +00:00

193 lines
5.3 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Test.h"
#include "SkArenaAlloc.h"
#include "SkRefCnt.h"
namespace {
static int created, destroyed;
struct Foo {
Foo() : x(-2), y(-3.0f) { created++; }
Foo(int X, float Y) : x(X), y(Y) { created++; }
~Foo() { destroyed++; }
int x;
float y;
};
struct Big {
Big() {}
uint32_t array[128];
};
struct Node {
Node(Node* n) : next(n) { created++; }
~Node() {
destroyed++;
if (next) {
next->~Node();
}
}
Node *next;
};
struct Start {
~Start() {
if (start) {
start->~Node();
}
}
Node* start;
};
struct FooRefCnt : public SkRefCnt {
FooRefCnt() : x(-2), y(-3.0f) { created++; }
FooRefCnt(int X, float Y) : x(X), y(Y) { created++; }
~FooRefCnt() { destroyed++; }
int x;
float y;
};
}
struct WithDtor {
~WithDtor() { }
};
DEF_TEST(ArenaAlloc, r) {
{
created = 0;
destroyed = 0;
SkArenaAlloc arena{0};
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
Foo* foo = arena.make<Foo>(3, 4.0f);
REPORTER_ASSERT(r, foo->x == 3);
REPORTER_ASSERT(r, foo->y == 4.0f);
REPORTER_ASSERT(r, created == 1);
REPORTER_ASSERT(r, destroyed == 0);
arena.makeArrayDefault<int>(10);
int* zeroed = arena.makeArray<int>(10);
for (int i = 0; i < 10; i++) {
REPORTER_ASSERT(r, zeroed[i] == 0);
}
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
REPORTER_ASSERT(r, fooArray[3].x == -2);
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 0);
arena.make<typename std::aligned_storage<10,8>::type>();
}
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 11);
{
created = 0;
destroyed = 0;
SkSTArenaAlloc<64> arena;
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
Foo* foo = arena.make<Foo>(3, 4.0f);
REPORTER_ASSERT(r, foo->x == 3);
REPORTER_ASSERT(r, foo->y == 4.0f);
REPORTER_ASSERT(r, created == 1);
REPORTER_ASSERT(r, destroyed == 0);
arena.makeArrayDefault<int>(10);
int* zeroed = arena.makeArray<int>(10);
for (int i = 0; i < 10; i++) {
REPORTER_ASSERT(r, zeroed[i] == 0);
}
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
REPORTER_ASSERT(r, fooArray[3].x == -2);
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 0);
arena.make<typename std::aligned_storage<10,8>::type>();
}
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 11);
{
created = 0;
destroyed = 0;
std::unique_ptr<char[]> block{new char[1024]};
SkArenaAlloc arena{block.get(), 1024, 0};
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
Foo* foo = arena.make<Foo>(3, 4.0f);
REPORTER_ASSERT(r, foo->x == 3);
REPORTER_ASSERT(r, foo->y == 4.0f);
REPORTER_ASSERT(r, created == 1);
REPORTER_ASSERT(r, destroyed == 0);
arena.makeArrayDefault<int>(10);
int* zeroed = arena.makeArray<int>(10);
for (int i = 0; i < 10; i++) {
REPORTER_ASSERT(r, zeroed[i] == 0);
}
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
REPORTER_ASSERT(r, fooArray[3].x == -2);
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 0);
arena.make<typename std::aligned_storage<10,8>::type>();
}
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 11);
{
SkSTArenaAlloc<64> arena;
arena.makeArrayDefault<char>(256);
arena.reset();
arena.reset();
}
{
created = 0;
destroyed = 0;
SkSTArenaAlloc<64> arena;
Start start;
Node* current = nullptr;
for (int i = 0; i < 128; i++) {
uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*));
current = new (temp)Node(current);
}
start.start = current;
}
REPORTER_ASSERT(r, created == 128);
REPORTER_ASSERT(r, destroyed == 128);
{
created = 0;
destroyed = 0;
SkSTArenaAlloc<64> arena;
sk_sp<FooRefCnt> f = arena.makeSkSp<FooRefCnt>(4, 5.0f);
REPORTER_ASSERT(r, f->x == 4);
REPORTER_ASSERT(r, f->y == 5.0f);
REPORTER_ASSERT(r, created == 1);
REPORTER_ASSERT(r, destroyed == 0);
}
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;
}