1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #ifndef SHARE_RUNTIME_STACKOVERFLOW_HPP
26 #define SHARE_RUNTIME_STACKOVERFLOW_HPP
27 
28 #include "utilities/align.hpp"
29 #include "utilities/debug.hpp"
30 
31 class JavaThread;
32 
33 // StackOverflow handling is encapsulated in this class.  This class contains state variables
34 // for each JavaThread that are used to detect stack overflow though explicit checks or through
35 // checks in the signal handler when stack banging into guard pages causes a trap.
36 // The state variables also record whether guard pages are enabled or disabled.
37 
38 class StackOverflow {
39   friend class JVMCIVMStructs;
40   friend class JavaThread;
41  public:
42   // State of the stack guard pages for the containing thread.
43   enum StackGuardState {
44     stack_guard_unused,         // not needed
45     stack_guard_reserved_disabled,
46     stack_guard_yellow_reserved_disabled,// disabled (temporarily) after stack overflow
47     stack_guard_enabled         // enabled
48   };
49 
StackOverflow()50   StackOverflow() :
51     _stack_guard_state(stack_guard_unused),
52     _stack_overflow_limit(nullptr),
53     _reserved_stack_activation(nullptr),  // stack base not known yet
54     _stack_base(nullptr), _stack_end(nullptr) {}
55 
56   // Initialization after thread is started.
initialize(address base,address end)57   void initialize(address base, address end) {
58      _stack_base = base;
59      _stack_end = end;
60     set_stack_overflow_limit();
61     set_reserved_stack_activation(base);
62   }
63  private:
64 
65   StackGuardState  _stack_guard_state;
66 
67   // Precompute the limit of the stack as used in stack overflow checks.
68   // We load it from here to simplify the stack overflow check in assembly.
69   address          _stack_overflow_limit;
70   address          _reserved_stack_activation;
71 
72   // Support for stack overflow handling, copied down from thread.
73   address          _stack_base;
74   address          _stack_end;
75 
stack_end() const76   address stack_end()  const           { return _stack_end; }
stack_base() const77   address stack_base() const           { assert(_stack_base != nullptr, "Sanity check"); return _stack_base; }
78 
79   // Stack overflow support
80   //
81   //  (low addresses)
82   //
83   //  --  <-- stack_end()                   ---
84   //  |                                      |
85   //  |  red zone                            |
86   //  |                                      |
87   //  --  <-- stack_red_zone_base()          |
88   //  |                                      |
89   //  |                                     guard
90   //  |  yellow zone                        zone
91   //  |                                      |
92   //  |                                      |
93   //  --  <-- stack_yellow_zone_base()       |
94   //  |                                      |
95   //  |                                      |
96   //  |  reserved zone                       |
97   //  |                                      |
98   //  --  <-- stack_reserved_zone_base()    ---      ---
99   //                                                 /|\  shadow     <--  stack_overflow_limit() (somewhere in here)
100   //                                                  |   zone
101   //                                                 \|/  size
102   //  some untouched memory                          ---
103   //
104   //
105   //  --
106   //  |
107   //  |  shadow zone
108   //  |
109   //  --
110   //  x    frame n
111   //  --
112   //  x    frame n-1
113   //  x
114   //  --
115   //  ...
116   //
117   //  --
118   //  x    frame 0
119   //  --  <-- stack_base()
120   //
121   //  (high addresses)
122   //
123 
124  private:
125   // These values are derived from flags StackRedPages, StackYellowPages,
126   // StackReservedPages and StackShadowPages.
127   static size_t _stack_red_zone_size;
128   static size_t _stack_yellow_zone_size;
129   static size_t _stack_reserved_zone_size;
130   static size_t _stack_shadow_zone_size;
131 
132  public:
133   static void initialize_stack_zone_sizes();
134 
stack_red_zone_size()135   static size_t stack_red_zone_size() {
136     assert(_stack_red_zone_size > 0, "Don't call this before the field is initialized.");
137     return _stack_red_zone_size;
138   }
139 
140   // Returns base of red zone (one-beyond the highest red zone address, so
141   //  itself outside red zone and the highest address of the yellow zone).
stack_red_zone_base() const142   address stack_red_zone_base() const {
143     return (address)(stack_end() + stack_red_zone_size());
144   }
145 
146   // Returns true if address points into the red zone.
in_stack_red_zone(address a) const147   bool in_stack_red_zone(address a) const {
148     return a < stack_red_zone_base() && a >= stack_end();
149   }
150 
stack_yellow_zone_size()151   static size_t stack_yellow_zone_size() {
152     assert(_stack_yellow_zone_size > 0, "Don't call this before the field is initialized.");
153     return _stack_yellow_zone_size;
154   }
155 
stack_reserved_zone_size()156   static size_t stack_reserved_zone_size() {
157     // _stack_reserved_zone_size may be 0. This indicates the feature is off.
158     return _stack_reserved_zone_size;
159   }
160 
161   // Returns base of the reserved zone (one-beyond the highest reserved zone address).
stack_reserved_zone_base() const162   address stack_reserved_zone_base() const {
163     return (address)(stack_end() +
164                      (stack_red_zone_size() + stack_yellow_zone_size() + stack_reserved_zone_size()));
165   }
166 
167   // Returns true if address points into the reserved zone.
in_stack_reserved_zone(address a) const168   bool in_stack_reserved_zone(address a) const {
169     return (a < stack_reserved_zone_base()) &&
170            (a >= (address)((intptr_t)stack_reserved_zone_base() - stack_reserved_zone_size()));
171   }
172 
stack_yellow_reserved_zone_size()173   static size_t stack_yellow_reserved_zone_size() {
174     return _stack_yellow_zone_size + _stack_reserved_zone_size;
175   }
176 
177   // Returns true if a points into either yellow or reserved zone.
in_stack_yellow_reserved_zone(address a) const178   bool in_stack_yellow_reserved_zone(address a) const {
179     return (a < stack_reserved_zone_base()) && (a >= stack_red_zone_base());
180   }
181 
182   // Size of red + yellow + reserved zones.
stack_guard_zone_size()183   static size_t stack_guard_zone_size() {
184     return stack_red_zone_size() + stack_yellow_reserved_zone_size();
185   }
186 
stack_shadow_zone_size()187   static size_t stack_shadow_zone_size() {
188     assert(_stack_shadow_zone_size > 0, "Don't call this before the field is initialized.");
189     return _stack_shadow_zone_size;
190   }
191 
192   void create_stack_guard_pages();
193   void remove_stack_guard_pages();
194 
195   void enable_stack_reserved_zone(bool check_if_disabled = false);
196   void disable_stack_reserved_zone();
197   void enable_stack_yellow_reserved_zone();
198   void disable_stack_yellow_reserved_zone();
199   void enable_stack_red_zone();
200   void disable_stack_red_zone();
201 
stack_guard_zone_unused() const202   bool stack_guard_zone_unused() const { return _stack_guard_state == stack_guard_unused; }
203 
stack_yellow_reserved_zone_disabled() const204   bool stack_yellow_reserved_zone_disabled() const {
205     return _stack_guard_state == stack_guard_yellow_reserved_disabled;
206   }
207 
stack_available(address cur_sp) const208   size_t stack_available(address cur_sp) const {
209     // This code assumes java stacks grow down
210     address low_addr; // Limit on the address for deepest stack depth
211     if (_stack_guard_state == stack_guard_unused) {
212       low_addr = stack_end();
213     } else {
214       low_addr = stack_reserved_zone_base();
215     }
216     return cur_sp > low_addr ? cur_sp - low_addr : 0;
217   }
218 
219   bool stack_guards_enabled() const;
220 
reserved_stack_activation() const221   address reserved_stack_activation() const { return _reserved_stack_activation; }
set_reserved_stack_activation(address addr)222   void set_reserved_stack_activation(address addr) {
223     assert(_reserved_stack_activation == stack_base()
224             || _reserved_stack_activation == nullptr
225             || addr == stack_base(), "Must not be set twice");
226     _reserved_stack_activation = addr;
227   }
228 
229   // Attempt to reguard the stack after a stack overflow may have occurred.
230   // Returns true if (a) guard pages are not needed on this thread, (b) the
231   // pages are already guarded, or (c) the pages were successfully reguarded.
232   // Returns false if there is not enough stack space to reguard the pages, in
233   // which case the caller should unwind a frame and try again.  The argument
234   // should be the caller's (approximate) sp.
235   bool reguard_stack(address cur_sp);
236   // Similar to above but see if current stackpoint is out of the guard area
237   // and reguard if possible.
238   bool reguard_stack(void);
239   bool reguard_stack_if_needed(void);
240 
set_stack_overflow_limit()241   void set_stack_overflow_limit() {
242     _stack_overflow_limit =
243       stack_end() + MAX2(stack_guard_zone_size(), stack_shadow_zone_size());
244   }
245 };
246 
247 #endif // SHARE_RUNTIME_STACKOVERFLOW_HPP
248