Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Side by Side Diff: runtime/vm/malloc_hooks.cc

Issue 2701013002: Resolution for issue #28746: changed order in which locks/flags are grabbed in MallocHooks to preve… (Closed)
Patch Set: Resolution for issue #28746: changed order in which locks/flags are grabbed in MallocHooks to preve… Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/globals.h" 5 #include "platform/globals.h"
6 6
7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
8 8
9 #include "vm/malloc_hooks.h" 9 #include "vm/malloc_hooks.h"
10 10
11 #include "gperftools/malloc_hook.h" 11 #include "gperftools/malloc_hook.h"
12 12
13 #include "platform/assert.h" 13 #include "platform/assert.h"
14 #include "vm/hash_map.h" 14 #include "vm/hash_map.h"
15 #include "vm/json_stream.h" 15 #include "vm/json_stream.h"
16 #include "vm/lockers.h" 16 #include "vm/lockers.h"
17 17
18 namespace dart { 18 namespace dart {
19 19
20 // A locker-type class to automatically grab and release the 20 // A locker-type class to automatically grab and release the
21 // in_malloc_hook_flag_. 21 // in_malloc_hook_flag_.
22 class MallocHookScope { 22 class MallocHookScope {
23 public: 23 public:
24 static void InitMallocHookFlag() { 24 static void InitMallocHookFlag() {
25 MutexLocker ml(malloc_hook_scope_mutex_);
25 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); 26 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey);
26 in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); 27 in_malloc_hook_flag_ = OSThread::CreateThreadLocal();
27 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); 28 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
28 } 29 }
29 30
30 static void DestroyMallocHookFlag() { 31 static void DestroyMallocHookFlag() {
32 MutexLocker ml(malloc_hook_scope_mutex_);
31 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 33 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
32 OSThread::DeleteThreadLocal(in_malloc_hook_flag_); 34 OSThread::DeleteThreadLocal(in_malloc_hook_flag_);
33 in_malloc_hook_flag_ = kUnsetThreadLocalKey; 35 in_malloc_hook_flag_ = kUnsetThreadLocalKey;
34 } 36 }
35 37
36 MallocHookScope() { 38 MallocHookScope() {
39 MutexLocker ml(malloc_hook_scope_mutex_);
37 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 40 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
38 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1); 41 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
39 } 42 }
40 43
41 ~MallocHookScope() { 44 ~MallocHookScope() {
45 MutexLocker ml(malloc_hook_scope_mutex_);
42 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
43 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); 47 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
44 } 48 }
45 49
46 static bool IsInHook() { 50 static bool IsInHook() {
47 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 51 MutexLocker ml(malloc_hook_scope_mutex_);
bkonyi 2017/02/17 21:15:11 I added a mutex to the MallocHookScope class so th
52 if (in_malloc_hook_flag_ == kUnsetThreadLocalKey) {
53 // Bail out if the malloc hook flag is invalid. This means that
54 // MallocHookState::TearDown() has been called and MallocHookScope is no
55 // longer intitialized. Don't worry if MallocHookState::TearDown() is
56 // called before the hooks grab the mutex, since
57 // MallocHookScope::Active() is checked after the lock is taken before
58 // proceeding to act on the allocation/free.
59 return false;
60 }
48 return OSThread::GetThreadLocal(in_malloc_hook_flag_); 61 return OSThread::GetThreadLocal(in_malloc_hook_flag_);
49 } 62 }
50 63
64 static bool Active() {
zra 2017/02/17 21:42:26 rm
65 MutexLocker ml(malloc_hook_scope_mutex_);
66 return in_malloc_hook_flag_ != kUnsetThreadLocalKey;
bkonyi 2017/02/17 21:15:11 I'm guessing this needs parens around the boolean
67 }
68
51 private: 69 private:
70 static Mutex* malloc_hook_scope_mutex_;
52 static ThreadLocalKey in_malloc_hook_flag_; 71 static ThreadLocalKey in_malloc_hook_flag_;
53 72
54 DISALLOW_ALLOCATION(); 73 DISALLOW_ALLOCATION();
55 DISALLOW_COPY_AND_ASSIGN(MallocHookScope); 74 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
56 }; 75 };
57 76
58 77
59 // Custom key/value trait specifically for address/size pairs. Unlike 78 // Custom key/value trait specifically for address/size pairs. Unlike
60 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. 79 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
61 class AddressKeyValueTrait { 80 class AddressKeyValueTrait {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 static intptr_t original_pid_; 185 static intptr_t original_pid_;
167 static Mutex* malloc_hook_mutex_; 186 static Mutex* malloc_hook_mutex_;
168 static intptr_t allocation_count_; 187 static intptr_t allocation_count_;
169 static intptr_t heap_allocated_memory_in_bytes_; 188 static intptr_t heap_allocated_memory_in_bytes_;
170 static AddressMap* address_map_; 189 static AddressMap* address_map_;
171 190
172 static const intptr_t kInvalidPid = -1; 191 static const intptr_t kInvalidPid = -1;
173 }; 192 };
174 193
175 194
195 // MallocHookScope state.
196 Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex();
197 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
198
176 // MallocHooks state / locks. 199 // MallocHooks state / locks.
177 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
178 bool MallocHooksState::active_ = false; 200 bool MallocHooksState::active_ = false;
179 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; 201 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
180 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); 202 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
181 203
182 // Memory allocation state information. 204 // Memory allocation state information.
183 intptr_t MallocHooksState::allocation_count_ = 0; 205 intptr_t MallocHooksState::allocation_count_ = 0;
184 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; 206 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
185 AddressMap* MallocHooksState::address_map_ = NULL; 207 AddressMap* MallocHooksState::address_map_ = NULL;
186 208
187 209
(...skipping 17 matching lines...) Expand all
205 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 227 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
206 ASSERT(MallocHooksState::Active()); 228 ASSERT(MallocHooksState::Active());
207 229
208 // Remove malloc hooks. 230 // Remove malloc hooks.
209 bool success = false; 231 bool success = false;
210 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); 232 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
211 ASSERT(success); 233 ASSERT(success);
212 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); 234 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
213 ASSERT(success); 235 ASSERT(success);
214 236
215 MallocHooksState::TearDown(); 237 MallocHooksState::TearDown();
zra 2017/02/17 21:29:53 !MallocHooksState::Active() implies !MallocHookSco
216 MallocHookScope::DestroyMallocHookFlag(); 238 MallocHookScope::DestroyMallocHookFlag();
217 } 239 }
218 240
219 241
220 void MallocHooks::ResetStats() { 242 void MallocHooks::ResetStats() {
221 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 243 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
222 if (MallocHooksState::Active()) { 244 if (MallocHooksState::Active()) {
223 MallocHooksState::ResetStats(); 245 MallocHooksState::ResetStats();
224 } 246 }
225 } 247 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 285 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
264 return MallocHooksState::heap_allocated_memory_in_bytes(); 286 return MallocHooksState::heap_allocated_memory_in_bytes();
265 } 287 }
266 288
267 289
268 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { 290 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
269 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 291 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
270 return; 292 return;
271 } 293 }
272 294
273 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
274 // again.
275 MallocHookScope mhs;
276 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 295 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
277 if ((ptr != NULL) && MallocHooksState::Active()) { 296 // Now that we hold the lock, check to make sure everything is still active.
297 if ((ptr != NULL) && MallocHooksState::Active() &&
298 MallocHookScope::Active()) {
bkonyi 2017/02/17 21:15:11 This extra condition, MallocHookScope::Active(), i
zra 2017/02/17 21:29:53 I don't think it's possible that we could have Mal
299 // Set the malloc hook flag to avoid calling hooks again if memory is
300 // allocated/freed below.
301 MallocHookScope mhs;
278 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); 302 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
279 MallocHooksState::address_map()->Insert(ptr, size); 303 MallocHooksState::address_map()->Insert(ptr, size);
280 } 304 }
281 } 305 }
282 306
283 307
284 void MallocHooksState::RecordFreeHook(const void* ptr) { 308 void MallocHooksState::RecordFreeHook(const void* ptr) {
285 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 309 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
286 return; 310 return;
287 } 311 }
288 312
289 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
290 // again.
291 MallocHookScope mhs;
292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 313 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
293 if ((ptr != NULL) && MallocHooksState::Active()) { 314 // Now that we hold the lock, check to make sure everything is still active.
315 if ((ptr != NULL) && MallocHooksState::Active() &&
316 MallocHookScope::Active()) {
zra 2017/02/17 21:29:53 ditto
317 // Set the malloc hook flag to avoid calling hooks again if memory is
318 // allocated/freed below.
319 MallocHookScope mhs;
294 intptr_t size = 0; 320 intptr_t size = 0;
295 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { 321 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
296 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); 322 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
297 MallocHooksState::address_map()->Remove(ptr); 323 MallocHooksState::address_map()->Remove(ptr);
298 } 324 }
299 } 325 }
300 } 326 }
301 327
302 } // namespace dart 328 } // namespace dart
303 329
304 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 330 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698