8298065: Provide more information in message of NoSuchFieldError

Reviewed-by: dholmes, iklam, coleenp
This commit is contained in:
Matias Saavedra Silva 2023-01-11 19:13:26 +00:00 committed by Coleen Phillimore
parent a17b563f54
commit 43847c43ad
9 changed files with 357 additions and 3 deletions

@ -975,7 +975,11 @@ void LinkResolver::resolve_field(fieldDescriptor& fd,
// check if field exists; i.e., if a klass containing the field def has been selected
if (sel_klass == NULL) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
stringStream ss;
ss.print("Class %s does not have member field '", resolved_klass->external_name());
sig->print_as_field_external_type(&ss);
ss.print(" %s'", field->as_C_string());
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), ss.as_string());
}
// Access checking may be turned off when calling from within the VM.

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, 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
@ -294,6 +294,25 @@ void Symbol::print_as_signature_external_parameters(outputStream *os) {
}
}
void Symbol::print_as_field_external_type(outputStream *os) {
SignatureStream ss(this, false);
assert(!ss.is_done(), "must have at least one element in field ref");
assert(!ss.at_return_type(), "field ref cannot be a return type");
assert(!Signature::is_method(this), "field ref cannot be a method");
if (ss.is_array()) {
print_array(os, ss);
} else if (ss.is_reference()) {
print_class(os, ss);
} else {
os->print("%s", type2name(ss.type()));
}
#ifdef ASSERT
ss.next();
assert(ss.is_done(), "must have at most one element in field ref");
#endif
}
// Increment refcount while checking for zero. If the Symbol's refcount becomes zero
// a thread could be concurrently removing the Symbol. This is used during SymbolTable
// lookup to avoid reviving a dead Symbol.

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, 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
@ -275,6 +275,7 @@ class Symbol : public MetaspaceObj {
// separated by ', ' to the outputStream. Prints external names as
// 'double' or 'java.lang.Object[][]'.
void print_as_signature_external_parameters(outputStream *os);
void print_as_field_external_type(outputStream *os);
void metaspace_pointers_do(MetaspaceClosure* it);
MetaspaceObj::Type type() const { return SymbolType; }

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023, 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.
*/
/*
public class NoSuchFieldArray {
static char[] z;
public NoSuchFieldArray() {
z = new char[1];
}
}
*/
super public class NoSuchFieldArray
version 65:0
{
// REMOVED static Field z:"[C";
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
iconst_1;
newarray char;
putstatic Field z:"[C";
return;
}
} // end Class NoSuchFieldArray

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023, 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.
*/
/*
public class NoSuchFieldMultiArray {
static double[][] a;
public NoSuchFieldMultiArray() {
a = new double[1][1];
}
}
*/
super public class NoSuchFieldMultiArray
version 65:0
{
// REMOVED static Field a:"[[D";
public Method "<init>":"()V"
stack 2 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
iconst_1;
iconst_1;
multianewarray class "[[D", 2;
putstatic Field a:"[[D";
return;
}
} // end Class NoSuchFieldMultiArray

@ -0,0 +1,108 @@
/*
* Copyright (c) 2023, 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 8298065
* @summary Test output of NoSuchFieldError when field signature does not match
* @compile NoSuchFieldPrimitive.jasm NoSuchFieldReference.jasm TestClass.java
* @compile NoSuchFieldArray.jasm NoSuchFieldMultiArray.jasm
* @run main NoSuchFieldOutputTest
*/
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Tests the output text of NoSuchFieldError
public class NoSuchFieldOutputTest {
public static void main(java.lang.String[] unused) throws Exception {
try {
Class.forName("NoSuchFieldPrimitive").newInstance();
} catch (NoSuchFieldError nsfe) {
testNoSuchFieldOutput(nsfe, "primitive");
}
try {
Class.forName("NoSuchFieldReference").newInstance();
} catch (NoSuchFieldError nsfe) {
testNoSuchFieldOutput(nsfe, "reference");
}
try {
Class.forName("NoSuchFieldArray").newInstance();
} catch (NoSuchFieldError nsfe) {
testNoSuchFieldOutput(nsfe, "array");
}
try {
Class.forName("NoSuchFieldMultiArray").newInstance();
} catch (NoSuchFieldError nsfe) {
testNoSuchFieldOutput(nsfe, "multiArray");
}
}
private static void testNoSuchFieldOutput(NoSuchFieldError nsfe, String testType) throws Exception {
Pattern noSuchFieldPattern = Pattern.compile("Class (?<classname>[\\w\\d]+) does not have member field '(?<signature>[\\S]+) (?<varname>[\\w\\d]+)'");
String output = nsfe.getMessage();
Matcher noSuchFieldMatcher = noSuchFieldPattern.matcher(output);
if (noSuchFieldMatcher.matches()) {
switch (testType) {
case "primitive":
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldPrimitive", "int", "x");
break;
case "reference":
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldReference", "TestClass", "y");
break;
case "array":
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldArray", "char[]", "z");
break;
case "multiArray":
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldMultiArray", "double[][]", "a");
break;
default:
throwTestException("No matching test", output);
}
} else {
throwTestException("Output format does not match", output);
}
System.out.println(output);
}
private static void checkOutputGroups(Matcher noSuchFieldMatcher, String output,
String testClass, String testSig, String testVar) throws Exception {
String classname = noSuchFieldMatcher.group("classname");
String signature = noSuchFieldMatcher.group("signature");
String varname = noSuchFieldMatcher.group("varname");
if (!classname.equals(testClass)) {
throwTestException("Failed to match class name", output);
}
if (!signature.equals(testSig)) {
throwTestException("Failed to match type signature", output);
}
if (!varname.equals(testVar)) {
throwTestException("Failed to match field name", output);
}
}
private static void throwTestException(String reason, String output) throws Exception {
throw new Exception(reason + " . Stdout is :\n" + output);
}
}

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023, 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.
*/
/*
public class NoSuchFieldPrimitive {
// static int x;
public NoSuchFieldPrimitive() {
x = 123;
}
}
*/
super public class NoSuchFieldPrimitive
version 65:0
{
// REMOVED static Field x:I;
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
bipush 123;
putstatic Field x:"I";
return;
}
} // end Class NoSuchFieldPrimitive

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023, 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.
*/
/*
public class NoSuchFieldReference {
static TestClass y;
public NoSuchFieldReference() {
y = new TestClass();
}
}
*/
super public class NoSuchFieldReference
version 65:0
{
// REMOVED static Field y:"LTestClass;";
public Method "<init>":"()V"
stack 2 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
new class TestClass;
dup;
invokespecial Method TestClass."<init>":"()V";
putstatic Field y:"LTestClass;";
return;
}
} // end Class NoSuchFieldReference

@ -0,0 +1,25 @@
/*
* Copyright (c) 2023, 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.
*/
// Used as a reference type for a field in NoSuchFieldReference.jasm
public class TestClass {}