undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
461
test/langtools/jdk/jshell/ExceptionsTest.java
Normal file
461
test/langtools/jdk/jshell/ExceptionsTest.java
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
* @summary Tests for exceptions
|
||||
* @bug 8198801 8212167 8210527 8370175
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* @library /tools/lib
|
||||
* @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
|
||||
* @build KullaTesting TestingInputStream Compiler
|
||||
* @run junit ExceptionsTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import jdk.jshell.EvalException;
|
||||
import jdk.jshell.JShellException;
|
||||
import jdk.jshell.Snippet;
|
||||
import jdk.jshell.SnippetEvent;
|
||||
import jdk.jshell.UnresolvedReferenceException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ExceptionsTest extends KullaTesting {
|
||||
|
||||
private final Compiler compiler = new Compiler();
|
||||
private final Path outDir = Paths.get("test_class_path");
|
||||
|
||||
@Test
|
||||
public void throwUncheckedException() {
|
||||
String message = "error_message";
|
||||
SnippetEvent cr = assertEvalException("throw new RuntimeException(\"" + message + "\");");
|
||||
assertExceptionMatch(cr,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "", cr.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwCheckedException() {
|
||||
String message = "error_message";
|
||||
SnippetEvent cr = assertEvalException("throw new Exception(\"" + message + "\");");
|
||||
assertExceptionMatch(cr,
|
||||
new ExceptionInfo(Exception.class, message,
|
||||
newStackTraceElement("", "", cr.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromStaticMethodOfClass() {
|
||||
String message = "error_message";
|
||||
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
|
||||
Snippet s2 = classKey(assertEval("class A { static void g() { f(); } }"));
|
||||
SnippetEvent cr3 = assertEvalException("A.g();");
|
||||
assertExceptionMatch(cr3,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "f", s1, 1),
|
||||
newStackTraceElement("A", "g", s2, 1),
|
||||
newStackTraceElement("", "", cr3.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromStaticMethodOfInterface() {
|
||||
String message = "error_message";
|
||||
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
|
||||
Snippet s2 = classKey(assertEval("interface A { static void g() { f(); } }"));
|
||||
SnippetEvent cr3 = assertEvalException("A.g();");
|
||||
assertExceptionMatch(cr3,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "f", s1, 1),
|
||||
newStackTraceElement("A", "g", s2, 1),
|
||||
newStackTraceElement("", "", cr3.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwChained() {
|
||||
String message1 = "error_message1";
|
||||
String message2 = "error_message2";
|
||||
Snippet s1 = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }"));
|
||||
Snippet s2 = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new java.io.IOException(\"" + message2 + "\", ex); }}"));
|
||||
Snippet s3 = methodKey(assertEval("void m() {\n"
|
||||
+ "try { n(); }\n"
|
||||
+ "catch (Exception ex) {\n"
|
||||
+ " throw new RuntimeException(\"" + message1 + "\", ex);\n"
|
||||
+ "}}"));
|
||||
SnippetEvent cr4 = assertEvalException("m();");
|
||||
assertExceptionMatch(cr4,
|
||||
new ExceptionInfo(RuntimeException.class, message1,
|
||||
new ExceptionInfo(IOException.class, message2,
|
||||
new ExceptionInfo(NullPointerException.class, null,
|
||||
newStackTraceElement("", "p", s1, 1),
|
||||
newStackTraceElement("", "n", s2, 1),
|
||||
newStackTraceElement("", "m", s3, 2),
|
||||
newStackTraceElement("", "", cr4.snippet(), 1)),
|
||||
newStackTraceElement("", "n", s2, 1),
|
||||
newStackTraceElement("", "m", s3, 2),
|
||||
newStackTraceElement("", "", cr4.snippet(), 1)),
|
||||
newStackTraceElement("", "m", s3, 4),
|
||||
newStackTraceElement("", "", cr4.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwChainedUnresolved() {
|
||||
String message1 = "error_message1";
|
||||
String message2 = "error_message2";
|
||||
Snippet s1 = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }"));
|
||||
Snippet s2 = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new java.io.IOException(\"" + message2 + "\", ex); }}"));
|
||||
Snippet s3 = methodKey(assertEval("void m() {\n"
|
||||
+ "try { n(); }\n"
|
||||
+ "catch (Exception ex) {\n"
|
||||
+ " throw new RuntimeException(\"" + message1 + "\", ex);\n"
|
||||
+ "}}"));
|
||||
getState().drop(s1);
|
||||
SnippetEvent cr4 = assertEvalException("m();");
|
||||
assertExceptionMatch(cr4,
|
||||
new ExceptionInfo(RuntimeException.class, message1,
|
||||
new UnresolvedExceptionInfo(s2,
|
||||
newStackTraceElement("", "n", s2, 1),
|
||||
newStackTraceElement("", "m", s3, 2),
|
||||
newStackTraceElement("", "", cr4.snippet(), 1)),
|
||||
newStackTraceElement("", "m", s3, 4),
|
||||
newStackTraceElement("", "", cr4.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromConstructor() {
|
||||
String message = "error_message";
|
||||
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
|
||||
Snippet s2 = classKey(assertEval("class A { A() { f(); } }"));
|
||||
SnippetEvent cr3 = assertEvalException("new A();");
|
||||
assertExceptionMatch(cr3,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "f", s1, 1),
|
||||
newStackTraceElement("A", "<init>", s2, 1),
|
||||
newStackTraceElement("", "", cr3.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromDefaultMethodOfInterface() {
|
||||
String message = "error_message";
|
||||
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
|
||||
Snippet s2 = classKey(assertEval("interface A { default void g() { f(); } }"));
|
||||
SnippetEvent cr3 = assertEvalException("new A() { }.g();");
|
||||
assertExceptionMatch(cr3,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "f", s1, 1),
|
||||
newStackTraceElement("A", "g", s2, 1),
|
||||
newStackTraceElement("", "", cr3.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromLambda() {
|
||||
String message = "lambda";
|
||||
Snippet s1 = varKey(assertEval(
|
||||
"Runnable run = () -> {\n" +
|
||||
" throw new RuntimeException(\"" + message + "\");\n" +
|
||||
"};"
|
||||
));
|
||||
SnippetEvent cr2 = assertEvalException("run.run();");
|
||||
assertExceptionMatch(cr2,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("", "lambda$", s1, 2),
|
||||
newStackTraceElement("", "", cr2.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromAnonymousClass() {
|
||||
String message = "anonymous";
|
||||
Snippet s1 = varKey(assertEval(
|
||||
"Runnable run = new Runnable() {\n" +
|
||||
" public void run() {\n"+
|
||||
" throw new RuntimeException(\"" + message + "\");\n" +
|
||||
" }\n" +
|
||||
"};"
|
||||
));
|
||||
SnippetEvent cr2 = assertEvalException("run.run();");
|
||||
assertExceptionMatch(cr2,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("1", "run", s1, 3),
|
||||
newStackTraceElement("", "", cr2.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwFromLocalClass() {
|
||||
String message = "local";
|
||||
Snippet s1 = methodKey(assertEval(
|
||||
"void f() {\n" +
|
||||
" class A {\n" +
|
||||
" void f() {\n"+
|
||||
" throw new RuntimeException(\"" + message + "\");\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" new A().f();\n" +
|
||||
"}"
|
||||
));
|
||||
SnippetEvent cr2 = assertEvalException("f();");
|
||||
assertExceptionMatch(cr2,
|
||||
new ExceptionInfo(RuntimeException.class, message,
|
||||
newStackTraceElement("1A", "f", s1, 4),
|
||||
newStackTraceElement("", "f", s1, 7),
|
||||
newStackTraceElement("", "", cr2.snippet(), 1)));
|
||||
}
|
||||
|
||||
// test 8210527
|
||||
@Test
|
||||
public void throwFromWithoutSource() {
|
||||
String message = "show this";
|
||||
SnippetEvent se = assertEvalException("java.lang.reflect.Proxy.newProxyInstance(" +
|
||||
"Thread.currentThread().getContextClassLoader(), new Class[] {}," +
|
||||
"(p, m, a) -> { throw new IllegalStateException(\"" + message + "\"); }).hashCode()");
|
||||
assertExceptionMatch(se,
|
||||
new ExceptionInfo(IllegalStateException.class, message,
|
||||
newStackTraceElement("", "lambda$do_it$$0", se.snippet(), 1),
|
||||
new StackTraceElement("jdk.proxy1.$Proxy0", "hashCode", null, -1),
|
||||
newStackTraceElement("", "", se.snippet(), 1)));
|
||||
}
|
||||
|
||||
// test 8210527
|
||||
@Test
|
||||
public void throwFromNoSource() {
|
||||
Path path = outDir.resolve("fail");
|
||||
compiler.compile(path,
|
||||
"package fail;\n" +
|
||||
"public class Fail {\n" +
|
||||
" static { int x = 1 / 0; }\n" +
|
||||
"}\n");
|
||||
addToClasspath(compiler.getPath(path));
|
||||
SnippetEvent se = assertEvalException("Class.forName(\"fail.Fail\")");
|
||||
assertExceptionMatch(se,
|
||||
new ExceptionInfo(ExceptionInInitializerError.class, null,
|
||||
new StackTraceElement("java.lang.Class", "forName0", "Class.java", -2),
|
||||
new StackTraceElement("java.lang.Class", "forName", "Class.java", -2),
|
||||
new StackTraceElement("java.lang.Class", "forName", "Class.java", -2),
|
||||
newStackTraceElement("", "", se.snippet(), 1)));
|
||||
}
|
||||
|
||||
// test 8212167
|
||||
@Test
|
||||
public void throwLineFormat1() {
|
||||
SnippetEvent se = assertEvalException(
|
||||
"if (true) { \n" +
|
||||
" int x = 10; \n" +
|
||||
" int y = 10 / 0;}"
|
||||
);
|
||||
assertExceptionMatch(se,
|
||||
new ExceptionInfo(ArithmeticException.class, "/ by zero",
|
||||
newStackTraceElement("", "", se.snippet(), 3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwLineFormat3() {
|
||||
Snippet sp = methodKey(assertEval(
|
||||
"int p() \n" +
|
||||
" { return 4/0; }"));
|
||||
Snippet sm = methodKey(assertEval(
|
||||
"int m(int x)\n" +
|
||||
" \n" +
|
||||
" {\n" +
|
||||
" return p() + x; \n" +
|
||||
" }"));
|
||||
Snippet sn = methodKey(assertEval(
|
||||
"int n(int x) {\n" +
|
||||
" try {\n" +
|
||||
" return m(x);\n" +
|
||||
" }\n" +
|
||||
" catch (Throwable ex) {\n" +
|
||||
" throw new IllegalArgumentException( \"GOT:\", ex);\n" +
|
||||
" }\n" +
|
||||
" }"));
|
||||
SnippetEvent se = assertEvalException("n(33);");
|
||||
assertExceptionMatch(se,
|
||||
new ExceptionInfo(IllegalArgumentException.class, null,
|
||||
new ExceptionInfo(ArithmeticException.class, "/ by zero",
|
||||
newStackTraceElement("", "p", sp, 2),
|
||||
newStackTraceElement("", "m", sm, 4),
|
||||
newStackTraceElement("", "n", sn, 3),
|
||||
newStackTraceElement("", "", se.snippet(), 1)),
|
||||
newStackTraceElement("", "n", sn, 6),
|
||||
newStackTraceElement("", "", se.snippet(), 1)));
|
||||
}
|
||||
|
||||
@Test // TODO 8129427
|
||||
@Disabled
|
||||
public void outOfMemory() {
|
||||
assertEval("import java.util.*;");
|
||||
assertEval("List<byte[]> list = new ArrayList<>();");
|
||||
assertExecuteException("while (true) { list.add(new byte[10000]); }", OutOfMemoryError.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stackOverflow() {
|
||||
assertEval("void f() { f(); }");
|
||||
assertExecuteException("f();", StackOverflowError.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recursiveCauses() {
|
||||
assertEval("var one = new Throwable();");
|
||||
assertEval("var two = new Error();");
|
||||
assertEval("one.initCause(two);");
|
||||
assertEval("two.initCause(one);");
|
||||
assertExecuteException("throw one;", Throwable.class);
|
||||
assertExecuteException("throw two;", Error.class);
|
||||
}
|
||||
|
||||
private StackTraceElement newStackTraceElement(String className, String methodName, Snippet key, int lineNumber) {
|
||||
return new StackTraceElement(className, methodName, "#" + key.id(), lineNumber);
|
||||
}
|
||||
|
||||
private static class AnyExceptionInfo {
|
||||
|
||||
public final StackTraceElement[] stackTraceElements;
|
||||
|
||||
public AnyExceptionInfo(StackTraceElement... stackTraceElements) {
|
||||
this.stackTraceElements = stackTraceElements.length == 0 ? null : stackTraceElements;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnresolvedExceptionInfo extends AnyExceptionInfo {
|
||||
|
||||
public final Snippet sn;
|
||||
|
||||
public UnresolvedExceptionInfo(Snippet sn, StackTraceElement... stackTraceElements) {
|
||||
super(stackTraceElements);
|
||||
this.sn = sn;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExceptionInfo extends AnyExceptionInfo {
|
||||
|
||||
public final Class<? extends Throwable> exception;
|
||||
public final String message;
|
||||
public final AnyExceptionInfo cause;
|
||||
|
||||
public ExceptionInfo(Class<? extends Throwable> exception, String message,
|
||||
StackTraceElement... stackTraceElements) {
|
||||
this(exception, message, null, stackTraceElements);
|
||||
}
|
||||
|
||||
public ExceptionInfo(Class<? extends Throwable> exception, String message,
|
||||
AnyExceptionInfo cause, StackTraceElement... stackTraceElements) {
|
||||
super(stackTraceElements);
|
||||
this.exception = exception;
|
||||
this.message = message;
|
||||
this.cause = cause;
|
||||
}
|
||||
}
|
||||
|
||||
private void assertExecuteException(String input, Class<? extends Throwable> exception) {
|
||||
assertExceptionMatch(assertEvalException(input), new ExceptionInfo(exception, null));
|
||||
}
|
||||
|
||||
private void assertExceptionMatch(SnippetEvent cr, ExceptionInfo exceptionInfo) {
|
||||
assertExceptionMatch(cr.exception(), cr.snippet().source(), exceptionInfo);
|
||||
}
|
||||
|
||||
private void assertExceptionMatch(Throwable exception, String source, ExceptionInfo exceptionInfo) {
|
||||
assertNotNull(exception, "Expected exception was not thrown: " + exceptionInfo.exception);
|
||||
if (exception instanceof EvalException) {
|
||||
EvalException ex = (EvalException) exception;
|
||||
String actualException = ex.getExceptionClassName();
|
||||
String expectedException = exceptionInfo.exception.getCanonicalName();
|
||||
assertEquals(expectedException, actualException,
|
||||
String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s",
|
||||
source, expectedException, actualException, getStackTrace(ex)));
|
||||
if (exceptionInfo.message != null) {
|
||||
assertEquals(exceptionInfo.message, ex.getMessage(),
|
||||
String.format("Given \"%s\" expected message: %s, got: %s",
|
||||
source, exceptionInfo.message, ex.getMessage()));
|
||||
}
|
||||
assertStackMatch(ex, source, exceptionInfo);
|
||||
if (exceptionInfo.cause != null) {
|
||||
assertAnyExceptionMatch(exception.getCause(), exceptionInfo.cause);
|
||||
}
|
||||
} else {
|
||||
fail("Unexpected exception: " + exception + " or exceptionInfo: " + exceptionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertStackMatch(JShellException exception, String source, AnyExceptionInfo exceptionInfo) {
|
||||
if (exceptionInfo.stackTraceElements != null) {
|
||||
assertStackTrace(exception.getStackTrace(), exceptionInfo.stackTraceElements,
|
||||
String.format("Given \"%s\"%nStack trace:%n%s%n",
|
||||
source, getStackTrace(exception)));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAnyExceptionMatch(Throwable exception, AnyExceptionInfo exceptionInfo) {
|
||||
if (exceptionInfo instanceof ExceptionInfo) {
|
||||
assertExceptionMatch(exception, "", (ExceptionInfo) exceptionInfo);
|
||||
} else {
|
||||
assertTrue(exceptionInfo instanceof UnresolvedExceptionInfo, "Bad exceptionInfo: " + exceptionInfo);
|
||||
assertTrue(exception instanceof UnresolvedReferenceException,
|
||||
"Expected UnresolvedReferenceException: " + exception);
|
||||
UnresolvedExceptionInfo uei = (UnresolvedExceptionInfo) exceptionInfo;
|
||||
UnresolvedReferenceException ure = (UnresolvedReferenceException) exception;
|
||||
assertEquals(uei.sn, ure.getSnippet());
|
||||
assertStackMatch(ure, "", exceptionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertStackTrace(StackTraceElement[] actual, StackTraceElement[] expected, String message) {
|
||||
if (actual != expected) {
|
||||
if (actual == null || expected == null) {
|
||||
fail(message);
|
||||
} else {
|
||||
assertEquals(expected.length, actual.length, message + " : arrays do not have the same size");
|
||||
for (int i = 0; i < actual.length; ++i) {
|
||||
StackTraceElement actualElement = actual[i];
|
||||
StackTraceElement expectedElement = expected[i];
|
||||
assertEquals(expectedElement.getClassName(), actualElement.getClassName(), message + " : class names [" + i + "]");
|
||||
String expectedMethodName = expectedElement.getMethodName();
|
||||
if (expectedMethodName.startsWith("lambda$")) {
|
||||
assertTrue(actualElement.getMethodName().startsWith("lambda$"), message + " : method names");
|
||||
} else {
|
||||
assertEquals(expectedElement.getMethodName(), actualElement.getMethodName(), message + " : method names [" + i + "]");
|
||||
}
|
||||
assertEquals(expectedElement.getFileName(), actualElement.getFileName(), message + " : file names [" + i + "]");
|
||||
if (expectedElement.getLineNumber() >= 0) {
|
||||
assertEquals(expectedElement.getLineNumber(), actualElement.getLineNumber(), message + " : line numbers [" + i + "]"
|
||||
+ " -- actual: " + actualElement.getLineNumber() + ", expected: " + expectedElement.getLineNumber() +
|
||||
" -- in: " + actualElement.getClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getStackTrace(Throwable ex) {
|
||||
StringWriter st = new StringWriter();
|
||||
ex.printStackTrace(new PrintWriter(st));
|
||||
return st.toString();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue