blob: d0960d0253058201c3a94966e03355ce707575fd [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/windows_heap_adapter.h"
#include "base/compiler_specific.h"
#include "base/rand_util.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "syzygy/agent/asan/heap_manager.h"
namespace agent {
namespace asan {
namespace {
using testing::Return;
using testing::_;
// A mock heap manager to make sure that the calls to the Windows heap adapter
// are correctly forwarded.
class LenientMockHeapManager : public HeapManagerInterface {
public:
MOCK_METHOD0(CreateHeap, HeapId());
MOCK_METHOD1(DestroyHeap, bool(HeapId));
MOCK_METHOD2(Size, size_t(HeapId, const void*));
MOCK_METHOD2(Allocate, void*(HeapId, size_t));
MOCK_METHOD2(Free, bool(HeapId, void*));
MOCK_METHOD1(Lock, void(HeapId));
MOCK_METHOD1(Unlock, void(HeapId));
};
typedef testing::StrictMock<LenientMockHeapManager> MockHeapManager;
class WindowsHeapAdapterTest : public testing::Test {
public:
WindowsHeapAdapterTest() { }
virtual void SetUp() OVERRIDE {
WindowsHeapAdapter::SetUp(&mock_heap_manager_);
}
virtual void TearDown() OVERRIDE {
WindowsHeapAdapter::TearDown();
}
protected:
const HeapManagerInterface::HeapId kFakeHeapId =
static_cast<HeapManagerInterface::HeapId>(0XAABBCCDD);
// The mock heap manager we delegate to.
MockHeapManager mock_heap_manager_;
};
} // namespace
TEST_F(WindowsHeapAdapterTest, HeapCreate) {
EXPECT_CALL(mock_heap_manager_, CreateHeap()).WillOnce(Return(kFakeHeapId));
EXPECT_EQ(reinterpret_cast<HANDLE>(kFakeHeapId),
WindowsHeapAdapter::HeapCreate(0, 0, 0));
}
TEST_F(WindowsHeapAdapterTest, HeapDestroy) {
EXPECT_CALL(mock_heap_manager_,
DestroyHeap(kFakeHeapId)).WillOnce(Return(true));
EXPECT_TRUE(
WindowsHeapAdapter::HeapDestroy(reinterpret_cast<HANDLE>(kFakeHeapId)));
}
TEST_F(WindowsHeapAdapterTest, HeapAlloc) {
const size_t kAllocSize = 100;
void* kFakeAlloc = reinterpret_cast<void*>(0x12345678);
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kAllocSize)).WillOnce(
Return(kFakeAlloc));
void* alloc =
WindowsHeapAdapter::HeapAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
kAllocSize);
ASSERT_EQ(kFakeAlloc, alloc);
}
TEST_F(WindowsHeapAdapterTest, HeapAllocWithZeroMemoryFlag) {
const size_t kAllocSize = 10;
uint8 kDummyBuffer[kAllocSize];
// Fill the array with a non-zero value.
::memset(kDummyBuffer, 0xFF, kAllocSize);
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kAllocSize)).WillOnce(
Return(reinterpret_cast<void*>(kDummyBuffer)));
void* alloc =
WindowsHeapAdapter::HeapAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
HEAP_ZERO_MEMORY,
kAllocSize);
EXPECT_EQ(reinterpret_cast<void*>(kDummyBuffer), alloc);
for (size_t i = 0; i < kAllocSize; ++i)
EXPECT_EQ(0, kDummyBuffer[i]);
}
TEST_F(WindowsHeapAdapterTest, HeapReAlloc) {
void* kFakeAlloc = reinterpret_cast<void*>(0x12345678);
void* kFakeReAlloc = reinterpret_cast<void*>(0x87654321);
// A successful call to WindowsHeapAdapter::HeapReAlloc should end up calling
// HeapManagerInterface::Allocate, HeapManagerInterface::Size and
// HeapManagerInterface::Free.
const size_t kReAllocSize = 200;
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kReAllocSize)).WillOnce(
Return(kFakeReAlloc));
EXPECT_CALL(mock_heap_manager_, Free(kFakeHeapId, kFakeAlloc)).WillOnce(
Return(true));
// Return a size of 0 to avoid trying to copy the old buffer into the new one.
EXPECT_CALL(mock_heap_manager_, Size(kFakeHeapId, kFakeAlloc)).WillOnce(
Return(0));
EXPECT_EQ(kFakeReAlloc,
WindowsHeapAdapter::HeapReAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
kFakeAlloc,
kReAllocSize));
}
TEST_F(WindowsHeapAdapterTest, HeapReAllocWithNullSrcPointer) {
const size_t kReAllocSize = 10;
void* kFakeReAlloc = reinterpret_cast<void*>(0x87654321);
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kReAllocSize)).WillOnce(
Return(kFakeReAlloc));
EXPECT_EQ(kFakeReAlloc,
WindowsHeapAdapter::HeapReAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
NULL,
kReAllocSize));
}
TEST_F(WindowsHeapAdapterTest, HeapReAllocFailForInPlaceReallocations) {
const size_t kReAllocSize = 10;
EXPECT_CALL(mock_heap_manager_, Allocate(_, _)).Times(0);
EXPECT_EQ(NULL,
WindowsHeapAdapter::HeapReAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
HEAP_REALLOC_IN_PLACE_ONLY,
NULL,
kReAllocSize));
}
TEST_F(WindowsHeapAdapterTest, HeapReAllocFailOnOOM) {
const size_t kReAllocSize = 10;
// Return NULL in the internal call that allocates the new buffer.
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kReAllocSize)).WillOnce(
Return(static_cast<void*>(NULL)));
EXPECT_EQ(NULL,
WindowsHeapAdapter::HeapReAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
NULL,
kReAllocSize));
}
TEST_F(WindowsHeapAdapterTest, HeapReallocCopyData) {
const size_t kAllocSize = 10;
const size_t kReAllocSize = kAllocSize * 2;
uint8 kDummyBuffer1[kAllocSize];
uint8 kDummyBuffer2[kReAllocSize];
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kAllocSize)).WillOnce(
Return(reinterpret_cast<void*>(kDummyBuffer1)));
void* alloc =
WindowsHeapAdapter::HeapAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
kAllocSize);
EXPECT_EQ(reinterpret_cast<void*>(kDummyBuffer1), alloc);
base::RandBytes(alloc, kAllocSize);
EXPECT_CALL(mock_heap_manager_, Allocate(kFakeHeapId, kReAllocSize)).WillOnce(
Return(reinterpret_cast<void*>(kDummyBuffer2)));
EXPECT_CALL(mock_heap_manager_, Free(kFakeHeapId, alloc)).WillOnce(
Return(true));
EXPECT_CALL(mock_heap_manager_, Size(kFakeHeapId, alloc)).WillOnce(
Return(kAllocSize));
void* re_alloc =
WindowsHeapAdapter::HeapReAlloc(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
alloc,
kReAllocSize);
EXPECT_EQ(0, ::memcmp(alloc, re_alloc, kAllocSize));
}
TEST_F(WindowsHeapAdapterTest, HeapFree) {
void* kFakeAlloc = reinterpret_cast<void*>(0x12345678);
EXPECT_CALL(mock_heap_manager_, Free(kFakeHeapId, kFakeAlloc)).WillOnce(
Return(true));
ASSERT_TRUE(
WindowsHeapAdapter::HeapFree(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
kFakeAlloc));
}
TEST_F(WindowsHeapAdapterTest, HeapSize) {
const size_t kAllocSize = 100;
const void* kFakeAlloc = reinterpret_cast<const void*>(0x12345678);
EXPECT_CALL(mock_heap_manager_, Size(kFakeHeapId, kFakeAlloc)).WillOnce(
Return(kAllocSize));
EXPECT_EQ(kAllocSize,
WindowsHeapAdapter::HeapSize(reinterpret_cast<HANDLE>(kFakeHeapId),
0,
kFakeAlloc));
}
TEST_F(WindowsHeapAdapterTest, HeapLock) {
EXPECT_CALL(mock_heap_manager_, Lock(kFakeHeapId)).Times(1);
WindowsHeapAdapter::HeapLock(reinterpret_cast<HANDLE>(kFakeHeapId));
}
TEST_F(WindowsHeapAdapterTest, HeapUnlock) {
EXPECT_CALL(mock_heap_manager_, Unlock(kFakeHeapId)).Times(1);
WindowsHeapAdapter::HeapUnlock(reinterpret_cast<HANDLE>(kFakeHeapId));
}
} // namespace asan
} // namespace agent