OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/heap/StackFrameDepth.h" | 5 #include "wtf/StackUtil.h" |
6 | 6 |
7 #include "public/platform/Platform.h" | 7 #include "wtf/Assertions.h" |
| 8 #include "wtf/Threading.h" |
| 9 #include "wtf/WTFThreadData.h" |
8 | 10 |
9 #if OS(WIN) | 11 #if OS(WIN) |
10 #include <stddef.h> | 12 #include <stddef.h> |
11 #include <windows.h> | 13 #include <windows.h> |
12 #include <winnt.h> | 14 #include <winnt.h> |
13 #elif defined(__GLIBC__) | 15 #elif defined(__GLIBC__) |
14 extern "C" void* __libc_stack_end; // NOLINT | 16 extern "C" void* __libc_stack_end; // NOLINT |
15 #endif | 17 #endif |
16 | 18 |
17 namespace blink { | 19 namespace WTF { |
18 | 20 |
19 static const char* s_avoidOptimization = nullptr; | 21 size_t getUnderestimatedStackSize() { |
20 | |
21 // NEVER_INLINE ensures that |dummy| array on configureLimit() is not optimized | |
22 // away, and the stack frame base register is adjusted |kSafeStackFrameSize|. | |
23 NEVER_INLINE static uintptr_t currentStackFrameBaseOnCallee(const char* dummy) { | |
24 s_avoidOptimization = dummy; | |
25 return StackFrameDepth::currentStackFrame(); | |
26 } | |
27 | |
28 uintptr_t StackFrameDepth::getFallbackStackLimit() { | |
29 // Allocate an |kSafeStackFrameSize|-sized object on stack and query | |
30 // stack frame base after it. | |
31 char dummy[kSafeStackFrameSize]; | |
32 | |
33 // Check that the stack frame can be used. | |
34 dummy[sizeof(dummy) - 1] = 0; | |
35 return currentStackFrameBaseOnCallee(dummy); | |
36 } | |
37 | |
38 void StackFrameDepth::enableStackLimit() { | |
39 // All supported platforms will currently return a non-zero estimate, | |
40 // except if ASan is enabled. | |
41 size_t stackSize = getUnderestimatedStackSize(); | |
42 if (!stackSize) { | |
43 m_stackFrameLimit = getFallbackStackLimit(); | |
44 return; | |
45 } | |
46 | |
47 static const int kStackRoomSize = 1024; | |
48 | |
49 Address stackBase = reinterpret_cast<Address>(getStackStart()); | |
50 RELEASE_ASSERT(stackSize > static_cast<const size_t>(kStackRoomSize)); | |
51 size_t stackRoom = stackSize - kStackRoomSize; | |
52 RELEASE_ASSERT(stackBase > reinterpret_cast<Address>(stackRoom)); | |
53 m_stackFrameLimit = reinterpret_cast<uintptr_t>(stackBase - stackRoom); | |
54 | |
55 // If current stack use is already exceeding estimated limit, mark as | |
56 // disabled. | |
57 if (!isSafeToRecurse()) | |
58 disableStackLimit(); | |
59 } | |
60 | |
61 size_t StackFrameDepth::getUnderestimatedStackSize() { | |
62 // FIXME: ASAN bot uses a fake stack as a thread stack frame, | 22 // FIXME: ASAN bot uses a fake stack as a thread stack frame, |
63 // and its size is different from the value which APIs tells us. | 23 // and its size is different from the value which APIs tells us. |
64 #if defined(ADDRESS_SANITIZER) | 24 #if defined(ADDRESS_SANITIZER) |
65 return 0; | 25 return 0; |
66 #endif | 26 #endif |
67 | 27 |
68 // FIXME: On Mac OSX and Linux, this method cannot estimate stack size | 28 // FIXME: On Mac OSX and Linux, this method cannot estimate stack size |
69 // correctly for the main thread. | 29 // correctly for the main thread. |
70 | 30 |
71 #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) | 31 #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 // size. | 80 // size. |
121 return (1 * 1024 * 1024 - guardSize); | 81 return (1 * 1024 * 1024 - guardSize); |
122 #else | 82 #else |
123 // Stack size for the main thread is 8MB on OSX excluding the guard page | 83 // Stack size for the main thread is 8MB on OSX excluding the guard page |
124 // size. | 84 // size. |
125 return (8 * 1024 * 1024); | 85 return (8 * 1024 * 1024); |
126 #endif | 86 #endif |
127 } | 87 } |
128 return pthread_get_stacksize_np(pthread_self()); | 88 return pthread_get_stacksize_np(pthread_self()); |
129 #elif OS(WIN) && COMPILER(MSVC) | 89 #elif OS(WIN) && COMPILER(MSVC) |
130 return ThreadState::current()->threadStackSize(); | 90 return WTFThreadData::threadStackSize(); |
131 #else | 91 #else |
132 #error "Stack frame size estimation not supported on this platform." | 92 #error "Stack frame size estimation not supported on this platform." |
133 return 0; | 93 return 0; |
134 #endif | 94 #endif |
135 } | 95 } |
136 | 96 |
137 void* StackFrameDepth::getStackStart() { | 97 void* getStackStart() { |
138 #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) | 98 #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) |
139 pthread_attr_t attr; | 99 pthread_attr_t attr; |
140 int error; | 100 int error; |
141 #if OS(FREEBSD) | 101 #if OS(FREEBSD) |
142 pthread_attr_init(&attr); | 102 pthread_attr_init(&attr); |
143 error = pthread_attr_get_np(pthread_self(), &attr); | 103 error = pthread_attr_get_np(pthread_self(), &attr); |
144 #else | 104 #else |
145 error = pthread_getattr_np(pthread_self(), &attr); | 105 error = pthread_getattr_np(pthread_self(), &attr); |
146 #endif | 106 #endif |
147 if (!error) { | 107 if (!error) { |
148 void* base; | 108 void* base; |
149 size_t size; | 109 size_t size; |
150 error = pthread_attr_getstack(&attr, &base, &size); | 110 error = pthread_attr_getstack(&attr, &base, &size); |
151 RELEASE_ASSERT(!error); | 111 RELEASE_ASSERT(!error); |
152 pthread_attr_destroy(&attr); | 112 pthread_attr_destroy(&attr); |
153 return reinterpret_cast<uint8_t*>(base) + size; | 113 return reinterpret_cast<uint8_t*>(base) + size; |
154 } | 114 } |
155 #if OS(FREEBSD) | 115 #if OS(FREEBSD) |
156 pthread_attr_destroy(&attr); | 116 pthread_attr_destroy(&attr); |
157 #endif | 117 #endif |
158 #if defined(__GLIBC__) | 118 #if defined(__GLIBC__) |
159 // pthread_getattr_np can fail for the main thread. In this case | 119 // pthread_getattr_np can fail for the main thread. In this case |
160 // just like NaCl we rely on the __libc_stack_end to give us | 120 // just like NaCl we rely on the __libc_stack_end to give us |
161 // the start of the stack. | 121 // the start of the stack. |
162 // See https://code.google.com/p/nativeclient/issues/detail?id=3431. | 122 // See https://code.google.com/p/nativeclient/issues/detail?id=3431. |
163 return __libc_stack_end; | 123 return __libc_stack_end; |
164 #else | 124 #else |
165 ASSERT_NOT_REACHED(); | 125 NOTREACHED(); |
166 return nullptr; | 126 return nullptr; |
167 #endif | 127 #endif |
168 #elif OS(MACOSX) | 128 #elif OS(MACOSX) |
169 return pthread_get_stackaddr_np(pthread_self()); | 129 return pthread_get_stackaddr_np(pthread_self()); |
170 #elif OS(WIN) && COMPILER(MSVC) | 130 #elif OS(WIN) && COMPILER(MSVC) |
171 // On Windows stack limits for the current thread are available in | 131 // On Windows stack limits for the current thread are available in |
172 // the thread information block (TIB). Its fields can be accessed through | 132 // the thread information block (TIB). Its fields can be accessed through |
173 // FS segment register on x86 and GS segment register on x86_64. | 133 // FS segment register on x86 and GS segment register on x86_64. |
174 #ifdef _WIN64 | 134 #ifdef _WIN64 |
175 return reinterpret_cast<void*>(__readgsqword(offsetof(NT_TIB64, StackBase))); | 135 return reinterpret_cast<void*>(__readgsqword(offsetof(NT_TIB64, StackBase))); |
176 #else | 136 #else |
177 return reinterpret_cast<void*>(__readfsdword(offsetof(NT_TIB, StackBase))); | 137 return reinterpret_cast<void*>(__readfsdword(offsetof(NT_TIB, StackBase))); |
178 #endif | 138 #endif |
179 #else | 139 #else |
180 #error Unsupported getStackStart on this platform. | 140 #error Unsupported getStackStart on this platform. |
181 #endif | 141 #endif |
182 } | 142 } |
183 | 143 |
184 } // namespace blink | 144 namespace internal { |
| 145 |
| 146 uintptr_t mainThreadUnderestimatedStackSize() { |
| 147 size_t underestimatedStackSize = getUnderestimatedStackSize(); |
| 148 // See comment in mayNotBeMainThread as to why we subtract here. |
| 149 if (underestimatedStackSize > sizeof(void*)) { |
| 150 underestimatedStackSize = underestimatedStackSize - sizeof(void*); |
| 151 } |
| 152 return underestimatedStackSize; |
| 153 } |
| 154 |
| 155 #if OS(WIN) && COMPILER(MSVC) |
| 156 size_t threadStackSize() { |
| 157 // Notice that we cannot use the TIB's StackLimit for the stack end, as i |
| 158 // tracks the end of the committed range. We're after the end of the reserved |
| 159 // stack area (most of which will be uncommitted, most times.) |
| 160 MEMORY_BASIC_INFORMATION stackInfo; |
| 161 memset(&stackInfo, 0, sizeof(MEMORY_BASIC_INFORMATION)); |
| 162 size_t resultSize = |
| 163 VirtualQuery(&stackInfo, &stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); |
| 164 DCHECK_GE(resultSize, sizeof(MEMORY_BASIC_INFORMATION)); |
| 165 uint8_t* stackEnd = reinterpret_cast<uint8_t*>(stackInfo.AllocationBase); |
| 166 |
| 167 uint8_t* stackStart = reinterpret_cast<uint8_t*>(WTF::getStackStart()); |
| 168 RELEASE_ASSERT(stackStart && stackStart > stackEnd); |
| 169 size_t s_threadStackSize = static_cast<size_t>(stackStart - stackEnd); |
| 170 // When the third last page of the reserved stack is accessed as a |
| 171 // guard page, the second last page will be committed (along with removing |
| 172 // the guard bit on the third last) _and_ a stack overflow exception |
| 173 // is raised. |
| 174 // |
| 175 // We have zero interest in running into stack overflow exceptions while |
| 176 // marking objects, so simply consider the last three pages + one above |
| 177 // as off-limits and adjust the reported stack size accordingly. |
| 178 // |
| 179 // http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-man
agement.aspx |
| 180 // explains the details. |
| 181 RELEASE_ASSERT(s_threadStackSize > 4 * 0x1000); |
| 182 s_threadStackSize -= 4 * 0x1000; |
| 183 return s_threadStackSize; |
| 184 } |
| 185 #endif |
| 186 |
| 187 } // namespace internal |
| 188 |
| 189 } // namespace WTF |
OLD | NEW |