blob: e837ae1a920e1abdc8ce4a06fa5dc2893c1278e8 [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "syzygy/agent/asan/allocators.h"
#include <set>
#include <utility>
#include "base/basictypes.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "syzygy/agent/asan/unittest_util.h"
namespace agent {
namespace asan {
namespace {
class DummyMemoryNotifier : public MemoryNotifierInterface {
public:
typedef std::pair<const void*, size_t> MemoryRange;
typedef std::set<MemoryRange> MemoryRangeSet;
DummyMemoryNotifier()
: internal_used_(0), future_used_(0) {
}
virtual ~DummyMemoryNotifier() { }
virtual void NotifyInternalUse(const void* address, size_t size) {
MemoryRange range(address, size);
ASSERT_TRUE(internal_.find(range) == internal_.end());
ASSERT_TRUE(future_.find(range) == future_.end());
internal_used_ += size;
internal_.insert(range);
}
virtual void NotifyFutureHeapUse(const void* address, size_t size) {
MemoryRange range(address, size);
ASSERT_TRUE(internal_.find(range) == internal_.end());
ASSERT_TRUE(future_.find(range) == future_.end());
future_used_ += size;
future_.insert(range);
}
virtual void NotifyReturnedToOS(const void* address, size_t size) {
MemoryRange range(address, size);
size_t count_internal = internal_.erase(range);
size_t count_future = future_.erase(range);
ASSERT_EQ(1u, count_internal + count_future);
if (count_internal) {
internal_used_ -= size;
ASSERT_LE(0u, internal_used_);
}
if (count_future) {
future_used_ -= size;
ASSERT_LE(0u, future_used_);
}
}
size_t internal_used_;
size_t future_used_;
MemoryRangeSet internal_;
MemoryRangeSet future_;
};
typedef DummyMemoryNotifier::MemoryRange MemoryRange;
} // namespace
TEST(MemoryNotifierAllocatorTest, ConstructorsWorkAsExpected) {
DummyMemoryNotifier n;
MemoryNotifierAllocator<uint32> a1(&n);
EXPECT_EQ(&n, a1.memory_notifier());
MemoryNotifierAllocator<uint32> a2(a1);
EXPECT_EQ(&n, a2.memory_notifier());
MemoryNotifierAllocator<uint16> a3(a1);
EXPECT_EQ(&n, a3.memory_notifier());
}
TEST(MemoryNotifierAllocatorTest, NotifiesInternalUse) {
DummyMemoryNotifier n;
MemoryNotifierAllocator<uint32> a1(&n);
MemoryNotifierAllocator<uint16> a2(a1);
EXPECT_EQ(0u, n.internal_.size());
EXPECT_EQ(0u, n.future_.size());
uint32* ui32 = a1.allocate(10);
EXPECT_EQ(1u, n.internal_.size());
EXPECT_EQ(0u, n.future_.size());
EXPECT_THAT(n.internal_,
testing::UnorderedElementsAre(MemoryRange(ui32, 40)));
uint16* ui16 = a2.allocate(8);
EXPECT_EQ(2u, n.internal_.size());
EXPECT_EQ(0u, n.future_.size());
EXPECT_THAT(n.internal_,
testing::UnorderedElementsAre(MemoryRange(ui32, 40),
MemoryRange(ui16, 16)));
a1.deallocate(ui32, 10);
EXPECT_EQ(1u, n.internal_.size());
EXPECT_EQ(0u, n.future_.size());
EXPECT_THAT(n.internal_,
testing::UnorderedElementsAre(MemoryRange(ui16, 16)));
a2.deallocate(ui16, 8);
EXPECT_EQ(0u, n.internal_.size());
EXPECT_EQ(0u, n.future_.size());
}
TEST(MemoryNotifierAllocatorTest, StlContainerStressTest) {
DummyMemoryNotifier n;
typedef std::set<uint32,
std::less<uint32>,
MemoryNotifierAllocator<uint32>> DummySet;
MemoryNotifierAllocator<uint32> a(&n);
DummySet s(a);
for (size_t i = 0; i < 10000; ++i) {
uint32 j = ::rand() % 2000;
s.insert(j);
}
for (size_t i = 0; i < 1500; ++i) {
uint32 j = ::rand() % 2000;
s.erase(j);
}
s.clear();
}
TEST(HeapAllocatorTest, Allocate) {
testing::MockHeap h;
HeapAllocator<uint32> a(&h);
EXPECT_CALL(h, Allocate(sizeof(uint32)));
a.allocate(1, NULL);
}
TEST(HeapAllocatorTest, Deallocate) {
testing::MockHeap h;
HeapAllocator<uint32> a(&h);
EXPECT_CALL(h, Free(reinterpret_cast<void*>(0x12345678)));
a.deallocate(reinterpret_cast<uint32*>(0x12345678), 1);
}
TEST(HeapAllocatorTest, StlContainerStressTest) {
testing::DummyHeap h;
typedef std::set<uint32,
std::less<uint32>,
HeapAllocator<uint32>> DummySet;
HeapAllocator<uint32> a(&h);
DummySet s(a);
for (size_t i = 0; i < 10000; ++i) {
uint32 j = ::rand() % 2000;
s.insert(j);
}
for (size_t i = 0; i < 1500; ++i) {
uint32 j = ::rand() % 2000;
s.erase(j);
}
s.clear();
}
} // namespace asan
} // namespace agent