Skip to content

Commit 591aa7c

Browse files
committed
8335362: [Windows] Stack pointer increment in _cont_thaw stub can cause program to terminate with exit code 0xc0000005
Reviewed-by: dholmes, fparain
1 parent 237a540 commit 591aa7c

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

src/hotspot/os/windows/os_windows.inline.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,17 @@ inline void os::map_stack_shadow_pages(address sp) {
4949
// If we decrement stack pointer more than one page
5050
// the OS may not map an intervening page into our space
5151
// and may fault on a memory access to interior of our frame.
52+
address original_sp = sp;
5253
const size_t page_size = os::vm_page_size();
5354
const size_t n_pages = StackOverflow::stack_shadow_zone_size() / page_size;
5455
for (size_t pages = 1; pages <= n_pages; pages++) {
5556
sp -= page_size;
5657
*sp = 0;
5758
}
59+
StackOverflow* state = JavaThread::current()->stack_overflow_state();
60+
assert(original_sp > state->shadow_zone_safe_limit(), "original_sp=" INTPTR_FORMAT ", "
61+
"shadow_zone_safe_limit=" INTPTR_FORMAT, p2i(original_sp), p2i(state->shadow_zone_safe_limit()));
62+
state->set_shadow_zone_growth_watermark(original_sp);
5863
}
5964

6065
inline bool os::numa_has_group_homing() { return false; }

src/hotspot/share/runtime/continuationFreezeThaw.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,31 @@ class Config {
277277
}
278278
};
279279

280+
#ifdef _WINDOWS
281+
static void map_stack_pages(JavaThread* thread, size_t size, address sp) {
282+
address new_sp = sp - size;
283+
address watermark = thread->stack_overflow_state()->shadow_zone_growth_watermark();
284+
285+
if (new_sp < watermark) {
286+
size_t page_size = os::vm_page_size();
287+
address last_touched_page = watermark - StackOverflow::stack_shadow_zone_size();
288+
size_t pages_to_touch = align_up(watermark - new_sp, page_size) / page_size;
289+
while (pages_to_touch-- > 0) {
290+
last_touched_page -= page_size;
291+
*last_touched_page = 0;
292+
}
293+
thread->stack_overflow_state()->set_shadow_zone_growth_watermark(new_sp);
294+
}
295+
}
296+
#endif
297+
280298
static bool stack_overflow_check(JavaThread* thread, size_t size, address sp) {
281299
const size_t page_size = os::vm_page_size();
282300
if (size > page_size) {
283301
if (sp - size < thread->stack_overflow_state()->shadow_zone_safe_limit()) {
284302
return false;
285303
}
304+
WINDOWS_ONLY(map_stack_pages(thread, size, sp));
286305
}
287306
return true;
288307
}

src/hotspot/share/runtime/stackOverflow.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,16 @@ class StackOverflow {
293293
return _shadow_zone_safe_limit;
294294
}
295295

296+
address shadow_zone_growth_watermark() const {
297+
assert(_shadow_zone_growth_watermark != nullptr, "Don't call this before the field is initialized.");
298+
return _shadow_zone_growth_watermark;
299+
}
300+
301+
void set_shadow_zone_growth_watermark(address new_watermark) {
302+
assert(_shadow_zone_growth_watermark != nullptr, "Don't call this before the field is initialized.");
303+
_shadow_zone_growth_watermark = new_watermark;
304+
}
305+
296306
void create_stack_guard_pages();
297307
void remove_stack_guard_pages();
298308

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (c) 2024, 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+
* @test id=default
26+
* @bug 8335362
27+
* @summary Test virtual thread usage with big stackChunks
28+
* @requires vm.continuations
29+
* @run junit/othervm BigStackChunk
30+
*/
31+
32+
import java.util.concurrent.locks.ReentrantLock;
33+
34+
import org.junit.jupiter.api.Test;
35+
import static org.junit.jupiter.api.Assertions.*;
36+
37+
class BigStackChunk {
38+
39+
void recurse(int cnt, ReentrantLock rlock) {
40+
int i1 = cnt;
41+
int i2 = i1 + 1;
42+
int i3 = i2 + 1;
43+
int i4 = i3 + 1;
44+
int i5 = i4 + 1;
45+
int i6 = i5 + 1;
46+
int i7 = i6 + 1;
47+
long ll = 2 * (long)i1;
48+
float ff = ll + 1.2f;
49+
double dd = ff + 1.3D;
50+
51+
if (cnt > 0) {
52+
recurse(cnt - 1, rlock);
53+
} else {
54+
rlock.lock();
55+
rlock.unlock();
56+
}
57+
}
58+
59+
@Test
60+
void bigStackChunkTest() throws Exception {
61+
int VTHREAD_CNT = Runtime.getRuntime().availableProcessors();
62+
ReentrantLock rlock = new ReentrantLock();
63+
Thread[] vthreads = new Thread[VTHREAD_CNT];
64+
65+
rlock.lock();
66+
for (int i = 0; i < VTHREAD_CNT; i++) {
67+
vthreads[i] = Thread.ofVirtual().start(() -> {
68+
// Set up things so that half of the carriers will commit lots of
69+
// pages in the stack while running the mounted vthread and half
70+
// will just commit very few ones.
71+
if (Math.random() < 0.5) {
72+
recurse(300, rlock);
73+
} else {
74+
recurse(1, rlock);
75+
}
76+
});
77+
}
78+
await(vthreads[0], Thread.State.WAITING);
79+
// Now we expect that some vthread that recursed a lot is mounted on
80+
// a carrier that previously run a vthread that didn't recurse at all.
81+
rlock.unlock();
82+
83+
for (int i = 0; i < VTHREAD_CNT; i++) {
84+
vthreads[i].join();
85+
}
86+
}
87+
88+
private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
89+
Thread.State state = thread.getState();
90+
while (state != expectedState) {
91+
assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
92+
Thread.sleep(10);
93+
state = thread.getState();
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)