blob: b73ff57763ff2d718d49d72ac432033e13ddb0fb [file] [log] [blame]
// Copyright 2012 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/asan_rtl_impl.h"
#include <windows.h> // NOLINT
#include "base/rand_util.h"
#include "gtest/gtest.h"
#include "syzygy/agent/asan/asan_runtime.h"
#include "syzygy/agent/asan/shadow.h"
#include "syzygy/agent/asan/unittest_util.h"
#include "syzygy/core/unittest_util.h"
namespace {
class AsanRtlImplTest : public testing::TestWithAsanLogger {
public:
AsanRtlImplTest() : heap_(NULL) {
}
void SetUp() OVERRIDE {
testing::TestWithAsanLogger::SetUp();
asan_runtime_.SetUp(std::wstring());
agent::asan::SetUpRtl(&asan_runtime_);
heap_ = asan_HeapCreate(0, 0, 0);
ASSERT_TRUE(heap_ != NULL);
}
void TearDown() OVERRIDE {
if (heap_ != NULL) {
asan_HeapDestroy(heap_);
heap_ = NULL;
}
agent::asan::TearDownRtl();
asan_runtime_.TearDown();
testing::TestWithAsanLogger::TearDown();
}
protected:
agent::asan::AsanRuntime asan_runtime_;
// Arbitrary constant for all size limit.
static const size_t kMaxAllocSize = 134584;
// Scratch heap handle valid from SetUp to TearDown.
HANDLE heap_;
};
} // namespace
TEST_F(AsanRtlImplTest, CreateDestroy) {
HANDLE heap = asan_HeapCreate(0, 0, 0);
ASSERT_TRUE(heap != NULL);
ASSERT_TRUE(asan_HeapDestroy(heap));
}
TEST_F(AsanRtlImplTest, Alloc) {
for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
void* mem = asan_HeapAlloc(heap_, 0, size);
ASSERT_TRUE(mem != NULL);
::memset(mem, '\0', size);
size_t new_size = size;
while (new_size == size)
new_size = base::RandInt(size / 2, size * 2);
void* new_mem = asan_HeapReAlloc(heap_, 0, mem, new_size);
ASSERT_TRUE(new_mem != NULL);
ASSERT_NE(mem, new_mem);
ASSERT_TRUE(asan_HeapFree(heap_, 0, new_mem));
}
}
TEST_F(AsanRtlImplTest, Size) {
for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
void* mem = asan_HeapAlloc(heap_, 0, size);
ASSERT_TRUE(mem != NULL);
ASSERT_EQ(size, asan_HeapSize(heap_, 0, mem));
ASSERT_TRUE(asan_HeapFree(heap_, 0, mem));
}
}
TEST_F(AsanRtlImplTest, Validate) {
for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
void* mem = asan_HeapAlloc(heap_, 0, size);
ASSERT_TRUE(mem != NULL);
ASSERT_TRUE(asan_HeapValidate(heap_, 0, mem));
ASSERT_TRUE(asan_HeapFree(heap_, 0, mem));
}
}
TEST_F(AsanRtlImplTest, Compact) {
// Compact isn't supported by the current heap implementation and should
// always return 0.
ASSERT_EQ(0U, asan_HeapCompact(heap_, 0));
}
TEST_F(AsanRtlImplTest, LockUnlock) {
// We can't really test these, aside from not crashing.
ASSERT_TRUE(asan_HeapLock(heap_));
ASSERT_TRUE(asan_HeapUnlock(heap_));
}
TEST_F(AsanRtlImplTest, Walk) {
// Walk isn't supported by the current heap implementation.
PROCESS_HEAP_ENTRY entry = {};
ASSERT_FALSE(asan_HeapWalk(heap_, &entry));
}
TEST_F(AsanRtlImplTest, SetQueryInformation) {
ULONG compat_flag = -1;
unsigned long ret = 0;
// QueryInformation isn't supported by the current heap implementation and
// should always return false.
ASSERT_FALSE(
asan_HeapQueryInformation(heap_, HeapCompatibilityInformation,
&compat_flag, sizeof(compat_flag), &ret));
// Put the heap in LFH, which should always succeed, except when a debugger
// is attached. When a debugger is attached, the heap is wedged in certain
// debug settings.
if (base::debug::BeingDebugged()) {
LOG(WARNING) << "Can't test HeapProxy::SetInformation under debugger.";
return;
}
// SetInformation isn't supported by the current heap implementation and
// should always return true.
ASSERT_TRUE(
asan_HeapSetInformation(heap_, HeapCompatibilityInformation,
&compat_flag, sizeof(compat_flag)));
}
TEST_F(AsanRtlImplTest, SetInformationWithNullHeapPtr) {
// The documentation of HeapSetInformation specify that the heap handle is
// optional.
ASSERT_TRUE(
asan_HeapSetInformation(NULL, HeapEnableTerminationOnCorruption,
NULL, 0));
}