8202913: loader constraint message for fields specifies incorrect referring class

Improve the message to display the right referring class.

Reviewed-by: acorn, goetz, dholmes
This commit is contained in:
Harold Seigel 2018-05-31 10:38:06 -04:00
parent fcb805f9a6
commit d892ac8d4c
8 changed files with 349 additions and 10 deletions

View File

@ -688,19 +688,21 @@ void LinkResolver::check_field_loader_constraints(Symbol* field, Symbol* sig,
CHECK);
if (failed_type_symbol != NULL) {
const char* msg = "loader constraint violation: when resolving field"
" \"%s\" the class loader %s of the referring class, "
"%s, and the class loader %s for the field's resolved "
"type, %s, have different Class objects for that type";
char* field_name = field->as_C_string();
" \"%s\" of type %s, the class loader %s of the current class, "
"%s, and the class loader %s for the field's defining "
"type, %s, have different Class objects for type %s";
const char* field_name = field->as_C_string();
const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
char* sel = sel_klass->name()->as_C_string();
const char* sel = sel_klass->external_name();
const char* loader2_name = java_lang_ClassLoader::describe_external(sel_loader());
char* failed_type_name = failed_type_symbol->as_C_string();
size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1_name) +
strlen(sel) + strlen(loader2_name) + strlen(failed_type_name) + 1;
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
const char* curr_klass_name = current_klass->external_name();
size_t buflen = strlen(msg) + strlen(field_name) + 2 * strlen(failed_type_name) +
strlen(loader1_name) + strlen(curr_klass_name) +
strlen(loader2_name) + strlen(sel) + 1;
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
jio_snprintf(buf, buflen, msg, field_name, loader1_name, sel, loader2_name,
failed_type_name);
jio_snprintf(buf, buflen, msg, field_name, failed_type_name, loader1_name,
curr_klass_name, loader2_name, sel, failed_type_name);
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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
* @compile pkg/Grand.java pkg/Parent.java pkg/ClassLoaderForParentFoo.java
* @compile pkg/ClassLoaderForChildGrandFoo.java pkg/Child.jasm
* @run main/othervm LdrCnstrFldMsgTest
*/
import java.lang.reflect.Method;
// Check that LinkageError loader constraint message for fields contains the
// correct information.
//
// The test creates two class loaders. The first class loader loads classes
// Child, Foo, and Grand. The second class loader loads Parent and Foo. Class
// Parent is a sub-class of Grand and class Child is a sub-class of Parent.
// Class Child tries to load Parent._field1. This should fail because type Foo
// for Parent._field1 is a different type than Child's Foo.
//
public class LdrCnstrFldMsgTest {
public static void main(String... args) throws Exception {
ClassLoader l = new pkg.ClassLoaderForChildGrandFoo("pkg.Foo", "pkg.Child", "pkg.Grand");
l.loadClass("pkg.Foo");
// Try to call a public method in Grand.
Runnable r = (Runnable) l.loadClass("pkg.Child").newInstance();
try {
r.run();
throw new RuntimeException("Expected LinkageError exception not thrown");
} catch (java.lang.LinkageError e) {
if (!e.getMessage().contains("for the field's defining type, pkg.Parent,") ||
!e.getMessage().contains("have different Class objects for type pkg.Foo")) {
throw new RuntimeException("Wrong LinkageError exception thrown: " + e.toString());
}
}
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.
*
*/
package pkg;
// The getfield of Parent._field1 gets a LinkageError because class Parent
// has a different Foo class than Child, causing a loader constraint violation.
super public class Child extends pkg/Parent implements java/lang/Runnable version 50:0 {
public Method "<init>":"()V" stack 1 locals 1 {
aload_0;
invokespecial Method pkg/Parent."<init>":"()V";
return;
}
public Method run:"()V" stack 4 locals 4 {
ldc class pkg/Foo;
astore_1;
new class pkg/Child;
dup;
invokespecial Method pkg/Child."<init>":"()V";
astore_2;
aload_2;
getstatic Field pkg/Parent._field1:"Lpkg/Foo;";
pop;
return;
}
} // end Class Child

View File

@ -0,0 +1,73 @@
/*
* 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.
*
*/
package pkg;
import java.util.*;
import java.io.*;
// This class loader loads Foo, Child, and Grand.
public class ClassLoaderForChildGrandFoo extends ClassLoader {
ClassLoader l2 = null;
private final Set<String> names = new HashSet<>();
public ClassLoaderForChildGrandFoo(String... names) {
for (String n : names) this.names.add(n);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// Create class loader l2 to load Parent and Foo. And, pass this class
// loader to l2 so l2 can use it to load Grand.
if (name.contains("Parent") && l2 == null) {
l2 = new ClassLoaderForParentFoo(this, "pkg.Foo", "pkg.Grand", "pkg.Parent");
Class<?> b = l2.loadClass("pkg.Parent");
return b;
}
if (!names.contains(name)) return super.loadClass(name, resolve);
Class<?> result = findLoadedClass(name);
if (result == null) {
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) throw new ClassNotFoundException();
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) buffer.write(b);
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
} catch (IOException e) {
throw new ClassNotFoundException("Error reading class file", e);
}
}
if (resolve) resolveClass(result);
return result;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.
*
*/
package pkg;
import java.util.*;
import java.io.*;
// This class loader loads Foo and Parent and calls back to l1 to load Grand.
public class ClassLoaderForParentFoo extends ClassLoader {
private final Set<String> names = new HashSet<>();
ClassLoader l1;
public ClassLoaderForParentFoo(ClassLoader l, String... names) {
l1 = l;
for (String n : names) this.names.add(n);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.contains("Grand")) return l1.loadClass("pkg.Grand");
if (!names.contains(name)) return super.loadClass(name, resolve);
Class<?> result = findLoadedClass(name);
if (result == null) {
// Load our own version of Foo that will be referenced by Parent.
if (name.contains("Parent")) loadClass("pkg.Foo", resolve);
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) throw new ClassNotFoundException();
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) buffer.write(b);
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
} catch (IOException e) {
throw new ClassNotFoundException("Error reading class file", e);
}
}
if (resolve) resolveClass(result);
return result;
}
}

View File

@ -0,0 +1,27 @@
/*
* 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.
*
*/
package pkg;
public class Foo {}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
*/
package pkg;
public class Grand {
public static Foo _field1;
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
*/
package pkg;
public class Parent extends Grand {
public static Foo _field1;
}