blob: cf47fa345660362fa72accd20a022e0ab8ead979 [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.
//
// Implementations of the Asan heap interceptors. These functions are
// instrumented and log detailed function call information to the call-trace
// service.
#include <windows.h>
#include "base/hash.h"
#include "base/synchronization/lock.h"
#include "syzygy/agent/memprof/memprof.h"
// A wrapper to EMIT_DETAILED_FUNCTION_CALL that provides the MemoryProfiler
// FunctionCallLogger instance.
#define EMIT_DETAILED_HEAP_FUNCTION_CALL(...) \
DCHECK_NE(static_cast<agent::memprof::MemoryProfiler*>(nullptr), \
agent::memprof::memory_profiler.get()); \
EMIT_DETAILED_FUNCTION_CALL( \
&agent::memprof::memory_profiler->function_call_logger(), \
agent::memprof::memory_profiler->GetOrAllocateThreadState()-> \
segment(), \
__VA_ARGS__);
// A conditional scoped lock, based on timestamp serialization. Used to
// completely serialize heap access when enabled.
struct ConditionalScopedLock {
public:
ConditionalScopedLock() : locked_(
agent::memprof::memory_profiler->parameters().serialize_timestamps) {
if (locked_)
conditional_lock_.Acquire();
}
~ConditionalScopedLock() {
if (locked_)
conditional_lock_.Release();
}
private:
static base::Lock conditional_lock_;
bool locked_;
};
base::Lock ConditionalScopedLock::conditional_lock_;
extern "C" {
HANDLE WINAPI asan_GetProcessHeap() {
// This function doesn't need to be logged, but does need to be implemented
// for compatibility with old ASAN implementations.
return ::GetProcessHeap();
}
HANDLE WINAPI asan_HeapCreate(DWORD options,
SIZE_T initial_size,
SIZE_T maximum_size) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
HANDLE ret = ::HeapCreate(options, initial_size, maximum_size);
EMIT_DETAILED_HEAP_FUNCTION_CALL(options, initial_size, maximum_size, ret);
return ret;
}
BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapDestroy(heap);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
return ret;
}
LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
DWORD flags,
SIZE_T bytes) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
LPVOID ret = ::HeapAlloc(heap, flags, bytes);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, bytes, ret);
return ret;
}
LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
DWORD flags,
LPVOID mem,
SIZE_T bytes) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
LPVOID ret = ::HeapReAlloc(heap, flags, mem, bytes);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, bytes, ret);
return ret;
}
BOOL WINAPI asan_HeapFree(HANDLE heap,
DWORD flags,
LPVOID mem) {
// Calculate a hash value of the contents if necessary.
uint32_t hash = 0;
if (mem != nullptr &&
agent::memprof::memory_profiler->parameters().hash_contents_at_free) {
size_t size = ::HeapSize(heap, 0, mem);
hash = base::SuperFastHash(reinterpret_cast<const char*>(mem), size);
}
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapFree(heap, flags, mem);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret, hash);
return ret;
}
SIZE_T WINAPI asan_HeapSize(HANDLE heap,
DWORD flags,
LPCVOID mem) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
SIZE_T ret = ::HeapSize(heap, flags, mem);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret);
return ret;
}
BOOL WINAPI asan_HeapValidate(HANDLE heap,
DWORD flags,
LPCVOID mem) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapValidate(heap, flags, mem);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret);
return ret;
}
SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
DWORD flags) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
SIZE_T ret = ::HeapCompact(heap, flags);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, ret);
return ret;
}
BOOL WINAPI asan_HeapLock(HANDLE heap) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapLock(heap);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
return ret;
}
BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapUnlock(heap);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
return ret;
}
BOOL WINAPI asan_HeapWalk(HANDLE heap,
LPPROCESS_HEAP_ENTRY entry) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapWalk(heap, entry);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, entry, ret);
return ret;
}
BOOL WINAPI asan_HeapSetInformation(
HANDLE heap, HEAP_INFORMATION_CLASS info_class,
PVOID info, SIZE_T info_length) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapSetInformation(heap, info_class, info, info_length);
EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, info_class, info, info_length, ret);
return ret;
}
BOOL WINAPI asan_HeapQueryInformation(
HANDLE heap, HEAP_INFORMATION_CLASS info_class,
PVOID info, SIZE_T info_length, PSIZE_T return_length) {
// This ensures that all heap access is synchronous if 'serialize_timestamps'
// is enabled.
ConditionalScopedLock conditional_scoped_lock;
BOOL ret = ::HeapQueryInformation(
heap, info_class, info, info_length, return_length);
EMIT_DETAILED_HEAP_FUNCTION_CALL(
heap, info_class, info, info_length, return_length, ret);
return ret;
}
} // extern "C"