1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // Implementations of the Asan heap interceptors. These functions are
16 : // instrumented and log detailed function call information to the call-trace
17 : // service.
18 :
19 : #include <windows.h>
20 :
21 : #include "base/hash.h"
22 : #include "base/synchronization/lock.h"
23 : #include "syzygy/agent/memprof/memprof.h"
24 :
25 : // A wrapper to EMIT_DETAILED_FUNCTION_CALL that provides the MemoryProfiler
26 : // FunctionCallLogger instance.
27 : #define EMIT_DETAILED_HEAP_FUNCTION_CALL(...) \
28 m : DCHECK_NE(static_cast<agent::memprof::MemoryProfiler*>(nullptr), \
29 m : agent::memprof::memory_profiler.get()); \
30 m : EMIT_DETAILED_FUNCTION_CALL( \
31 m : &agent::memprof::memory_profiler->function_call_logger(), \
32 m : agent::memprof::memory_profiler->GetOrAllocateThreadState()-> \
33 m : segment(), \
34 m : __VA_ARGS__);
35 :
36 : // A conditional scoped lock, based on timestamp serialization. Used to
37 : // completely serialize heap access when enabled.
38 m : struct ConditionalScopedLock {
39 m : public:
40 m : ConditionalScopedLock() : locked_(
41 m : agent::memprof::memory_profiler->parameters().serialize_timestamps) {
42 m : if (locked_)
43 m : conditional_lock_.Acquire();
44 m : }
45 :
46 m : ~ConditionalScopedLock() {
47 m : if (locked_)
48 m : conditional_lock_.Release();
49 m : }
50 :
51 m : private:
52 m : static base::Lock conditional_lock_;
53 m : bool locked_;
54 m : };
55 m : base::Lock ConditionalScopedLock::conditional_lock_;
56 :
57 m : extern "C" {
58 :
59 m : HANDLE WINAPI asan_GetProcessHeap() {
60 : // This function doesn't need to be logged, but does need to be implemented
61 : // for compatibility with old ASAN implementations.
62 m : return ::GetProcessHeap();
63 m : }
64 :
65 m : HANDLE WINAPI asan_HeapCreate(DWORD options,
66 m : SIZE_T initial_size,
67 m : SIZE_T maximum_size) {
68 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
69 : // is enabled.
70 m : ConditionalScopedLock conditional_scoped_lock;
71 m : HANDLE ret = ::HeapCreate(options, initial_size, maximum_size);
72 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(options, initial_size, maximum_size, ret);
73 m : return ret;
74 m : }
75 :
76 m : BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
77 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
78 : // is enabled.
79 m : ConditionalScopedLock conditional_scoped_lock;
80 m : BOOL ret = ::HeapDestroy(heap);
81 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
82 m : return ret;
83 m : }
84 :
85 m : LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
86 m : DWORD flags,
87 m : SIZE_T bytes) {
88 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
89 : // is enabled.
90 m : ConditionalScopedLock conditional_scoped_lock;
91 m : LPVOID ret = ::HeapAlloc(heap, flags, bytes);
92 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, bytes, ret);
93 m : return ret;
94 m : }
95 :
96 m : LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
97 m : DWORD flags,
98 m : LPVOID mem,
99 m : SIZE_T bytes) {
100 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
101 : // is enabled.
102 m : ConditionalScopedLock conditional_scoped_lock;
103 m : LPVOID ret = ::HeapReAlloc(heap, flags, mem, bytes);
104 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, bytes, ret);
105 m : return ret;
106 m : }
107 :
108 m : BOOL WINAPI asan_HeapFree(HANDLE heap,
109 m : DWORD flags,
110 m : LPVOID mem) {
111 : // Calculate a hash value of the contents if necessary.
112 m : uint32_t hash = 0;
113 m : if (mem != nullptr &&
114 m : agent::memprof::memory_profiler->parameters().hash_contents_at_free) {
115 m : size_t size = ::HeapSize(heap, 0, mem);
116 m : hash = base::SuperFastHash(reinterpret_cast<const char*>(mem), size);
117 m : }
118 :
119 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
120 : // is enabled.
121 m : ConditionalScopedLock conditional_scoped_lock;
122 m : BOOL ret = ::HeapFree(heap, flags, mem);
123 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret, hash);
124 m : return ret;
125 m : }
126 :
127 m : SIZE_T WINAPI asan_HeapSize(HANDLE heap,
128 m : DWORD flags,
129 m : LPCVOID mem) {
130 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
131 : // is enabled.
132 m : ConditionalScopedLock conditional_scoped_lock;
133 m : SIZE_T ret = ::HeapSize(heap, flags, mem);
134 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret);
135 m : return ret;
136 m : }
137 :
138 m : BOOL WINAPI asan_HeapValidate(HANDLE heap,
139 m : DWORD flags,
140 m : LPCVOID mem) {
141 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
142 : // is enabled.
143 m : ConditionalScopedLock conditional_scoped_lock;
144 m : BOOL ret = ::HeapValidate(heap, flags, mem);
145 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, mem, ret);
146 m : return ret;
147 m : }
148 :
149 m : SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
150 m : DWORD flags) {
151 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
152 : // is enabled.
153 m : ConditionalScopedLock conditional_scoped_lock;
154 m : SIZE_T ret = ::HeapCompact(heap, flags);
155 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, flags, ret);
156 m : return ret;
157 m : }
158 :
159 m : BOOL WINAPI asan_HeapLock(HANDLE heap) {
160 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
161 : // is enabled.
162 m : ConditionalScopedLock conditional_scoped_lock;
163 m : BOOL ret = ::HeapLock(heap);
164 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
165 m : return ret;
166 m : }
167 :
168 m : BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
169 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
170 : // is enabled.
171 m : ConditionalScopedLock conditional_scoped_lock;
172 m : BOOL ret = ::HeapUnlock(heap);
173 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, ret);
174 m : return ret;
175 m : }
176 :
177 m : BOOL WINAPI asan_HeapWalk(HANDLE heap,
178 m : LPPROCESS_HEAP_ENTRY entry) {
179 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
180 : // is enabled.
181 m : ConditionalScopedLock conditional_scoped_lock;
182 m : BOOL ret = ::HeapWalk(heap, entry);
183 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, entry, ret);
184 m : return ret;
185 m : }
186 :
187 m : BOOL WINAPI asan_HeapSetInformation(
188 m : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
189 m : PVOID info, SIZE_T info_length) {
190 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
191 : // is enabled.
192 m : ConditionalScopedLock conditional_scoped_lock;
193 m : BOOL ret = ::HeapSetInformation(heap, info_class, info, info_length);
194 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(heap, info_class, info, info_length, ret);
195 m : return ret;
196 m : }
197 :
198 m : BOOL WINAPI asan_HeapQueryInformation(
199 m : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
200 m : PVOID info, SIZE_T info_length, PSIZE_T return_length) {
201 : // This ensures that all heap access is synchronous if 'serialize_timestamps'
202 : // is enabled.
203 m : ConditionalScopedLock conditional_scoped_lock;
204 m : BOOL ret = ::HeapQueryInformation(
205 m : heap, info_class, info, info_length, return_length);
206 m : EMIT_DETAILED_HEAP_FUNCTION_CALL(
207 m : heap, info_class, info, info_length, return_length, ret);
208 m : return ret;
209 m : }
210 :
211 m : } // extern "C"
|