1 // Copyright 2021 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef PARTITION_ALLOC_STACK_STACK_H_ 6 #define PARTITION_ALLOC_STACK_STACK_H_ 7 8 #include <cstdint> 9 #include <functional> 10 #include <mutex> 11 #include <unordered_map> 12 #include <utility> 13 14 #include "partition_alloc/internal_allocator.h" 15 #include "partition_alloc/partition_alloc_base/compiler_specific.h" 16 #include "partition_alloc/partition_alloc_base/component_export.h" 17 #include "partition_alloc/partition_alloc_base/thread_annotations.h" 18 #include "partition_alloc/partition_alloc_base/threading/platform_thread.h" 19 #include "partition_alloc/partition_lock.h" 20 21 namespace partition_alloc::internal { 22 23 // Returns the current stack pointer. 24 // TODO(bikineev,1202644): Remove this once base/stack_util.h lands. 25 PA_NOINLINE PA_COMPONENT_EXPORT(PARTITION_ALLOC) uintptr_t* GetStackPointer(); 26 // Returns the top of the stack using system API. 27 PA_COMPONENT_EXPORT(PARTITION_ALLOC) void* GetStackTop(); 28 29 // Interface for stack visitation. 30 class StackVisitor { 31 public: 32 virtual void VisitStack(uintptr_t* stack_ptr, uintptr_t* stack_top) = 0; 33 }; 34 35 // Abstraction over the stack. Supports handling of: 36 // - native stack; 37 // - SafeStack: 38 // https://releases.llvm.org/10.0.0/tools/clang/docs/SafeStack.html PA_COMPONENT_EXPORT(PARTITION_ALLOC)39class PA_COMPONENT_EXPORT(PARTITION_ALLOC) Stack final { 40 public: 41 // Sets start of the stack. 42 explicit Stack(void* stack_top); 43 44 // Word-aligned iteration of the stack. Flushes callee saved registers and 45 // passes the range of the stack on to |visitor|. 46 void IteratePointers(StackVisitor* visitor) const; 47 48 // Returns the top of the stack. 49 void* stack_top() const { return stack_top_; } 50 51 private: 52 void* stack_top_; 53 }; 54 55 // A class to keep stack top pointers through thread creation/destruction. PA_COMPONENT_EXPORT(PARTITION_ALLOC)56class PA_COMPONENT_EXPORT(PARTITION_ALLOC) StackTopRegistry { 57 public: 58 static StackTopRegistry& Get(); 59 void NotifyThreadCreated(void* stack_top = GetStackPointer()); 60 void NotifyThreadDestroyed(); 61 void* GetCurrentThreadStackTop() const; 62 63 private: 64 using StackTops = 65 std::unordered_map<base::PlatformThreadId, 66 void*, 67 std::hash<base::PlatformThreadId>, 68 std::equal_to<>, 69 internal::InternalAllocator< 70 std::pair<const base::PlatformThreadId, void*>>>; 71 72 friend class base::NoDestructor<StackTopRegistry>; 73 74 StackTopRegistry(); 75 ~StackTopRegistry(); 76 77 // TLS emulation of stack tops. Since this is guaranteed to go through 78 // non-quarantinable partition, using it from safepoints is safe. 79 mutable Lock lock_; 80 StackTops stack_tops_ PA_GUARDED_BY(lock_); 81 }; 82 83 } // namespace partition_alloc::internal 84 85 #endif // PARTITION_ALLOC_STACK_STACK_H_ 86