1 : // Copyright 2012 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 : // A class that take care of initializing asan run-time library.
16 :
17 : #ifndef SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
18 : #define SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
19 :
20 : #include <set>
21 : #include <string>
22 :
23 : #include "base/callback.h"
24 : #include "base/logging.h"
25 : #include "base/memory/scoped_ptr.h"
26 : #include "base/synchronization/lock.h"
27 : #include "syzygy/agent/asan/heap_checker.h"
28 : #include "syzygy/agent/asan/heap_managers/block_heap_manager.h"
29 : #include "syzygy/agent/common/stack_capture.h"
30 : #include "syzygy/common/asan_parameters.h"
31 :
32 : namespace agent {
33 : namespace asan {
34 :
35 : // Forward declarations.
36 : class AsanLogger;
37 :
38 : // An Asan Runtime manager.
39 : // This class takes care of initializing the different modules (stack cache,
40 : // logger...) and provide the functions to report an error.
41 : // Basic usage:
42 : // AsanRuntime* asan_runtime = new AsanRuntime();
43 : // std::wstring asan_flags_str;
44 : // AsanRuntime::GetAsanFlagsEnvVar(&asan_flags_str);
45 : // asan_runtime->SetUp(asan_flags_str); // Initialize the modules.
46 : // ...
47 : // AsanErrorInfo bad_access_info = {};
48 : // ::RtlCaptureContext(&bad_access_info.context);
49 : // StackCapture stack;
50 : // stack.InitFromStack();
51 : // stack.set_stack_id(stack.ComputeRelativeStackId());
52 : // bad_access_info.crash_stack_id = stack.stack_id();
53 : // asan_runtime->OnError(&bad_access_info);
54 : // asan_runtime->TearDown(); // Release the modules.
55 : // delete asan_runtime;
56 : class AsanRuntime {
57 : public:
58 : typedef std::set<common::StackCapture::StackId> StackIdSet;
59 :
60 : // The type of callback used by the OnError function.
61 : typedef base::Callback<void(AsanErrorInfo*)> AsanOnErrorCallBack;
62 :
63 : AsanRuntime();
64 : ~AsanRuntime();
65 :
66 : // @name Accessors.
67 : // @{
68 : AsanLogger* logger() {
69 : DCHECK(logger_.get() != NULL);
70 : return logger_.get();
71 : }
72 E : StackCaptureCache* stack_cache() {
73 E : DCHECK(stack_cache_.get() != NULL);
74 E : return stack_cache_.get();
75 E : }
76 : // @}
77 :
78 : // Initialize asan runtime library.
79 : // @param flags_command_line The parameters string.
80 : void SetUp(const std::wstring& flags_command_line);
81 :
82 : // Release asan runtime library.
83 : void TearDown();
84 :
85 : // The body of the OnError functions, minus the error handler callback.
86 : // Factored out for reuse by OnError and unfiltered exception handling.
87 : // @param error_info The information about this error.
88 : void OnErrorImpl(AsanErrorInfo* error_info);
89 :
90 : // The error handler.
91 : // @param error_info The information about this error.
92 : void OnError(AsanErrorInfo* error_info);
93 :
94 : // Set the callback called on error.
95 : // TODO(sebmarchand): Move the signature of this callback to an header file
96 : // so it'll be easier to update it.
97 : void SetErrorCallBack(const AsanOnErrorCallBack& callback);
98 :
99 : // Try to read the Asan environment variable.
100 : // @param env_var_wstr The wstring where to store the environment variable.
101 : // returns true on success, false otherwise.
102 : static bool GetAsanFlagsEnvVar(std::wstring* env_var_wstr);
103 :
104 : // Returns true if we should ignore the given @p stack_id, false
105 : // otherwise.
106 E : bool ShouldIgnoreError(::common::AsanStackId stack_id) const {
107 : // TODO(sebmarchand): Keep a list of the stack ids that have already been
108 : // reported so we can avoid reporting the same error multiple times.
109 : return params_.ignored_stack_ids_set.find(stack_id) !=
110 E : params_.ignored_stack_ids_set.end();
111 E : }
112 :
113 : // Get information about a bad access.
114 : // @param bad_access_info Will receive the information about this access.
115 : void GetBadAccessInformation(AsanErrorInfo* error_info);
116 :
117 : // TODO(chrisha): Make this a proper singleton.
118 : // @returns the singleton runtime.
119 E : static AsanRuntime* runtime() { return runtime_; }
120 :
121 : // Accessors for runtime parameters.
122 E : ::common::InflatedAsanParameters& params() { return params_; }
123 : const ::common::InflatedAsanParameters& params() const { return params_; }
124 :
125 : // @returns the value of the tick counter when the runtime was created.
126 E : uint32 starting_ticks() const { return starting_ticks_; }
127 :
128 : // Retrieves the process's heap.
129 : // @returns The ID of the process's heap.
130 E : HeapManagerInterface::HeapId GetProcessHeap() {
131 E : return heap_manager_->process_heap();
132 E : }
133 :
134 : // Returns the allocation-filter flag value.
135 : // @returns the allocation-filter flag value.
136 : // @note The flag is stored per-thread using TLS. Multiple threads do not
137 : // share the same flag.
138 : bool allocation_filter_flag();
139 :
140 : // Sets the allocation-filter flag to the specified value.
141 : // @param value the new value for the flag.
142 : // @note The flag is stored per-thread using TLS. Multiple threads do not
143 : // share the same flag.
144 : void set_allocation_filter_flag(bool value);
145 :
146 : // Observes a given thread ID, adding it to thread ID set.
147 : // @param thread_id The thread ID that has been observed.
148 : void AddThreadId(uint32 thread_id);
149 :
150 : // Determines if a thread ID has already been seen.
151 : // @param thread_id The thread ID to be queried.
152 : // @returns true if a given thread ID is valid for this process.
153 : bool ThreadIdIsValid(uint32 thread_id);
154 :
155 : // @name Introspection entry points into the block heap manager. These
156 : // are only meant to be run when the block heap manager lock is already
157 : // held, like during crash processing. If used in unittests care must be
158 : // taken to ensure the access is synchronous if the lock isn't otherwise
159 : // held.
160 : // @{
161 : // Determines if a given heap ID is valid.
162 : // @param uint32 heap_id The heap ID to check.
163 : // @returns true if valid, false otherwise.
164 : bool HeapIdIsValid(HeapManagerInterface::HeapId heap_id);
165 :
166 : // Returns the type of a given heap.
167 : // @param uint32 heap_id The heap ID to check.
168 : // @returns the heap type, or kUnknownHeapType if the heap is invalid.
169 : HeapType GetHeapType(HeapManagerInterface::HeapId heap_id);
170 : // @}
171 :
172 : // Processes an exception and determines if an Asan error has occurred,
173 : // updating the exception if so. If Breakpad is enabled, passes the
174 : // exception to it, otherwise lets the exception continue unhandled.
175 : // @note This is basically a Windows SEH exception filter.
176 : // @param exception The exception to be processed.
177 : // @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_EXECUTE_HANDLER.
178 : static int CrashForException(EXCEPTION_POINTERS* exception);
179 :
180 : protected:
181 : // Propagate the values of the flags to the target modules.
182 : void PropagateParams();
183 :
184 : // @returns the space required to write the provided corrupt heap info.
185 : // @param corrupt_ranges The corrupt range info.
186 : size_t CalculateCorruptHeapInfoSize(
187 : const HeapChecker::CorruptRangesVector& corrupt_ranges);
188 :
189 : // Writes corrupt heap information to the provided buffer. This will write
190 : // as much of the information as possible in the space provided.
191 : // @param corrupt_ranges The corrupt range info.
192 : // @param buffer_size The size of the buffer to be written to. May be zero.
193 : // @param buffer The location where data will be written. May be null.
194 : // @param error_info The written heap metadata will be wired up to the
195 : // provided error_info.
196 : void WriteCorruptHeapInfo(
197 : const HeapChecker::CorruptRangesVector& corrupt_ranges,
198 : size_t buffer_size,
199 : void* buffer,
200 : AsanErrorInfo* error_info);
201 :
202 : // Logs information about an Asan error.
203 : void LogAsanErrorInfo(AsanErrorInfo* error_info);
204 :
205 : // The heap manager.
206 : scoped_ptr<heap_managers::BlockHeapManager> heap_manager_; // Under lock_.
207 :
208 : private:
209 : // Set up the logger.
210 : void SetUpLogger();
211 :
212 : // Tear down the logger.
213 : void TearDownLogger();
214 :
215 : // Set up the stack cache.
216 : void SetUpStackCache();
217 :
218 : // Tear down the stack cache.
219 : void TearDownStackCache();
220 :
221 : // Set up the heap manager.
222 : void SetUpHeapManager();
223 :
224 : // Tear down the heap manager.
225 : void TearDownHeapManager();
226 :
227 : // The unhandled exception filter registered by this runtime. This is used
228 : // to catch unhandled exceptions so we can augment them with information
229 : // about the corrupt heap.
230 : static LONG WINAPI UnhandledExceptionFilter(
231 : struct _EXCEPTION_POINTERS* exception);
232 :
233 : // The implementation of the Asan exception handler. This has two flavours:
234 : // in the context of an unhandled exception filter, and in the context of
235 : // an exception handler. If |is_unhandled| is true then this will pass the
236 : // exception along to the next unfiltered exception handler. Otherwise, it'll
237 : // pass it along to Breakpad, if present. Finally, it'll let the exception
238 : // processing continue unhandled.
239 : static LONG ExceptionFilterImpl(bool is_unhandled,
240 : EXCEPTION_POINTERS* exception);
241 :
242 : // @name Static variables related to unhandled exception filtering (UEF).
243 : // @{
244 : static base::Lock lock_; // Lock for all runtimes.
245 : static AsanRuntime* runtime_; // Singleton. Under lock_.
246 : static LPTOP_LEVEL_EXCEPTION_FILTER previous_uef_; // Under lock_.
247 : static bool uef_installed_; // Under lock_.
248 : // @}
249 :
250 : // The shared logger instance that will be used to report errors and runtime
251 : // information.
252 : scoped_ptr<AsanLogger> logger_;
253 :
254 : // The shared stack cache instance that will be used by all the heaps.
255 : scoped_ptr<StackCaptureCache> stack_cache_;
256 :
257 : // The asan error callback functor.
258 : AsanOnErrorCallBack asan_error_callback_;
259 :
260 : // The runtime parameters.
261 : ::common::InflatedAsanParameters params_;
262 :
263 : // The tick counter when the runtime was created. This is used for
264 : // bracketing valid alloc and free ticks values.
265 : uint32 starting_ticks_;
266 :
267 : // The set of thread IDs that have been seen in the current process.
268 : // This is used to validate thread IDs in a block trailer.
269 : base::Lock thread_ids_lock_;
270 : std::hash_set<uint32> thread_ids_; // Under thread_ids_lock_.
271 :
272 : DISALLOW_COPY_AND_ASSIGN(AsanRuntime);
273 : };
274 :
275 : } // namespace asan
276 : } // namespace agent
277 :
278 : #endif // SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
|