7179701: MaxJavaStackTraceDepth of zero is not handled correctly/consistently in the VM

Value of zero means unlimited stack trace.  If you want no stack trace, use -XX:-StackTraceInThrowable

Reviewed-by: dholmes, hseigel
This commit is contained in:
Coleen Phillimore 2018-01-31 11:07:55 -05:00
parent 0a10af4b06
commit 7660d97e2e
5 changed files with 112 additions and 11 deletions

View File

@ -1968,7 +1968,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
bool skip_throwableInit_check = false;
bool skip_hidden = !ShowHiddenFrames;
for (frame fr = thread->last_frame(); max_depth != total_count;) {
for (frame fr = thread->last_frame(); max_depth == 0 || max_depth != total_count;) {
Method* method = NULL;
int bci = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -133,7 +133,7 @@ void vframeStreamForte::forte_next() {
// By the time we get here we should never see unsafe but better
// safe then segv'd
if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
if ((loop_max != 0 && loop_count > loop_max) || !_frame.safe_for_sender(_thread)) {
_mode = at_end_mode;
return;
}
@ -324,7 +324,7 @@ static bool find_initial_Java_frame(JavaThread* thread,
int loop_max = MaxJavaStackTraceDepth * 2;
RegisterMap map(thread, false);
for (loop_count = 0; loop_count < loop_max; loop_count++) {
for (loop_count = 0; loop_max == 0 || loop_count < loop_max; loop_count++) {
if (!candidate.safe_for_sender(thread)) return false;
candidate = candidate.sender(&map);
if (candidate.cb() != NULL) break;
@ -338,7 +338,7 @@ static bool find_initial_Java_frame(JavaThread* thread,
int loop_max = MaxJavaStackTraceDepth * 2;
RegisterMap map(thread, false);
for (loop_count = 0; loop_count < loop_max; loop_count++) {
for (loop_count = 0; loop_max == 0 || loop_count < loop_max; loop_count++) {
if (candidate.is_entry_frame()) {
// jcw is NULL if the java call wrapper couldn't be found

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -677,7 +677,7 @@ JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_th
int depth = 0;
for (javaVFrame *jvf = java_thread->last_java_vframe(&reg_map); jvf != NULL;
jvf = jvf->java_sender()) {
if (depth++ < MaxJavaStackTraceDepth) { // check for stack too deep
if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) { // check for stack too deep
// add locked objects for this frame into list
err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1);
if (err != JVMTI_ERROR_NONE) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -3200,7 +3200,7 @@ void JavaThread::print_stack_on(outputStream* st) {
RegisterMap reg_map(this);
vframe* start_vf = last_java_vframe(&reg_map);
int count = 0;
for (vframe* f = start_vf; f; f = f->sender()) {
for (vframe* f = start_vf; f != NULL; f = f->sender()) {
if (f->is_java_frame()) {
javaVFrame* jvf = javaVFrame::cast(f);
java_lang_Throwable::print_stack_element(st, jvf->method(), jvf->bci());
@ -3213,9 +3213,9 @@ void JavaThread::print_stack_on(outputStream* st) {
// Ignore non-Java frames
}
// Bail-out case for too deep stacks
// Bail-out case for too deep stacks if MaxJavaStackTraceDepth > 0
count++;
if (MaxJavaStackTraceDepth == count) return;
if (MaxJavaStackTraceDepth > 0 && MaxJavaStackTraceDepth == count) return;
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7179701
* @summary MaxJavaStackTraceDepth of zero is not handled correctly/consistently in the VM
* @modules java.base/jdk.internal.misc:open
* @modules java.base/java.lang:open
* @library /test/lib
* @run main TestMaxJavaStackTraceDepth runTest
*/
import java.lang.reflect.Field;
import jdk.test.lib.Asserts;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class TestMaxJavaStackTraceDepth {
static final int maxDepth = 2010;
// Inner class that throws a lot of exceptions
static class Thrower {
int count = 0;
int getDepth(Throwable t) throws Exception {
Field f = Throwable.class.getDeclaredField("depth");
f.setAccessible(true); // it's private
return f.getInt(t);
}
void callThrow() throws Exception {
if (++count < maxDepth) {
callThrow();
} else {
throw new RuntimeException("depth tested " + maxDepth);
}
}
void testThrow() throws Exception {
try {
count = getDepth(new Throwable()); // count stack to this point.
callThrow();
} catch(Exception e) {
e.getStackTrace();
System.out.println(e.getMessage());
int throwableDepth = getDepth(e);
System.out.println("java.lang.RuntimeException, " + throwableDepth);
}
}
}
public static void main(String args[]) throws Exception {
if (args.length > 0) {
// Test values of MaxJavaStackTraceDepth
int[] depths = {0, 20, 1024};
for (int d : depths) {
System.out.println("running test with -XX:MaxJavaStackTraceDepth=" + d);
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stacktrace=info",
"-XX:MaxJavaStackTraceDepth=" + d,
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
"TestMaxJavaStackTraceDepth");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
if (d == 0) {
// Should get all the elements in stack trace
output.shouldContain("java.lang.RuntimeException, " + maxDepth);
} else {
output.shouldContain("java.lang.RuntimeException, " + d);
}
output.shouldHaveExitValue(0);
}
} else {
// run the test
Thrower t = new Thrower();
t.testThrow();
}
}
}