8020675: invalid jar file in the bootclasspath could lead to jvm fatal error
Summary: removed offending EXCEPTION_MARK calls and code cleanup
Reviewed-by: dholmes, iklam, coleenp, mseledtsov
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Mon Aug 26 07:01:23 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Mon Aug 26 14:11:26 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -197,7 +197,7 @@
}
-ClassFileStream* ClassPathDirEntry::open_stream(const char* name) {
+ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
// construct full path name
char path[JVM_MAXPATHLEN];
if (jio_snprintf(path, sizeof(path), "%s%s%s", _dir, os::file_separator(), name) == -1) {
@@ -240,7 +240,7 @@
FREE_C_HEAP_ARRAY(char, _zip_name, mtClass);
}
-ClassFileStream* ClassPathZipEntry::open_stream(const char* name) {
+ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
// enable call to C land
JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread);
@@ -284,24 +284,24 @@
}
}
-LazyClassPathEntry::LazyClassPathEntry(char* path, struct stat st) : ClassPathEntry() {
+LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st) : ClassPathEntry() {
_path = strdup(path);
- _st = st;
+ _st = *st;
_meta_index = NULL;
_resolved_entry = NULL;
+ _has_error = false;
}
bool LazyClassPathEntry::is_jar_file() {
return ((_st.st_mode & S_IFREG) == S_IFREG);
}
-ClassPathEntry* LazyClassPathEntry::resolve_entry() {
+ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) {
if (_resolved_entry != NULL) {
return (ClassPathEntry*) _resolved_entry;
}
ClassPathEntry* new_entry = NULL;
- ClassLoader::create_class_path_entry(_path, _st, &new_entry, false);
- assert(new_entry != NULL, "earlier code should have caught this");
+ new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, CHECK_NULL);
{
ThreadCritical tc;
if (_resolved_entry == NULL) {
@@ -314,12 +314,21 @@
return (ClassPathEntry*) _resolved_entry;
}
-ClassFileStream* LazyClassPathEntry::open_stream(const char* name) {
+ClassFileStream* LazyClassPathEntry::open_stream(const char* name, TRAPS) {
if (_meta_index != NULL &&
!_meta_index->may_contain(name)) {
return NULL;
}
- return resolve_entry()->open_stream(name);
+ if (_has_error) {
+ return NULL;
+ }
+ ClassPathEntry* cpe = resolve_entry(THREAD);
+ if (cpe == NULL) {
+ _has_error = true;
+ return NULL;
+ } else {
+ return cpe->open_stream(name, THREAD);
+ }
}
bool LazyClassPathEntry::is_lazy() {
@@ -465,20 +474,19 @@
}
}
-void ClassLoader::create_class_path_entry(char *path, struct stat st, ClassPathEntry **new_entry, bool lazy) {
+ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, bool lazy, TRAPS) {
JavaThread* thread = JavaThread::current();
if (lazy) {
- *new_entry = new LazyClassPathEntry(path, st);
- return;
+ return new LazyClassPathEntry(path, st);
}
- if ((st.st_mode & S_IFREG) == S_IFREG) {
+ ClassPathEntry* new_entry = NULL;
+ if ((st->st_mode & S_IFREG) == S_IFREG) {
// Regular file, should be a zip file
// Canonicalized filename
char canonical_path[JVM_MAXPATHLEN];
if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
// This matches the classic VM
- EXCEPTION_MARK;
- THROW_MSG(vmSymbols::java_io_IOException(), "Bad pathname");
+ THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
}
char* error_msg = NULL;
jzfile* zip;
@@ -489,7 +497,7 @@
zip = (*ZipOpen)(canonical_path, &error_msg);
}
if (zip != NULL && error_msg == NULL) {
- *new_entry = new ClassPathZipEntry(zip, path);
+ new_entry = new ClassPathZipEntry(zip, path);
if (TraceClassLoading) {
tty->print_cr("[Opened %s]", path);
}
@@ -504,16 +512,16 @@
msg = NEW_RESOURCE_ARRAY(char, len); ;
jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path);
}
- EXCEPTION_MARK;
- THROW_MSG(vmSymbols::java_lang_ClassNotFoundException(), msg);
+ THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
}
} else {
// Directory
- *new_entry = new ClassPathDirEntry(path);
+ new_entry = new ClassPathDirEntry(path);
if (TraceClassLoading) {
tty->print_cr("[Path %s]", path);
}
}
+ return new_entry;
}
@@ -572,13 +580,14 @@
}
}
-void ClassLoader::update_class_path_entry_list(const char *path,
+void ClassLoader::update_class_path_entry_list(char *path,
bool check_for_duplicates) {
struct stat st;
- if (os::stat((char *)path, &st) == 0) {
+ if (os::stat(path, &st) == 0) {
// File or directory found
ClassPathEntry* new_entry = NULL;
- create_class_path_entry((char *)path, st, &new_entry, LazyBootClassLoader);
+ Thread* THREAD = Thread::current();
+ new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, CHECK);
// The kernel VM adds dynamically to the end of the classloader path and
// doesn't reorder the bootclasspath which would break java.lang.Package
// (see PackageInfo).
@@ -897,7 +906,7 @@
PerfClassTraceTime::CLASS_LOAD);
ClassPathEntry* e = _first_entry;
while (e != NULL) {
- stream = e->open_stream(name);
+ stream = e->open_stream(name, CHECK_NULL);
if (stream != NULL) {
break;
}
@@ -1257,11 +1266,16 @@
}
void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) {
- resolve_entry()->compile_the_world(loader, CHECK);
+ ClassPathEntry* cpe = resolve_entry(THREAD);
+ if (cpe != NULL) {
+ cpe->compile_the_world(loader, CHECK);
+ }
}
bool LazyClassPathEntry::is_rt_jar() {
- return resolve_entry()->is_rt_jar();
+ Thread* THREAD = Thread::current();
+ ClassPathEntry* cpe = resolve_entry(THREAD);
+ return (cpe != NULL) ? cpe->is_jar_file() : false;
}
void ClassLoader::compile_the_world() {
--- a/hotspot/src/share/vm/classfile/classLoader.hpp Mon Aug 26 07:01:23 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp Mon Aug 26 14:11:26 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -63,7 +63,7 @@
ClassPathEntry();
// Attempt to locate file_name through this class path entry.
// Returns a class file parsing stream if successfull.
- virtual ClassFileStream* open_stream(const char* name) = 0;
+ virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
// Debugging
NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;)
NOT_PRODUCT(virtual bool is_rt_jar() = 0;)
@@ -77,7 +77,7 @@
bool is_jar_file() { return false; }
const char* name() { return _dir; }
ClassPathDirEntry(char* dir);
- ClassFileStream* open_stream(const char* name);
+ ClassFileStream* open_stream(const char* name, TRAPS);
// Debugging
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
NOT_PRODUCT(bool is_rt_jar();)
@@ -107,7 +107,7 @@
const char* name() { return _zip_name; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
~ClassPathZipEntry();
- ClassFileStream* open_stream(const char* name);
+ ClassFileStream* open_stream(const char* name, TRAPS);
void contents_do(void f(const char* name, void* context), void* context);
// Debugging
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
@@ -125,13 +125,14 @@
char* _path; // dir or file
struct stat _st;
MetaIndex* _meta_index;
+ bool _has_error;
volatile ClassPathEntry* _resolved_entry;
- ClassPathEntry* resolve_entry();
+ ClassPathEntry* resolve_entry(TRAPS);
public:
bool is_jar_file();
const char* name() { return _path; }
- LazyClassPathEntry(char* path, struct stat st);
- ClassFileStream* open_stream(const char* name);
+ LazyClassPathEntry(char* path, const struct stat* st);
+ ClassFileStream* open_stream(const char* name, TRAPS);
void set_meta_index(MetaIndex* meta_index) { _meta_index = meta_index; }
virtual bool is_lazy();
// Debugging
@@ -207,14 +208,15 @@
static void setup_meta_index();
static void setup_bootstrap_search_path();
static void load_zip_library();
- static void create_class_path_entry(char *path, struct stat st, ClassPathEntry **new_entry, bool lazy);
+ static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st,
+ bool lazy, TRAPS);
// Canonicalizes path names, so strcmp will work properly. This is mainly
// to avoid confusing the zip library
static bool get_canonical_path(char* orig, char* out, int len);
public:
// Used by the kernel jvm.
- static void update_class_path_entry_list(const char *path,
+ static void update_class_path_entry_list(char *path,
bool check_for_duplicates);
static void print_bootclasspath();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/LoadClass/LoadClassNegative.java Mon Aug 26 14:11:26 2013 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 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
+ * @key regression
+ * @bug 8020675
+ * @summary make sure there is no fatal error if a class is loaded from an invalid jar file which is in the bootclasspath
+ * @library /testlibrary
+ * @build TestForName
+ * @build LoadClassNegative
+ * @run main LoadClassNegative
+ */
+
+import java.io.File;
+import com.oracle.java.testlibrary.*;
+
+public class LoadClassNegative {
+
+ public static void main(String args[]) throws Exception {
+ String bootCP = "-Xbootclasspath/a:" + System.getProperty("test.src")
+ + File.separator + "dummy.jar";
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ bootCP,
+ "TestForName");
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("ClassNotFoundException");
+ output.shouldHaveExitValue(0);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/LoadClass/TestForName.java Mon Aug 26 14:11:26 2013 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, 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 TestForName {
+ public static void main(String[] args) {
+ try {
+ Class cls = Class.forName("xxx");
+ System.out.println("Class = " + cls.getName());
+ } catch (ClassNotFoundException cnfe) {
+ cnfe.printStackTrace();
+ }
+ }
+}