From 651e15fda63ec190b99092e9dd38ba8003f39eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Tue, 28 Jun 2016 10:37:52 +0200 Subject: [PATCH 01/43] 8159890: SIGSEGV with UseStringDeduplication and UseSharedSpaces/RequireSharedSpaces Co-authored-by: Ioi Lam Reviewed-by: stefank, drwhite, tschatzl, jiangli, iklam --- .../share/vm/classfile/compactHashtable.cpp | 2 +- .../SharedArchiveFile/SharedStringsDedup.java | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/runtime/SharedArchiveFile/SharedStringsDedup.java diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp index f2feec3c810..a9b6b28f365 100644 --- a/hotspot/src/share/vm/classfile/compactHashtable.cpp +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp @@ -248,7 +248,7 @@ inline void SimpleCompactHashtable::iterate(const I& iterator) { } else { u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]); while (entry < entry_max) { - iterator.do_value(_base_address, entry[0]); + iterator.do_value(_base_address, entry[1]); entry += 2; } } diff --git a/hotspot/test/runtime/SharedArchiveFile/SharedStringsDedup.java b/hotspot/test/runtime/SharedArchiveFile/SharedStringsDedup.java new file mode 100644 index 00000000000..432b36bffd8 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/SharedStringsDedup.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, 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 SharedStringsDedup + * @summary Test -Xshare:auto with shared strings and -XX:+UseStringDeduplication + * Feature support: G1GC only, compressed oops/kptrs, 64-bit os, not on windows + * @requires (sun.arch.data.model != "32") & (os.family != "windows") + * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true) + * @requires vm.gc.G1 + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * @run main SharedStringsDedup + */ + +import jdk.test.lib.*; +import java.io.File; + +// The main purpose is to test the interaction between shared strings +// and -XX:+UseStringDeduplication. We run in -Xshare:auto mode so +// we don't need to worry about CDS archive mapping failure (which +// doesn't happen often so it won't impact coverage). +public class SharedStringsDedup { + public static void main(String[] args) throws Exception { + // Dump + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./SharedStringsDedup.jsa", + "-XX:+UseCompressedOops", "-XX:+UseG1GC", + "-XX:+PrintSharedSpaces", + "-Xshare:dump"); + + new OutputAnalyzer(pb.start()) + .shouldContain("Loading classes to share") + .shouldContain("Shared string table stats") + .shouldHaveExitValue(0); + + // Run with -Xshare:auto + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./SharedStringsDedup.jsa", + "-XX:+UseCompressedOops", "-XX:+UseG1GC", + "-XX:+UseStringDeduplication", + "-Xshare:auto", + "-version"); + + new OutputAnalyzer(pb.start()) + .shouldMatch("(java|openjdk) version") + .shouldHaveExitValue(0); + } +} From 92eb334c91899599823d6d33fd4a60c6bc088c97 Mon Sep 17 00:00:00 2001 From: Lois Foltan Date: Tue, 28 Jun 2016 10:11:01 -0400 Subject: [PATCH 02/43] 8159262: Walking PackageEntry Export and ModuleEntry Reads Must Occur Only When Neccessary And Wait Until ClassLoader's Aliveness Determined Fixed an issue in class unloading to delay walk until class loader's aliveness is determined of modularity lists to remove dead modules Reviewed-by: coleenp, dholmes, sspitsyn, zgu --- .../share/vm/classfile/classLoaderData.cpp | 42 ++++-- .../share/vm/classfile/classLoaderData.hpp | 2 + .../src/share/vm/classfile/moduleEntry.cpp | 52 ++++++- .../src/share/vm/classfile/moduleEntry.hpp | 43 +++--- hotspot/src/share/vm/classfile/modules.cpp | 4 +- .../src/share/vm/classfile/packageEntry.cpp | 59 +++++++- .../src/share/vm/classfile/packageEntry.hpp | 3 + .../share/vm/classfile/systemDictionary.cpp | 15 +- .../share/vm/classfile/systemDictionary.hpp | 1 + .../ModuleStress/CustomSystemClassLoader.java | 35 +++++ .../ModuleStress/ModuleNonBuiltinCLMain.java | 129 +++++++++++++++++ .../ModuleStress/ModuleSameCLMain.java | 109 +++++++++++++++ .../modules/ModuleStress/ModuleStress.java | 131 ++++++++++++++++++ .../modules/ModuleStress/ModuleStressGC.java | 84 +++++++++++ .../src/jdk.test/test/MainGC.java | 114 +++++++++++++++ .../src/jdk.translet/translet/MainGC.java | 30 ++++ 16 files changed, 807 insertions(+), 46 deletions(-) create mode 100644 hotspot/test/runtime/modules/ModuleStress/CustomSystemClassLoader.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/ModuleStress.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/ModuleStressGC.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/src/jdk.test/test/MainGC.java create mode 100644 hotspot/test/runtime/modules/ModuleStress/src/jdk.translet/translet/MainGC.java diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 7635879a49a..f0fdc648095 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -501,13 +501,26 @@ ClassLoaderData::~ClassLoaderData() { } } -/** - * Returns true if this class loader data is for the platform class loader. - */ +// Returns true if this class loader data is for the system class loader. +bool ClassLoaderData::is_system_class_loader_data() const { + return SystemDictionary::is_system_class_loader(class_loader()); +} + +// Returns true if this class loader data is for the platform class loader. bool ClassLoaderData::is_platform_class_loader_data() const { return SystemDictionary::is_platform_class_loader(class_loader()); } +// Returns true if this class loader data is one of the 3 builtin +// (boot, application/system or platform) class loaders. Note, the +// builtin loaders are not freed by a GC. +bool ClassLoaderData::is_builtin_class_loader_data() const { + Handle classLoaderHandle = class_loader(); + return (is_the_null_class_loader_data() || + SystemDictionary::is_system_class_loader(classLoaderHandle) || + SystemDictionary::is_platform_class_loader(classLoaderHandle)); +} + Metaspace* ClassLoaderData::metaspace_non_null() { assert(!DumpSharedSpaces, "wrong metaspace!"); // If the metaspace has not been allocated, create a new one. Might want @@ -957,12 +970,6 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, data = _head; while (data != NULL) { if (data->is_alive(is_alive_closure)) { - if (data->packages_defined()) { - data->packages()->purge_all_package_exports(); - } - if (data->modules_defined()) { - data->modules()->purge_all_module_reads(); - } // clean metaspace if (walk_all_metadata) { data->classes_do(InstanceKlass::purge_previous_versions); @@ -990,6 +997,23 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, } if (seen_dead_loader) { + // Walk a ModuleEntry's reads and a PackageEntry's exports lists + // to determine if there are modules on those lists that are now + // dead and should be removed. A module's life cycle is equivalent + // to its defining class loader's life cycle. Since a module is + // considered dead if its class loader is dead, these walks must + // occur after each class loader's aliveness is determined. + data = _head; + while (data != NULL) { + if (data->packages_defined()) { + data->packages()->purge_all_package_exports(); + } + if (data->modules_defined()) { + data->modules()->purge_all_module_reads(); + } + data = data->next(); + } + post_class_unload_events(); } diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index 9fc9839b7cf..602097935cc 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -270,7 +270,9 @@ class ClassLoaderData : public CHeapObj { bool is_the_null_class_loader_data() const { return this == _the_null_class_loader_data; } + bool is_system_class_loader_data() const; bool is_platform_class_loader_data() const; + bool is_builtin_class_loader_data() const; // The Metaspace is created lazily so may be NULL. This // method will allocate a Metaspace if needed. diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp index c507584c712..a05c1644b92 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp @@ -40,7 +40,6 @@ ModuleEntry* ModuleEntryTable::_javabase_module = NULL; - void ModuleEntry::set_location(Symbol* location) { if (_location != NULL) { // _location symbol's refcounts are managed by ModuleEntry, @@ -115,10 +114,35 @@ void ModuleEntry::add_read(ModuleEntry* m) { // Lazily create a module's reads list _reads = new (ResourceObj::C_HEAP, mtModule)GrowableArray(MODULE_READS_SIZE, true); } + + // Determine, based on this newly established read edge to module m, + // if this module's read list should be walked at a GC safepoint. + set_read_walk_required(m->loader_data()); + + // Establish readability to module m _reads->append_if_missing(m); } } +// If the module's loader, that a read edge is being established to, is +// not the same loader as this module's and is not one of the 3 builtin +// class loaders, then this module's reads list must be walked at GC +// safepoint. Modules have the same life cycle as their defining class +// loaders and should be removed if dead. +void ModuleEntry::set_read_walk_required(ClassLoaderData* m_loader_data) { + assert_locked_or_safepoint(Module_lock); + if (!_must_walk_reads && + loader_data() != m_loader_data && + !m_loader_data->is_builtin_class_loader_data()) { + _must_walk_reads = true; + if (log_is_enabled(Trace, modules)) { + ResourceMark rm; + log_trace(modules)("ModuleEntry::set_read_walk_required(): module %s reads list must be walked", + (name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE); + } + } +} + bool ModuleEntry::has_reads() const { assert_locked_or_safepoint(Module_lock); return ((_reads != NULL) && !_reads->is_empty()); @@ -127,14 +151,28 @@ bool ModuleEntry::has_reads() const { // Purge dead module entries out of reads list. void ModuleEntry::purge_reads() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - if (has_reads()) { + + if (_must_walk_reads && has_reads()) { + // This module's _must_walk_reads flag will be reset based + // on the remaining live modules on the reads list. + _must_walk_reads = false; + + if (log_is_enabled(Trace, modules)) { + ResourceMark rm; + log_trace(modules)("ModuleEntry::purge_reads(): module %s reads list being walked", + (name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE); + } + // Go backwards because this removes entries that are dead. int len = _reads->length(); for (int idx = len - 1; idx >= 0; idx--) { ModuleEntry* module_idx = _reads->at(idx); - ClassLoaderData* cld = module_idx->loader(); - if (cld->is_unloading()) { + ClassLoaderData* cld_idx = module_idx->loader_data(); + if (cld_idx->is_unloading()) { _reads->delete_at(idx); + } else { + // Update the need to walk this module's reads based on live modules + set_read_walk_required(cld_idx); } } } @@ -248,7 +286,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle entry->set_module(loader_data->add_handle(module_handle)); } - entry->set_loader(loader_data); + entry->set_loader_data(loader_data); entry->set_version(version); entry->set_location(location); @@ -379,7 +417,7 @@ void ModuleEntry::print(outputStream* st) { p2i(this), name() == NULL ? UNNAMED_MODULE : name()->as_C_string(), p2i(module()), - loader()->loader_name(), + loader_data()->loader_name(), version() != NULL ? version()->as_C_string() : "NULL", location() != NULL ? location()->as_C_string() : "NULL", BOOL_TO_STR(!can_read_all_unnamed()), p2i(next())); @@ -401,5 +439,5 @@ void ModuleEntryTable::verify() { } void ModuleEntry::verify() { - guarantee(loader() != NULL, "A module entry must be associated with a loader."); + guarantee(loader_data() != NULL, "A module entry must be associated with a loader."); } diff --git a/hotspot/src/share/vm/classfile/moduleEntry.hpp b/hotspot/src/share/vm/classfile/moduleEntry.hpp index 9b68c01d424..8ec8237ec3f 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp @@ -43,6 +43,7 @@ class ModuleClosure; // It contains: // - Symbol* containing the module's name. // - pointer to the java.lang.reflect.Module for this module. +// - pointer to the java.security.ProtectionDomain shared by classes defined to this module. // - ClassLoaderData*, class loader of this module. // - a growable array containg other module entries that this module can read. // - a flag indicating if this module can read all unnamed modules. @@ -54,56 +55,58 @@ private: jobject _module; // java.lang.reflect.Module jobject _pd; // java.security.ProtectionDomain, cached // for shared classes from this module - ClassLoaderData* _loader; + ClassLoaderData* _loader_data; GrowableArray* _reads; // list of modules that are readable by this module Symbol* _version; // module version number Symbol* _location; // module location bool _can_read_all_unnamed; bool _has_default_read_edges; // JVMTI redefine/retransform support + bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules TRACE_DEFINE_TRACE_ID_FIELD; enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read. public: void init() { _module = NULL; - _loader = NULL; + _loader_data = NULL; _pd = NULL; _reads = NULL; _version = NULL; _location = NULL; _can_read_all_unnamed = false; _has_default_read_edges = false; + _must_walk_reads = false; } - Symbol* name() const { return literal(); } - void set_name(Symbol* n) { set_literal(n); } + Symbol* name() const { return literal(); } + void set_name(Symbol* n) { set_literal(n); } - jobject module() const { return _module; } - void set_module(jobject j) { _module = j; } + jobject module() const { return _module; } + void set_module(jobject j) { _module = j; } // The shared ProtectionDomain reference is set once the VM loads a shared class // originated from the current Module. The referenced ProtectionDomain object is // created by the ClassLoader when loading a class (shared or non-shared) from the // Module for the first time. This ProtectionDomain object is used for all // classes from the Module loaded by the same ClassLoader. - Handle shared_protection_domain(); - void set_shared_protection_domain(ClassLoaderData *loader_data, - Handle pd); + Handle shared_protection_domain(); + void set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd); - ClassLoaderData* loader() const { return _loader; } - void set_loader(ClassLoaderData* l) { _loader = l; } + ClassLoaderData* loader_data() const { return _loader_data; } + void set_loader_data(ClassLoaderData* l) { _loader_data = l; } - Symbol* version() const { return _version; } - void set_version(Symbol* version); + Symbol* version() const { return _version; } + void set_version(Symbol* version); - Symbol* location() const { return _location; } - void set_location(Symbol* location); + Symbol* location() const { return _location; } + void set_location(Symbol* location); - bool can_read(ModuleEntry* m) const; - bool has_reads() const; - void add_read(ModuleEntry* m); + bool can_read(ModuleEntry* m) const; + bool has_reads() const; + void add_read(ModuleEntry* m); + void set_read_walk_required(ClassLoaderData* m_loader_data); - bool is_named() const { return (literal() != NULL); } + bool is_named() const { return (name() != NULL); } bool can_read_all_unnamed() const { assert(is_named() || _can_read_all_unnamed == true, @@ -178,7 +181,7 @@ private: ModuleEntry* _unnamed_module; ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version, - Symbol* location, ClassLoaderData* class_loader); + Symbol* location, ClassLoaderData* loader_data); void add_entry(int index, ModuleEntry* new_entry); int entry_size() const { return BasicHashtable::entry_size(); } diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index de8aac056b7..cd0937267f8 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -113,7 +113,7 @@ static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring packag const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); if (package_name == NULL) return NULL; TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL); - PackageEntryTable* package_entry_table = module_entry->loader()->packages(); + PackageEntryTable* package_entry_table = module_entry->loader_data()->packages(); assert(package_entry_table != NULL, "Unexpected null package entry table"); return package_entry_table->lookup_only(pkg_symbol); } @@ -868,7 +868,7 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { package_name, module_entry->name()->as_C_string()); TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); - PackageEntryTable* package_table = module_entry->loader()->packages(); + PackageEntryTable* package_table = module_entry->loader_data()->packages(); assert(package_table != NULL, "Missing package_table"); bool pkg_exists = false; diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp index 11cc5ea71aa..d224941c32d 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.cpp +++ b/hotspot/src/share/vm/classfile/packageEntry.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/packageEntry.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" @@ -53,12 +54,40 @@ void PackageEntry::add_qexport(ModuleEntry* m) { if (!has_qual_exports_list()) { // Lazily create a package's qualified exports list. // Initial size is small, do not anticipate export lists to be large. - _qualified_exports = - new (ResourceObj::C_HEAP, mtModule) GrowableArray(QUAL_EXP_SIZE, true); + _qualified_exports = new (ResourceObj::C_HEAP, mtModule) GrowableArray(QUAL_EXP_SIZE, true); } + + // Determine, based on this newly established export to module m, + // if this package's export list should be walked at a GC safepoint. + set_export_walk_required(m->loader_data()); + + // Establish exportability to module m _qualified_exports->append_if_missing(m); } +// If the module's loader, that an export is being established to, is +// not the same loader as this module's and is not one of the 3 builtin +// class loaders, then this package's export list must be walked at GC +// safepoint. Modules have the same life cycle as their defining class +// loaders and should be removed if dead. +void PackageEntry::set_export_walk_required(ClassLoaderData* m_loader_data) { + assert_locked_or_safepoint(Module_lock); + ModuleEntry* this_pkg_mod = module(); + if (!_must_walk_exports && + (this_pkg_mod == NULL || this_pkg_mod->loader_data() != m_loader_data) && + !m_loader_data->is_builtin_class_loader_data()) { + _must_walk_exports = true; + if (log_is_enabled(Trace, modules)) { + ResourceMark rm; + assert(name() != NULL, "PackageEntry without a valid name"); + log_trace(modules)("PackageEntry::set_export_walk_required(): package %s defined in module %s, exports list must be walked", + name()->as_C_string(), + (this_pkg_mod == NULL || this_pkg_mod->name() == NULL) ? + UNNAMED_MODULE : this_pkg_mod->name()->as_C_string()); + } + } +} + // Set the package's exported states based on the value of the ModuleEntry. void PackageEntry::set_exported(ModuleEntry* m) { MutexLocker m1(Module_lock); @@ -96,14 +125,34 @@ void PackageEntry::set_is_exported_allUnnamed() { // Remove dead module entries within the package's exported list. void PackageEntry::purge_qualified_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - if (_qualified_exports != NULL) { + if (_must_walk_exports && + _qualified_exports != NULL && + !_qualified_exports->is_empty()) { + ModuleEntry* pkg_module = module(); + + // This package's _must_walk_exports flag will be reset based + // on the remaining live modules on the exports list. + _must_walk_exports = false; + + if (log_is_enabled(Trace, modules)) { + ResourceMark rm; + assert(name() != NULL, "PackageEntry without a valid name"); + ModuleEntry* pkg_mod = module(); + log_trace(modules)("PackageEntry::purge_qualified_exports(): package %s defined in module %s, exports list being walked", + name()->as_C_string(), + (pkg_mod == NULL || pkg_mod->name() == NULL) ? UNNAMED_MODULE : pkg_mod->name()->as_C_string()); + } + // Go backwards because this removes entries that are dead. int len = _qualified_exports->length(); for (int idx = len - 1; idx >= 0; idx--) { ModuleEntry* module_idx = _qualified_exports->at(idx); - ClassLoaderData* cld = module_idx->loader(); - if (cld->is_unloading()) { + ClassLoaderData* cld_idx = module_idx->loader_data(); + if (cld_idx->is_unloading()) { _qualified_exports->delete_at(idx); + } else { + // Update the need to walk this package's exports based on live modules + set_export_walk_required(cld_idx); } } } diff --git a/hotspot/src/share/vm/classfile/packageEntry.hpp b/hotspot/src/share/vm/classfile/packageEntry.hpp index e1bf62b3aa4..a379bf9de3b 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.hpp +++ b/hotspot/src/share/vm/classfile/packageEntry.hpp @@ -69,6 +69,7 @@ private: s2 _classpath_index; bool _is_exported_unqualified; bool _is_exported_allUnnamed; + bool _must_walk_exports; GrowableArray* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint GrowableArray* _qualified_exports; TRACE_DEFINE_TRACE_ID_FIELD; @@ -82,6 +83,7 @@ public: _classpath_index = -1; _is_exported_unqualified = false; _is_exported_allUnnamed = false; + _must_walk_exports = false; _exported_pending_delete = NULL; _qualified_exports = NULL; } @@ -147,6 +149,7 @@ public: // add the module to the package's qualified exports void add_qexport(ModuleEntry* m); + void set_export_walk_required(ClassLoaderData* m_loader_data); PackageEntry* next() const { return (PackageEntry*)HashtableEntry::next(); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index aaa2ad5dda1..b747fae54f2 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -175,9 +175,18 @@ bool SystemDictionary::is_parallelDefine(Handle class_loader) { return false; } -/** - * Returns true if the passed class loader is the platform class loader. - */ +// Returns true if the passed class loader is the builtin application class loader +// or a custom system class loader. A customer system class loader can be +// specified via -Djava.system.class.loader. +bool SystemDictionary::is_system_class_loader(Handle class_loader) { + if (class_loader.is_null()) { + return false; + } + return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() || + class_loader() == _java_system_loader); +} + +// Returns true if the passed class loader is the platform class loader. bool SystemDictionary::is_platform_class_loader(Handle class_loader) { if (class_loader.is_null()) { return false; diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 3626d881736..76a0b0772e9 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -660,6 +660,7 @@ public: static instanceKlassHandle load_shared_class(Symbol* class_name, Handle class_loader, TRAPS); + static bool is_system_class_loader(Handle class_loader); static bool is_platform_class_loader(Handle class_loader); protected: diff --git a/hotspot/test/runtime/modules/ModuleStress/CustomSystemClassLoader.java b/hotspot/test/runtime/modules/ModuleStress/CustomSystemClassLoader.java new file mode 100644 index 00000000000..dca359f6458 --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/CustomSystemClassLoader.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 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. + */ + +/** + * A custom system ClassLoader to define the module "m2" to during iterations of + * differing test runs within the test ModuleStress.java + */ +public class CustomSystemClassLoader extends ClassLoader { + public CustomSystemClassLoader() { + super(); + } + public CustomSystemClassLoader(ClassLoader parent) { + super(parent); + } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java b/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java new file mode 100644 index 00000000000..a8390f0fd5d --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// Java System Class Loader --> defines m3 --> packages p3 +// +// m1 can read m2 +// package p2 in m2 is exported to m1 and m3 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access allowed since m1 can read m2 and package p2 is exported to m1. +// +public class ModuleNonBuiltinCLMain { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported to unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base, m3 + // Packages: p2 + // Packages exported: package p2 is exported to m1 and m3 + Set targets = new HashSet<>(); + targets.add("m1"); + targets.add("m3"); + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .requires("m3") + .exports("p2", targets) + .build(); + + // Define module: m3 + // Can read: java.base + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + + // map each module to differing user defined class loaders for this test + Map map = new HashMap<>(); + Loader1 cl1 = new Loader1(); + Loader2 cl2 = new Loader2(); + ClassLoader cl3 = ClassLoader.getSystemClassLoader(); + map.put("m1", cl1); + map.put("m2", cl2); + map.put("m3", cl3); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + assertTrue(layer.findLoader("m1") == cl1); + assertTrue(layer.findLoader("m2") == cl2); + assertTrue(layer.findLoader("m3") == cl3); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = cl1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1"); + } + } + + public static void main(String args[]) throws Throwable { + ModuleNonBuiltinCLMain test = new ModuleNonBuiltinCLMain(); + test.createLayerOnBoot(); + } + + static class Loader1 extends ClassLoader { } + static class Loader2 extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java b/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java new file mode 100644 index 00000000000..b14a9a9b060 --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader1 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access allowed since m1 can read m2 and package p2 is exported to m1. +// +public class ModuleSameCLMain { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported to unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: package p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + Loader1 cl1 = new Loader1(); + map.put("m1", cl1); + map.put("m2", cl1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + assertTrue(layer.findLoader("m1") == cl1); + assertTrue(layer.findLoader("m2") == cl1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = cl1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1"); + } + } + + public static void main(String args[]) throws Throwable { + ModuleSameCLMain test = new ModuleSameCLMain(); + test.createLayerOnBoot(); + } + + static class Loader1 extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/ModuleStress.java b/hotspot/test/runtime/modules/ModuleStress/ModuleStress.java new file mode 100644 index 00000000000..d7791e9b43a --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/ModuleStress.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 8159262 + * @summary Test differing scenarios where a module's readability list and a package's exportability list should be walked + * @modules java.base/jdk.internal.misc + * @library /testlibrary /test/lib + * @compile ../AccessCheck/ModuleLibrary.java + * @compile ModuleSameCLMain.java + * @compile ModuleNonBuiltinCLMain.java + * @compile CustomSystemClassLoader.java + * @build ModuleStress + * @run main/othervm ModuleStress + */ + +import jdk.test.lib.*; +import java.io.File; + +public class ModuleStress { + + public static void main(String[] args) throws Exception { + + // Test #1: java -version + // All modules' readability lists and packages' exportability + // lists should contain only modules defined to the 3 builtin + // loaders (boot, application, platform). Thus there is + // not a need to walk those lists at a GC safepoint since + // those loaders never die. + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-Xlog:modules=trace", + "-version"); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + oa.shouldNotContain("must be walked") + .shouldNotContain("being walked") + .shouldHaveExitValue(0); + + // Next 2 tests involve the use of class p1.c1 and p2.c2 + String source1 = "package p1;" + + "import p2.c2;" + + "public class c1 {" + + " public c1() {" + + " p2.c2 c2_obj = new p2.c2();" + + " c2_obj.method2();" + + " }" + + "}"; + + String source2 = "package p2;" + + "public class c2 {" + + " public void method2() { }" + + "}"; + + ClassFileInstaller.writeClassToDisk("p2/c2", + InMemoryJavaCompiler.compile("p2.c2", source2), System.getProperty("test.classes")); + + ClassFileInstaller.writeClassToDisk("p1/c1", + InMemoryJavaCompiler.compile("p1.c1", source1), System.getProperty("test.classes")); + + // Test #2: Load two modules defined to the same customer class loader. + // m1's module readability list and package p2's exportability should + // not be walked at a GC safepoint since both modules are defined to + // the same loader and thus have the exact same life cycle. + pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-Xlog:modules=trace", + "ModuleSameCLMain"); + + oa = new OutputAnalyzer(pb.start()); + oa.shouldNotContain("must be walked") + .shouldNotContain("being walked") + .shouldHaveExitValue(0); + + // Test #3: Load two modules in differing custom class loaders. + // m1's module readability list and package p2's exportability list must + // be walked at a GC safepoint since both modules are defined to non-builtin + // class loaders which could die and thus be unloaded. + pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-Xlog:modules=trace", + "ModuleNonBuiltinCLMain"); + + oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("module m1 reads list must be walked") + .shouldContain("package p2 defined in module m2, exports list must be walked") + .shouldNotContain("module m2 reads list must be walked") + .shouldHaveExitValue(0); + + // Test #4: Load two modules in differing custom class loaders, + // of which one has been designated as the custom system class loader + // via -Djava.system.class.loader=CustomSystemClassLoader. Since + // m3 is defined to the system class loader, m2's module readability + // list does not have to be walked at a GC safepoint, but package p2's + // exportability list does. + pb = ProcessTools.createJavaProcessBuilder( + "-Djava.system.class.loader=CustomSystemClassLoader", + "-Xbootclasspath/a:.", + "-Xlog:modules=trace", + "ModuleNonBuiltinCLMain"); + + oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("package p2 defined in module m2, exports list must be walked") + .shouldNotContain("module m2 reads list must be walked") + .shouldHaveExitValue(0); + + } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/ModuleStressGC.java b/hotspot/test/runtime/modules/ModuleStress/ModuleStressGC.java new file mode 100644 index 00000000000..1ebb198ba5c --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/ModuleStressGC.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016, 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 8159262 + * @summary layers over the boot layer are repeatedly created, during this iteration, GCs are forced to verify correct walk of module and package lists. + * @modules java.base/jdk.internal.misc + * @library /testlibrary /test/lib + * @compile ../CompilerUtils.java + * @build ModuleStressGC + * @run main/othervm ModuleStressGC + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.*; + +public class ModuleStressGC { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String TEST_CLASSES = System.getProperty("test.classes"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); + + /** + * Compile two module definitions used by the test, jdk.test and jdk.translet. + */ + public static void main(String[] args) throws Exception { + + boolean compiled; + // Compile module jdk.test declaration + compiled = CompilerUtils.compile( + SRC_DIR.resolve("jdk.test"), + MODS_DIR.resolve("jdk.test")); + if (!compiled) { + throw new RuntimeException("Test failed to compile module jdk.test"); + } + + // Compile module jdk.translet declaration + compiled = CompilerUtils.compile( + SRC_DIR.resolve("jdk.translet"), + MODS_DIR.resolve("jdk.translet"), + "-XaddExports:jdk.test/test=jdk.translet", + "-mp", MODS_DIR.toString()); + if (!compiled) { + throw new RuntimeException("Test failed to compile module jdk.translet"); + } + + // Sanity check that the test, jdk.test/test/MainGC.java, + // correctly walks module jdk.test's reads list and package + // test's, defined to module jdk.translet, export list at + // GC safepoints. + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:modules=trace", + "-mp", MODS_DIR.toString(), + "-m", "jdk.test/test.MainGC"); + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("package test defined in module jdk.test, exports list being walked") + .shouldContain("module jdk.test reads list being walked") + .shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/src/jdk.test/test/MainGC.java b/hotspot/test/runtime/modules/ModuleStress/src/jdk.test/test/MainGC.java new file mode 100644 index 00000000000..25c121d3625 --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/src/jdk.test/test/MainGC.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, 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 test; + +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class MainGC { + + private static final Path MODS_DIR = Paths.get(System.getProperty("jdk.module.path")); + static final String MODULE_NAME = "jdk.translet"; + + public static void main(String[] args) throws Exception { + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer layerBoot = Layer.boot(); + + Configuration cf = layerBoot + .configuration() + .resolveRequires(ModuleFinder.of(), finder, Set.of(MODULE_NAME)); + + Module testModule = MainGC.class.getModule(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + // Create an unique module/class loader in a layer above the boot layer. + // Export this module to the jdk.test/test package. + // Add a read edge from module jdk.test to this module. + Callable task = new Callable() { + @Override + public Void call() throws Exception { + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + Module transletModule = layer.findModule(MODULE_NAME).get(); + testModule.addExports("test", transletModule); + testModule.addReads(transletModule); + Class c = layer.findLoader(MODULE_NAME).loadClass("translet.MainGC"); + Method method = c.getDeclaredMethod("go"); + method.invoke(null); + return null; + } + }; + + List> results = new ArrayList<>(); + + // Repeatedly create the layer above stressing the exportation of + // package jdk.test/test to several different modules. + ExecutorService pool = Executors.newFixedThreadPool(Math.min(100, Runtime.getRuntime().availableProcessors()*10)); + try { + for (int i = 0; i < 10000; i++) { + results.add(pool.submit(task)); + // At specified intervals, force a GC. This provides an + // opportunity to verify that both the module jdk.test's reads + // and the package test's, which is defined to jdk.test, exports + // lists are being walked. + if (i == 3000 || i == 6000 || i == 9000) { + System.gc(); + } + } + } finally { + pool.shutdown(); + } + + int passed = 0; + int failed = 0; + + // The failed state should be 0, the created modules in layers above the + // boot layer should be allowed access to the contents of the jdk.test/test + // package since that package was exported to the transletModule above. + for (Future result : results) { + try { + result.get(); + passed++; + } catch (Throwable x) { + x.printStackTrace(); + failed++; + } + } + + System.out.println("passed: " + passed); + System.out.println("failed: " + failed); + } + + public static void callback() { } +} diff --git a/hotspot/test/runtime/modules/ModuleStress/src/jdk.translet/translet/MainGC.java b/hotspot/test/runtime/modules/ModuleStress/src/jdk.translet/translet/MainGC.java new file mode 100644 index 00000000000..b5e7b7790d6 --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleStress/src/jdk.translet/translet/MainGC.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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 translet; + +public class MainGC { + public static void go() { + test.MainGC.callback(); + } +} From 69a42dc15a5331b00e98a9e8757ab0dd047c90f0 Mon Sep 17 00:00:00 2001 From: Kirill Zhaldybin Date: Wed, 29 Jun 2016 17:01:55 +0300 Subject: [PATCH 03/43] 8132715: Add tests which check that no allocations allowed in any of humongous regions Reviewed-by: dfazunen, tschatzl --- .../TestNoAllocationsInHRegions.java | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 hotspot/test/gc/g1/humongousObjects/TestNoAllocationsInHRegions.java diff --git a/hotspot/test/gc/g1/humongousObjects/TestNoAllocationsInHRegions.java b/hotspot/test/gc/g1/humongousObjects/TestNoAllocationsInHRegions.java new file mode 100644 index 00000000000..bbd15683324 --- /dev/null +++ b/hotspot/test/gc/g1/humongousObjects/TestNoAllocationsInHRegions.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2016, 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 gc.g1.humongousObjects; + +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * @test TestNoAllocationsInHRegions + * @summary Checks that no additional allocations are made in humongous regions + * @requires vm.gc.G1 + * @library /testlibrary /test/lib / + * @modules java.management java.base/jdk.internal.misc + * @build sun.hotspot.WhiteBox + * gc.testlibrary.Helpers + * gc.g1.humongousObjects.TestNoAllocationsInHRegions + * + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * + * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0 + * -Xlog:gc=trace:file=TestNoAllocationsInHRegions10.log + * gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 10 + * + * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0 + * -Xlog:gc=trace:file=TestNoAllocationsInHRegions50.log + * gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 50 + * + * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0 + * -Xlog:gc=trace:file=TestNoAllocationsInHRegions70.log + * gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 70 + */ +public class TestNoAllocationsInHRegions { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Random RND = Utils.getRandomInstance(); + private static final int G1_REGION_SIZE = WB.g1RegionSize(); + private static final int[] HUMONGOUS_SIZES = {G1_REGION_SIZE / 2, G1_REGION_SIZE + 1, G1_REGION_SIZE * 2 + 1}; + private static final int ALLOC_THREAD_COUNT = 5; + + // We fill specified part of heap with humongous objects - we need public static to prevent escape analysis to + // collect this field + public static LinkedList humongousAllocations = new LinkedList<>(); + + private static volatile boolean shouldStop = false; + private static volatile Error error = null; + + static class Allocator implements Runnable { + + private final List liveObjects = new LinkedList<>(); + private int usedMemory = 0; + public final Runnable[] actions; + + /** + * Maximum size of simple allocation + */ + private static final int MAX_ALLOCATION_SIZE = (int) (G1_REGION_SIZE / 2 * 0.9); + + /** + * Maximum size of dead (i.e. one which is made unreachable right after allocation) object + */ + private static final int DEAD_OBJECT_MAX_SIZE = G1_REGION_SIZE / 10; + + public Allocator(int maxAllocationMemory) { + + actions = new Runnable[]{ + // Allocation + () -> { + if (maxAllocationMemory - usedMemory != 0) { + int arraySize = RND.nextInt(Math.min(maxAllocationMemory - usedMemory, + MAX_ALLOCATION_SIZE)); + + if (arraySize != 0) { + byte[] allocation = new byte[arraySize]; + liveObjects.add(allocation); + usedMemory += arraySize; + + // Sanity check + if (WB.g1IsHumongous(allocation)) { + String errorMessage = String.format("Test Bug: Byte array of size" + + " %d is expected to be non-humongous but it is humongous", + allocation.length); + + System.out.println(errorMessage); + error = new Error(errorMessage); + shouldStop = true; + } + + // Test check + if (WB.g1BelongsToHumongousRegion(WB.getObjectAddress(allocation))) { + String errorMessage = String.format("Non-humongous allocation of byte array of " + + "length %d and size %d with address %d was made in Humongous Region", + allocation.length, WB.getObjectSize(allocation), + WB.getObjectAddress(allocation)); + + System.out.println(errorMessage); + error = new Error(errorMessage); + shouldStop = true; + } + } + } + }, + + // Deallocation + () -> { + if (liveObjects.size() != 0) { + int elementNum = RND.nextInt(liveObjects.size()); + int shouldFree = liveObjects.get(elementNum).length; + liveObjects.remove(elementNum); + usedMemory -= shouldFree; + } + }, + + // Dead object allocation + () -> { + int size = RND.nextInt(DEAD_OBJECT_MAX_SIZE); + byte[] deadObject = new byte[size]; + }, + + // Check + () -> { + List wrongHumongousAllocations = liveObjects.stream() + .filter(WB::g1IsHumongous) + .collect(Collectors.toList()); + + if (wrongHumongousAllocations.size() > 0) { + wrongHumongousAllocations.stream().forEach(a -> + System.out.format("Non-humongous allocation of byte array of length %d and" + + " size %d with address %d was made in Humongous Region", + a.length, WB.getObjectSize(a), WB.getObjectAddress(a))); + error = new Error("Some non-humongous allocations were made to humongous region"); + shouldStop = true; + } + } + }; + } + + @Override + public void run() { + while (!shouldStop) { + actions[RND.nextInt(actions.length)].run(); + Thread.yield(); + } + } + } + + public static void main(String[] args) { + if (args.length != 2) { + throw new Error("Test Bug: Expected duration (in seconds) and percent of allocated regions were not " + + "provided as command line argument"); + } + + // test duration + long duration = Integer.parseInt(args[0]) * 1000L; + // part of heap preallocated with humongous objects (in percents) + int percentOfAllocatedHeap = Integer.parseInt(args[1]); + + long startTime = System.currentTimeMillis(); + + long initialFreeRegionsCount = WB.g1NumFreeRegions(); + int regionsToAllocate = (int) ((double) initialFreeRegionsCount / 100.0 * percentOfAllocatedHeap); + long freeRegionLeft = initialFreeRegionsCount - regionsToAllocate; + + System.out.println("Regions to allocate: " + regionsToAllocate + "; regions to left free: " + freeRegionLeft); + + int maxMemoryPerAllocThread = (int) ((Runtime.getRuntime().freeMemory() / 100.0 + * (100 - percentOfAllocatedHeap)) / ALLOC_THREAD_COUNT * 0.5); + + System.out.println("Using " + maxMemoryPerAllocThread / 1024 + "KB for each of " + ALLOC_THREAD_COUNT + + " allocation threads"); + + while (WB.g1NumFreeRegions() > freeRegionLeft) { + try { + humongousAllocations.add(new byte[HUMONGOUS_SIZES[RND.nextInt(HUMONGOUS_SIZES.length)]]); + } catch (OutOfMemoryError oom) { + //We got OOM trying to fill heap with humongous objects + //It probably means that heap is fragmented which is strange since the test logic should avoid it + System.out.println("Warning: OOM while allocating humongous objects - it likely means " + + "that heap is fragmented"); + break; + } + } + + System.out.println("Initial free regions " + initialFreeRegionsCount + "; Free regions left " + + WB.g1NumFreeRegions()); + + LinkedList threads = new LinkedList<>(); + + for (int i = 0; i < ALLOC_THREAD_COUNT; i++) { + threads.add(new Thread(new Allocator(maxMemoryPerAllocThread))); + } + + threads.stream().forEach(Thread::start); + + while ((System.currentTimeMillis() - startTime < duration) && error == null) { + Thread.yield(); + } + + shouldStop = true; + System.out.println("Finished test"); + if (error != null) { + throw error; + } + } +} From ed9f8153362674b0af9c44c25039a07564b5b469 Mon Sep 17 00:00:00 2001 From: Kirill Zhaldybin Date: Wed, 29 Jun 2016 18:40:28 +0300 Subject: [PATCH 04/43] 8132711: Add tests which check that Humongous objects behave as expected after Mixed GC Reviewed-by: tschatzl, dfazunen --- .../humongousObjects/objectGraphTest/GC.java | 35 +++++++++++++++++++ .../humongousObjects/objectGraphTest/README | 3 ++ .../TestObjectGraphAfterGC.java | 6 ++++ 3 files changed, 44 insertions(+) diff --git a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java index 8da879dec5e..be721f54fd5 100644 --- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java +++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java @@ -138,6 +138,41 @@ public enum GC { } }, + MIXED_GC { + @Override + public Runnable get() { + return () -> { + WHITE_BOX.youngGC(); + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + WHITE_BOX.youngGC(); + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + + WHITE_BOX.g1StartConcMarkCycle(); + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + + WHITE_BOX.youngGC(); + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + // Provoking Mixed GC + WHITE_BOX.youngGC();// second evacuation pause will be mixed + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + }; + } + + public Consumer> getChecker() { + return getCheckerImpl(true, false, true, false); + } + + @Override + public List shouldContain() { + return Arrays.asList(GCTokens.WB_INITIATED_CMC); + } + + @Override + public List shouldNotContain() { + return Arrays.asList(GCTokens.YOUNG_GC); + } + }, + FULL_GC_MEMORY_PRESSURE { @Override public Runnable get() { diff --git a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README index 4ec9f0d3792..5366fc876be 100644 --- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README +++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README @@ -38,6 +38,9 @@ The test checks that after different type of GC unreachable objects behave as ex non-humongous and humongous objects are not collected since we make 2 Young GC to promote all weak references to Old Gen. +6. Mixed GC - weakly referenced non-humongous and humongous objects are collected, softly referenced non-humongous and + humongous objects are not collected. + The test gets gc type as a command line argument. Then the test allocates object graph in heap (currently testing scenarios are pre-generated and stored in TestcaseData.getPregeneratedTestcases()) with TestObjectGraphAfterGC::allocateObjectGraph. diff --git a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java index c7a4f2ff081..07f7a3bc89d 100644 --- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java +++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java @@ -66,6 +66,12 @@ import java.util.stream.Collectors; * sun.hotspot.WhiteBox$WhiteBoxPermission * * @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=30000 -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0 + * -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectGraphAfterGC_MIXED_GC.gc.log -XX:MaxTenuringThreshold=1 + * -XX:G1MixedGCCountTarget=1 -XX:G1OldCSetRegionThresholdPercent=100 -XX:SurvivorRatio=1 -XX:InitiatingHeapOccupancyPercent=0 + * gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC MIXED_GC + * + * @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M -Xlog:gc*=debug:file=TestObjectGraphAfterGC_YOUNG_GC.gc.log * gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC YOUNG_GC * From fd1c7ff505159c24a3cc75035dbd59d0ddaa7a15 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 29 Jun 2016 20:16:05 -0400 Subject: [PATCH 05/43] 8160551: assert(c == Bytecodes::_putfield) failed: must be putfield Illegal bytecodes which are detected later hit this assert first. Reviewed-by: jrose --- hotspot/src/share/vm/interpreter/rewriter.cpp | 7 +-- hotspot/test/runtime/Final/Bad.jasm | 55 +++++++++++++++++++ hotspot/test/runtime/Final/PutfieldError.java | 42 ++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 hotspot/test/runtime/Final/Bad.jasm create mode 100644 hotspot/test/runtime/Final/PutfieldError.java diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 52832e781ab..dfc110b8222 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -419,21 +419,20 @@ void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_err InstanceKlass* klass = method->method_holder(); u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1); constantPoolHandle cp(method->constants()); - Symbol* field_name = cp->name_ref_at(bc_index); - Symbol* field_sig = cp->signature_ref_at(bc_index); Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index)); if (klass->name() == ref_class_name) { + Symbol* field_name = cp->name_ref_at(bc_index); + Symbol* field_sig = cp->signature_ref_at(bc_index); + fieldDescriptor fd; klass->find_field(field_name, field_sig, &fd); if (fd.access_flags().is_final()) { if (fd.access_flags().is_static()) { - assert(c == Bytecodes::_putstatic, "must be putstatic"); if (!method->is_static_initializer()) { fd.set_has_initialized_final_update(true); } } else { - assert(c == Bytecodes::_putfield, "must be putfield"); if (!method->is_object_initializer()) { fd.set_has_initialized_final_update(true); } diff --git a/hotspot/test/runtime/Final/Bad.jasm b/hotspot/test/runtime/Final/Bad.jasm new file mode 100644 index 00000000000..607e2bcc078 --- /dev/null +++ b/hotspot/test/runtime/Final/Bad.jasm @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* Recoded in jasm to provoke an ICCE assigning a non-static final field with putstatic. +class Bad { + public static final int i; //rewritten + //rewritten to: public final int i; + static { i = 5; } // putstatic instruction +} +*/ + +super class Bad + version 53:0 +{ + +// Remove 'static' keyword +public final Field i:I; + +Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +static Method "":"()V" + stack 1 locals 0 +{ + iconst_5; + putstatic Field i:"I"; + return; +} + +} // end Class Bad diff --git a/hotspot/test/runtime/Final/PutfieldError.java b/hotspot/test/runtime/Final/PutfieldError.java new file mode 100644 index 00000000000..9669a1b1ade --- /dev/null +++ b/hotspot/test/runtime/Final/PutfieldError.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, 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 PutfieldError + * @bug 8160551 + * @summary Throw ICCE rather than crashing for nonstatic final field in static initializer + * @compile Bad.jasm + * @run main PutfieldError + */ + +public class PutfieldError { + public static void main(java.lang.String[] unused) { + try { + Bad b = new Bad(); + System.out.println("Bad.i = " + 5); + throw new RuntimeException("ICCE NOT thrown as expected"); + } catch (IncompatibleClassChangeError icce) { + System.out.println("ICCE thrown as expected"); + } + } +} From 992b6c464a9655438a808cf2e1979e04356123be Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Wed, 29 Jun 2016 16:11:50 +0200 Subject: [PATCH 06/43] 8159695: Arguments::atojulong() fails to detect overflows Reviewed-by: dholmes, dsamersoff --- hotspot/src/share/vm/runtime/arguments.cpp | 33 +++++---- .../test/native/runtime/test_arguments.cpp | 71 +++++++++++++++++++ 2 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 hotspot/test/native/runtime/test_arguments.cpp diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 4b29b2830ca..a9e944e4f7f 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -584,27 +584,26 @@ static bool verify_special_jvm_flags() { // Parses a size specification string. bool Arguments::atojulong(const char *s, julong* result) { julong n = 0; - int args_read = 0; - bool is_hex = false; - // Skip leading 0[xX] for hexadecimal - if (*s =='0' && (*(s+1) == 'x' || *(s+1) == 'X')) { - s += 2; - is_hex = true; - args_read = sscanf(s, JULONG_FORMAT_X, &n); - } else { - args_read = sscanf(s, JULONG_FORMAT, &n); - } - if (args_read != 1) { + + // First char must be a digit. Don't allow negative numbers or leading spaces. + if (!isdigit(*s)) { return false; } - while (*s != '\0' && (isdigit(*s) || (is_hex && isxdigit(*s)))) { - s++; - } - // 4705540: illegal if more characters are found after the first non-digit - if (strlen(s) > 1) { + + bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')); + char* remainder; + errno = 0; + n = strtoull(s, &remainder, (is_hex ? 16 : 10)); + if (errno != 0) { return false; } - switch (*s) { + + // Fail if no number was read at all or if the remainder contains more than a single non-digit character. + if (remainder == s || strlen(remainder) > 1) { + return false; + } + + switch (*remainder) { case 'T': case 't': *result = n * G * K; // Check for overflow. diff --git a/hotspot/test/native/runtime/test_arguments.cpp b/hotspot/test/native/runtime/test_arguments.cpp new file mode 100644 index 00000000000..f4327f3498d --- /dev/null +++ b/hotspot/test/native/runtime/test_arguments.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, 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. + * + */ +#include "precompiled.hpp" +#include "runtime/arguments.hpp" +#include "unittest.hpp" +#include "utilities/globalDefinitions.hpp" + +TEST(arguments, atojulong) { + char ullong_max[32]; + int ret = jio_snprintf(ullong_max, sizeof(ullong_max), JULONG_FORMAT, ULLONG_MAX); + ASSERT_NE(-1, ret); + + julong value; + const char* invalid_strings[] = { + "", "-1", "-100", " 1", "2 ", "3 2", "1.0", + "0x4.5", "0x", "0x0x1" "0.001", "4e10", "e" + "K", "M", "G", "1MB", "1KM", "AA", "0B", + "18446744073709551615K", "17179869184G", + "999999999999999999999999999999" + }; + for (uint i = 0; i < ARRAY_SIZE(invalid_strings); i++) { + ASSERT_FALSE(Arguments::atojulong(invalid_strings[i], &value)) + << "Invalid string '" << invalid_strings[i] << "' parsed without error."; + } + + struct { + const char* str; + julong expected_value; + } valid_strings[] = { + { "0", 0 }, + { "4711", 4711 }, + { "1K", 1ULL * K }, + { "1k", 1ULL * K }, + { "2M", 2ULL * M }, + { "2m", 2ULL * M }, + { "4G", 4ULL * G }, + { "4g", 4ULL * G }, + { "0K", 0 }, + { ullong_max, ULLONG_MAX }, + { "0xcafebabe", 0xcafebabe }, + { "0XCAFEBABE", 0xcafebabe }, + { "0XCAFEbabe", 0xcafebabe }, + { "0x10K", 0x10 * K } + }; + for (uint i = 0; i < ARRAY_SIZE(valid_strings); i++) { + ASSERT_TRUE(Arguments::atojulong(valid_strings[i].str, &value)) + << "Valid string '" << valid_strings[i].str << "' did not parse."; + ASSERT_EQ(valid_strings[i].expected_value, value); + } +} From 8ea7496925d011e3333417e960c8b9285fe57e15 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 30 Jun 2016 19:16:14 -0400 Subject: [PATCH 07/43] 8160356: invalid suffix on literal warning is occurred with GCC 6 Add whitespace separation Reviewed-by: kbarrett, kvn --- hotspot/src/share/vm/classfile/moduleEntry.cpp | 2 +- hotspot/src/share/vm/classfile/packageEntry.cpp | 4 ++-- hotspot/src/share/vm/gc/shared/preservedMarks.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp index a05c1644b92..a8b67c54e64 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp @@ -413,7 +413,7 @@ void ModuleEntryTable::print(outputStream* st) { void ModuleEntry::print(outputStream* st) { ResourceMark rm; - st->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT, + st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s next " PTR_FORMAT, p2i(this), name() == NULL ? UNNAMED_MODULE : name()->as_C_string(), p2i(module()), diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp index d224941c32d..2389cb25559 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.cpp +++ b/hotspot/src/share/vm/classfile/packageEntry.cpp @@ -346,8 +346,8 @@ void PackageEntryTable::print(outputStream* st) { void PackageEntry::print(outputStream* st) { ResourceMark rm; - st->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index " - INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next "PTR_FORMAT, + st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index " + INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT, p2i(this), name()->as_C_string(), (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE), _classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next())); diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp index 7a1078ebb34..2fcd86344be 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp @@ -48,10 +48,10 @@ void PreservedMarks::restore_and_increment(volatile size_t* const total_size_add #ifndef PRODUCT void PreservedMarks::assert_empty() { - assert(_stack.is_empty(), "stack expected to be empty, size = "SIZE_FORMAT, + assert(_stack.is_empty(), "stack expected to be empty, size = " SIZE_FORMAT, _stack.size()); assert(_stack.cache_size() == 0, - "stack expected to have no cached segments, cache size = "SIZE_FORMAT, + "stack expected to have no cached segments, cache size = " SIZE_FORMAT, _stack.cache_size()); } #endif // ndef PRODUCT From 5b2f045b846a4b542186dff4bc34b74d7679b69a Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 1 Jul 2016 11:55:25 +0200 Subject: [PATCH 08/43] 8158629: bash >(...) construct still causes race conditions Reviewed-by: tbell --- hotspot/make/gensrc/GensrcDtrace.gmk | 3 ++- hotspot/make/lib/CompileDtracePostJvm.gmk | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/make/gensrc/GensrcDtrace.gmk b/hotspot/make/gensrc/GensrcDtrace.gmk index 563f22112fb..126be0b3599 100644 --- a/hotspot/make/gensrc/GensrcDtrace.gmk +++ b/hotspot/make/gensrc/GensrcDtrace.gmk @@ -45,7 +45,8 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(DTRACE_GENSRC_DIR)/%.h: $(DTRACE_SOURCE_DIR)/%.d $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) - $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ + ( $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d ) ) $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: diff --git a/hotspot/make/lib/CompileDtracePostJvm.gmk b/hotspot/make/lib/CompileDtracePostJvm.gmk index 50a7f10d67d..45c81ad9c4e 100644 --- a/hotspot/make/lib/CompileDtracePostJvm.gmk +++ b/hotspot/make/lib/CompileDtracePostJvm.gmk @@ -68,7 +68,7 @@ ifeq ($(call check-jvm-feature, dtrace), true) $1: $$(BUILD_DTRACE_GEN_OFFSETS) $$(call LogInfo, Generating dtrace $2 file $$(@F)) $$(call MakeDir, $$(@D)) - $$(call ExecuteWithLog, $$@, $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@) + $$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) ) TARGETS += $1 endef From 7fbf406a0eca73265d4a2750e5322c67eb8fe6c2 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 1 Jul 2016 12:32:21 +0200 Subject: [PATCH 09/43] 8158629: bash >(...) construct still causes race conditions Reviewed-by: tbell --- make/common/MakeBase.gmk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 703994958d6..15c6bc6254d 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -801,15 +801,20 @@ endif # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # +# NOTE: If the command redirects stdout, the caller needs to wrap it in a +# subshell (by adding parentheses around it), otherwise the redirect to the +# subshell tee process will create a race condition where the target file may +# not be fully written when the make recipe is done. +# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ $(call LogCmdlines, Exececuting: [$(strip $2)]) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( ( $(strip $2) > >($(TEE) $(strip $1).log) 2> >($(TEE) $(strip $1).log >&2) || \ + ( $(strip $2) > >($(TEE) $(strip $1).log) 2> >($(TEE) $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(BUILD_OUTPUT)/%,%,$(strip $1))).log && \ - exit $(DOLLAR)exitcode ) ) && wait ) + exit $(DOLLAR)exitcode ) ) ################################################################################ # Find lib dir for module From f06ef85609fa75a73cb212de9d56b4c5c89e0104 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Fri, 1 Jul 2016 07:21:33 -0400 Subject: [PATCH 10/43] 8160484: Implement Hotspot Runtime tier 2 Reviewed-by: dholmes, gtriantafill --- hotspot/test/TEST.groups | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 262232e706c..b46499f7902 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -395,6 +395,17 @@ hotspot_jprt = \ :hotspot_fast_gc_gcold \ :hotspot_fast_runtime \ :hotspot_fast_serviceability + +hotspot_runtime_tier2 = \ + runtime/ \ + serviceability/ \ + -:hotspot_fast_runtime \ + -:hotspot_fast_serviceability \ + -:hotspot_runtime_tier2_platform_agnostic + +hotspot_runtime_tier2_platform_agnostic = \ + runtime/SelectionResolution \ + -:hotspot_fast_runtime #All tests that depends on nashorn extension. # From f97651b3560d43158f1f0196845f6844b7352144 Mon Sep 17 00:00:00 2001 From: Poonam Bajaj Date: Fri, 1 Jul 2016 12:51:29 -0700 Subject: [PATCH 11/43] 8064814: Print more helpful error message when getting OOM due to low Java Heap base when running with CompressedOops Improve OOM error message Reviewed-by: coleenp, dholmes --- hotspot/src/share/vm/utilities/vmError.cpp | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index d2c9cadb504..4a2ac95995b 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -205,16 +205,39 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, static void print_oom_reasons(outputStream* st) { st->print_cr("# Possible reasons:"); st->print_cr("# The system is out of physical RAM or swap space"); - st->print_cr("# In 32 bit mode, the process size limit was hit"); + if (UseCompressedOops) { + st->print_cr("# The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap"); + } + if (LogBytesPerWord == 2) { + st->print_cr("# In 32 bit mode, the process size limit was hit"); + } st->print_cr("# Possible solutions:"); st->print_cr("# Reduce memory load on the system"); st->print_cr("# Increase physical memory or swap space"); st->print_cr("# Check if swap backing store is full"); - st->print_cr("# Use 64 bit Java on a 64 bit OS"); + if (LogBytesPerWord == 2) { + st->print_cr("# Use 64 bit Java on a 64 bit OS"); + } st->print_cr("# Decrease Java heap size (-Xmx/-Xms)"); st->print_cr("# Decrease number of Java threads"); st->print_cr("# Decrease Java thread stack sizes (-Xss)"); st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize="); + if (UseCompressedOops) { + switch (Universe::narrow_oop_mode()) { + case Universe::UnscaledNarrowOop: + st->print_cr("# JVM is running with Unscaled Compressed Oops mode in which the Java heap is"); + st->print_cr("# placed in the first 4GB address space. The Java Heap base address is the"); + st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress"); + st->print_cr("# to set the Java Heap base and to place the Java Heap above 4GB virtual address."); + break; + case Universe::ZeroBasedNarrowOop: + st->print_cr("# JVM is running with Zero Based Compressed Oops mode in which the Java heap is"); + st->print_cr("# placed in the first 32GB address space. The Java Heap base address is the"); + st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress"); + st->print_cr("# to set the Java Heap base and to place the Java Heap above 32GB virtual address."); + break; + } + } st->print_cr("# This output file may be truncated or incomplete."); } From 1931ac419659c69f674964c581ffd99af24fb567 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 12 Jul 2016 09:41:49 +0800 Subject: [PATCH 12/43] 8130302: jarsigner and keytool -providerClass needs be re-examined for modules Reviewed-by: valeriep, mchung, mullan --- .../sun/security/tools/KeyStoreUtil.java | 68 ++++++ .../sun/security/tools/keytool/Main.java | 214 ++++++++++-------- .../sun/security/tools/keytool/Resources.java | 18 +- .../java.base/share/conf/security/java.policy | 3 +- .../security/ucrypto/UcryptoProvider.java | 13 +- .../sun/security/tools/jarsigner/Main.java | 81 ++++--- .../security/tools/jarsigner/Resources.java | 17 +- .../security/pkcs11/fips/ImportKeyStore.java | 2 +- .../security/tools/jarsigner/AltProvider.java | 161 +++++++++++++ .../jarsigner/alt/test.dummy/module-info.java | 26 +++ .../org/test/dummy}/DummyProvider.java | 18 +- .../security/tools/keytool/AltProviderPath.sh | 122 ---------- .../security/tools/keytool/KeyToolTest.java | 11 +- jdk/test/sun/security/tools/keytool/i18n.html | 20 +- 14 files changed, 490 insertions(+), 284 deletions(-) create mode 100644 jdk/test/sun/security/tools/jarsigner/AltProvider.java create mode 100644 jdk/test/sun/security/tools/jarsigner/alt/test.dummy/module-info.java rename jdk/test/sun/security/tools/{keytool => jarsigner/alt/test.dummy/org/test/dummy}/DummyProvider.java (89%) delete mode 100644 jdk/test/sun/security/tools/keytool/AltProviderPath.sh diff --git a/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java b/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java index 4d59e69be75..7c33d0753f6 100644 --- a/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java +++ b/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java @@ -38,6 +38,8 @@ import java.net.URL; import java.security.KeyStore; +import java.security.Provider; +import java.security.Security; import java.security.cert.X509Certificate; import java.text.Collator; @@ -46,6 +48,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Properties; +import java.util.ServiceLoader; import sun.security.util.PropertyExpander; @@ -209,6 +212,7 @@ public class KeyStoreUtil { /** * Prepends matched options from a pre-configured options file. + * * @param tool the name of the tool, can be "keytool" or "jarsigner" * @param file the pre-configured options file * @param c1 the name of the command, with the "-" prefix, @@ -259,4 +263,68 @@ public class KeyStoreUtil { return result.toArray(new String[result.size()]); } } + + /** + * Loads a security provider as a service. + * + * @param provName the name + * @param arg optional arg + * @throws IllegalArgumentException if no provider matches the name + */ + public static void loadProviderByName(String provName, String arg) { + Provider loaded = Security.getProvider(provName); + if (loaded != null) { + if (arg != null) { + loaded = loaded.configure(arg); + Security.addProvider(loaded); + } + return; + } + for (Provider p : ServiceLoader.load(Provider.class, + ClassLoader.getSystemClassLoader())) { + if (p.getName().equals(provName)) { + if (arg != null) { + p = p.configure(arg); + } + Security.addProvider(p); + return; + } + } + throw new IllegalArgumentException("No provider found"); + } + + /** + * Loads a security provider by a fully-qualified class name. + * + * @param provClass the class name + * @param arg optional arg + * @param cl optional class loader + * @throws IllegalArgumentException if no provider matches the class name + * @throws ClassCastException if the class has not extended Provider + */ + public static void loadProviderByClass( + String provClass, String arg, ClassLoader cl) { + + // For compatibility, SunPKCS11 and OracleUcrypto can still be + // loadable with -providerClass. + if (provClass.equals("sun.security.pkcs11.SunPKCS11")) { + loadProviderByName("SunPKCS11", arg); + return; + } else if (provClass.equals("com.oracle.security.crypto.UcryptoProvider")) { + loadProviderByName("OracleUcrypto", arg); + return; + } + + Provider prov; + try { + Class clazz = Class.forName(provClass, false, cl); + prov = (Provider) clazz.getConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalArgumentException(e); + } + if (arg != null) { + prov = prov.configure(arg); + } + Security.addProvider(prov); + } } diff --git a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 2832c0d8390..b5ac0930cbd 100644 --- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -33,13 +33,11 @@ import java.security.MessageDigest; import java.security.Key; import java.security.PublicKey; import java.security.PrivateKey; -import java.security.Security; import java.security.Signature; import java.security.Timestamp; import java.security.UnrecoverableEntryException; import java.security.UnrecoverableKeyException; import java.security.Principal; -import java.security.Provider; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.CertStoreException; @@ -128,6 +126,7 @@ public final class Main { // them through the command line. private Set> providers = null; + private Set> providerClasses = null; private String storetype = null; private boolean hasStoretypeOption = false; private String srcProviderName = null; @@ -166,57 +165,57 @@ public final class Main { enum Command { CERTREQ("Generates.a.certificate.request", ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), CHANGEALIAS("Changes.an.entry.s.alias", ALIAS, DESTALIAS, KEYPASS, KEYSTORE, STOREPASS, - STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + STORETYPE, PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), DELETE("Deletes.an.entry", ALIAS, KEYSTORE, STOREPASS, STORETYPE, - PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), EXPORTCERT("Exports.certificate", RFC, ALIAS, FILEOUT, KEYSTORE, STOREPASS, - STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + STORETYPE, PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), GENKEYPAIR("Generates.a.key.pair", ALIAS, KEYALG, KEYSIZE, SIGALG, DESTALIAS, DNAME, STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), GENSECKEY("Generates.a.secret.key", ALIAS, KEYPASS, KEYALG, KEYSIZE, KEYSTORE, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), GENCERT("Generates.certificate.from.a.certificate.request", RFC, INFILE, OUTFILE, ALIAS, SIGALG, DNAME, STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), IMPORTCERT("Imports.a.certificate.or.a.certificate.chain", NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN, KEYPASS, KEYSTORE, STOREPASS, STORETYPE, - PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), IMPORTPASS("Imports.a.password", ALIAS, KEYPASS, KEYALG, KEYSIZE, KEYSTORE, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), IMPORTKEYSTORE("Imports.one.or.all.entries.from.another.keystore", SRCKEYSTORE, DESTKEYSTORE, SRCSTORETYPE, DESTSTORETYPE, SRCSTOREPASS, DESTSTOREPASS, SRCPROTECTED, DESTPROTECTED, SRCPROVIDERNAME, DESTPROVIDERNAME, SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS, - NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, + NOPROMPT, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), KEYPASSWD("Changes.the.key.password.of.an.entry", ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS, - STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + STORETYPE, PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), LIST("Lists.entries.in.a.keystore", RFC, ALIAS, KEYSTORE, STOREPASS, STORETYPE, - PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, + PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), PRINTCERT("Prints.the.content.of.a.certificate", RFC, FILEIN, SSLSERVER, JARFILE, V), @@ -226,26 +225,26 @@ public final class Main { FILEIN, V), STOREPASSWD("Changes.the.store.password.of.a.keystore", NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, - PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), + ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), // Undocumented start here, KEYCLONE is used a marker in -help; KEYCLONE("Clones.a.key.entry", ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE, - KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V), + KEYSTORE, STOREPASS, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V), SELFCERT("Generates.a.self.signed.certificate", ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, - PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), + ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), GENCRL("Generates.CRL", RFC, FILEOUT, ID, ALIAS, SIGALG, EXT, KEYPASS, KEYSTORE, - STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V, PROTECTED), + STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, + PROVIDERCLASS, PROVIDERPATH, V, PROTECTED), IDENTITYDB("Imports.entries.from.a.JDK.1.1.x.style.identity.database", FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, - PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V); + ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V); final String description; final Option[] options; @@ -289,48 +288,48 @@ public final class Main { enum Option { ALIAS("alias", "", "alias.name.of.the.entry.to.process"), - DESTALIAS("destalias", "", "destination.alias"), + DESTALIAS("destalias", "", "destination.alias"), DESTKEYPASS("destkeypass", "", "destination.key.password"), - DESTKEYSTORE("destkeystore", "", "destination.keystore.name"), + DESTKEYSTORE("destkeystore", "", "destination.keystore.name"), DESTPROTECTED("destprotected", null, "destination.keystore.password.protected"), - DESTPROVIDERNAME("destprovidername", "", "destination.keystore.provider.name"), + DESTPROVIDERNAME("destprovidername", "", "destination.keystore.provider.name"), DESTSTOREPASS("deststorepass", "", "destination.keystore.password"), - DESTSTORETYPE("deststoretype", "", "destination.keystore.type"), - DNAME("dname", "", "distinguished.name"), + DESTSTORETYPE("deststoretype", "", "destination.keystore.type"), + DNAME("dname", "", "distinguished.name"), EXT("ext", "", "X.509.extension"), - FILEOUT("file", "", "output.file.name"), - FILEIN("file", "", "input.file.name"), + FILEOUT("file", "", "output.file.name"), + FILEIN("file", "", "input.file.name"), ID("id", "", "Serial.ID.of.cert.to.revoke"), - INFILE("infile", "", "input.file.name"), - KEYALG("keyalg", "", "key.algorithm.name"), + INFILE("infile", "", "input.file.name"), + KEYALG("keyalg", "", "key.algorithm.name"), KEYPASS("keypass", "", "key.password"), - KEYSIZE("keysize", "", "key.bit.size"), + KEYSIZE("keysize", "", "key.bit.size"), KEYSTORE("keystore", "", "keystore.name"), NEW("new", "", "new.password"), NOPROMPT("noprompt", null, "do.not.prompt"), - OUTFILE("outfile", "", "output.file.name"), + OUTFILE("outfile", "", "output.file.name"), PROTECTED("protected", null, "password.through.protected.mechanism"), - PROVIDERARG("providerarg", "", "provider.argument"), - PROVIDERCLASS("providerclass", "", "provider.class.name"), - PROVIDERNAME("providername", "", "provider.name"), - PROVIDERPATH("providerpath", "", "provider.classpath"), + PROVIDERCLASS("providerclass", "\n[-providerarg ]", "provider.class.option"), + ADDPROVIDER("addprovider", "\n[-providerarg ]", "addprovider.option"), + PROVIDERNAME("providername", "", "provider.name"), + PROVIDERPATH("providerpath", "", "provider.classpath"), RFC("rfc", null, "output.in.RFC.style"), - SIGALG("sigalg", "", "signature.algorithm.name"), - SRCALIAS("srcalias", "", "source.alias"), + SIGALG("sigalg", "", "signature.algorithm.name"), + SRCALIAS("srcalias", "", "source.alias"), SRCKEYPASS("srckeypass", "", "source.key.password"), - SRCKEYSTORE("srckeystore", "", "source.keystore.name"), + SRCKEYSTORE("srckeystore", "", "source.keystore.name"), SRCPROTECTED("srcprotected", null, "source.keystore.password.protected"), - SRCPROVIDERNAME("srcprovidername", "", "source.keystore.provider.name"), + SRCPROVIDERNAME("srcprovidername", "", "source.keystore.provider.name"), SRCSTOREPASS("srcstorepass", "", "source.keystore.password"), - SRCSTORETYPE("srcstoretype", "", "source.keystore.type"), + SRCSTORETYPE("srcstoretype", "", "source.keystore.type"), SSLSERVER("sslserver", "", "SSL.server.host.and.port"), - JARFILE("jarfile", "", "signed.jar.file"), - STARTDATE("startdate", "", "certificate.validity.start.date.time"), + JARFILE("jarfile", "", "signed.jar.file"), + STARTDATE("startdate", "", "certificate.validity.start.date.time"), STOREPASS("storepass", "", "keystore.password"), - STORETYPE("storetype", "", "keystore.type"), + STORETYPE("storetype", "", "keystore.type"), TRUSTCACERTS("trustcacerts", null, "trust.certificates.from.cacerts"), V("v", null, "verbose.output"), - VALIDITY("validity", "", "validity.number.of.days"); + VALIDITY("validity", "", "validity.number.of.days"); final String name, arg, description; Option(String name, String arg, String description) { @@ -344,8 +343,6 @@ public final class Main { } }; - private static final Class[] PARAM_STRING = { String.class }; - private static final String NONE = "NONE"; private static final String P11KEYSTORE = "PKCS11"; private static final String P12KEYSTORE = "PKCS12"; @@ -549,10 +546,10 @@ public final class Main { jarfile = args[++i]; } else if (collator.compare(flags, "-srckeystore") == 0) { srcksfname = args[++i]; - } else if ((collator.compare(flags, "-provider") == 0) || - (collator.compare(flags, "-providerclass") == 0)) { - if (providers == null) { - providers = new HashSet> (3); + } else if (collator.compare(flags, "-provider") == 0 || + collator.compare(flags, "-providerclass") == 0) { + if (providerClasses == null) { + providerClasses = new HashSet> (3); } String providerClass = args[++i]; String providerArg = null; @@ -565,8 +562,25 @@ public final class Main { i += 2; } } - providers.add( + providerClasses.add( Pair.of(providerClass, providerArg)); + } else if (collator.compare(flags, "-addprovider") == 0) { + if (providers == null) { + providers = new HashSet> (3); + } + String provider = args[++i]; + String providerArg = null; + + if (args.length > (i+1)) { + flags = args[i+1]; + if (collator.compare(flags, "-providerarg") == 0) { + if (args.length == (i+2)) errorNeedArgument(flags); + providerArg = args[i+2]; + i += 2; + } + } + providers.add( + Pair.of(provider, providerArg)); } /* @@ -617,7 +631,6 @@ public final class Main { return cmd != PRINTCERT && cmd != PRINTCERTREQ; } - /** * Execute the commands. */ @@ -703,6 +716,20 @@ public final class Main { // Try to load and install specified provider if (providers != null) { + for (Pair provider : providers) { + try { + KeyStoreUtil.loadProviderByName( + provider.fst, provider.snd); + if (debug) { + System.out.println("loadProviderByName: " + provider.fst); + } + } catch (IllegalArgumentException e) { + throw new Exception(String.format(rb.getString( + "provider.name.not.found"), provider.fst)); + } + } + } + if (providerClasses != null) { ClassLoader cl = null; if (pathlist != null) { String path = null; @@ -717,30 +744,20 @@ public final class Main { } else { cl = ClassLoader.getSystemClassLoader(); } - - for (Pair provider: providers) { - String provName = provider.fst; - Class provClass; - if (cl != null) { - provClass = cl.loadClass(provName); - } else { - provClass = Class.forName(provName); + for (Pair provider : providerClasses) { + try { + KeyStoreUtil.loadProviderByClass( + provider.fst, provider.snd, cl); + if (debug) { + System.out.println("loadProviderByClass: " + provider.fst); + } + } catch (ClassCastException cce) { + throw new Exception(String.format(rb.getString( + "provclass.not.a.provider"), provider.fst)); + } catch (IllegalArgumentException e) { + throw new Exception(String.format(rb.getString( + "provider.class.not.found"), provider.fst), e.getCause()); } - - @SuppressWarnings("deprecation") - Object obj = provClass.newInstance(); - if (!(obj instanceof Provider)) { - MessageFormat form = new MessageFormat - (rb.getString("provName.not.a.provider")); - Object[] source = {provName}; - throw new Exception(form.format(source)); - } - Provider p = (Provider) obj; - String provArg = provider.snd; - if (provArg != null) { - p = p.configure(provArg); - } - Security.addProvider(p); } } @@ -4132,27 +4149,40 @@ public final class Main { System.err.println(rb.getString("Options.")); System.err.println(); - // Left and right sides of the options list + // Left and right sides of the options list. Both might + // contain "\n" and span multiple lines String[] left = new String[command.options.length]; String[] right = new String[command.options.length]; - // Check if there's an unknown option - boolean found = false; - // Length of left side of options list int lenLeft = 0; - for (int j=0; j lenLeft) { - lenLeft = left[j].length(); + if (opt.arg != null) { + left[j] += " " + opt.arg; + } + String[] lefts = left[j].split("\n"); + for (String s : lefts) { + if (s.length() > lenLeft) { + lenLeft = s.length(); + } } right[j] = rb.getString(opt.description); } - for (int j=0; j>", "read"; }; grant codeBase "jrt:/java.sql" { diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java index 35cceda0757..661b50dafdb 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java @@ -235,13 +235,14 @@ public final class UcryptoProvider extends Provider { @Override public Provider configure(String configArg) throws InvalidParameterException { - // default policy entry only grants read access to default config - if (!defConfigName.equals(configArg)) { - throw new InvalidParameterException("Ucrypto provider can only be " + - "configured with default configuration file"); + try { + init(configArg); + } catch (UcryptoException ue) { + InvalidParameterException ipe = + new InvalidParameterException("Error using " + configArg); + ipe.initCause(ue.getCause()); + throw ipe; } - // re-read the config - init(defConfigName); return this; } diff --git a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index c0ea87c8986..10dcb2731b9 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -118,7 +118,8 @@ public class Main { boolean protectedPath; // protected authentication path String storetype; // keystore type String providerName; // provider name - Vector providers = null; // list of providers + List providers = null; // list of provider names + List providerClasses = null; // list of provider classes // arguments for provider constructors HashMap providerArgs = new HashMap<>(); char[] keypass; // private key password @@ -174,30 +175,36 @@ public class Main { // Try to load and install the specified providers if (providers != null) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - Enumeration e = providers.elements(); - while (e.hasMoreElements()) { - String provName = e.nextElement(); - Class provClass; - if (cl != null) { - provClass = cl.loadClass(provName); - } else { - provClass = Class.forName(provName); + for (String provName: providers) { + try { + KeyStoreUtil.loadProviderByName(provName, + providerArgs.get(provName)); + if (debug) { + System.out.println("loadProviderByName: " + provName); + } + } catch (IllegalArgumentException e) { + throw new Exception(String.format(rb.getString( + "provider.name.not.found"), provName)); } + } + } - Object obj = provClass.newInstance(); - if (!(obj instanceof Provider)) { - MessageFormat form = new MessageFormat(rb.getString - ("provName.not.a.provider")); - Object[] source = {provName}; - throw new Exception(form.format(source)); + if (providerClasses != null) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + for (String provClass: providerClasses) { + try { + KeyStoreUtil.loadProviderByClass(provClass, + providerArgs.get(provClass), cl); + if (debug) { + System.out.println("loadProviderByClass: " + provClass); + } + } catch (ClassCastException cce) { + throw new Exception(String.format(rb.getString( + "provclass.not.a.provider"), provClass)); + } catch (IllegalArgumentException e) { + throw new Exception(String.format(rb.getString( + "provider.class.not.found"), provClass), e.getCause()); } - Provider p = (Provider) obj; - String provArg = providerArgs.get(provName); - if (provArg != null) { - p = p.configure(provArg); - } - Security.addProvider(p); } } @@ -335,11 +342,26 @@ public class Main { } else if (collator.compare(flags, "-providerName") ==0) { if (++n == args.length) usageNoArg(); providerName = args[n]; - } else if ((collator.compare(flags, "-provider") == 0) || - (collator.compare(flags, "-providerClass") == 0)) { + } else if (collator.compare(flags, "-provider") == 0 || + collator.compare(flags, "-providerClass") == 0) { + if (++n == args.length) usageNoArg(); + if (providerClasses == null) { + providerClasses = new ArrayList<>(3); + } + providerClasses.add(args[n]); + + if (args.length > (n+1)) { + flags = args[n+1]; + if (collator.compare(flags, "-providerArg") == 0) { + if (args.length == (n+2)) usageNoArg(); + providerArgs.put(args[n], args[n+2]); + n += 2; + } + } + } else if (collator.compare(flags, "-addprovider") == 0) { if (++n == args.length) usageNoArg(); if (providers == null) { - providers = new Vector(3); + providers = new ArrayList<>(3); } providers.add(args[n]); @@ -584,9 +606,14 @@ public class Main { (".providerName.name.provider.name")); System.out.println(); System.out.println(rb.getString - (".providerClass.class.name.of.cryptographic.service.provider.s")); + (".add.provider.option")); System.out.println(rb.getString - (".providerArg.arg.master.class.file.and.constructor.argument")); + (".providerArg.option.1")); + System.out.println(); + System.out.println(rb.getString + (".providerClass.option")); + System.out.println(rb.getString + (".providerArg.option.2")); System.out.println(); System.out.println(rb.getString (".strict.treat.warnings.as.errors")); diff --git a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index 87c72f2046c..6198cd40ce9 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -40,8 +40,9 @@ public class Resources extends java.util.ListResourceBundle { {"6SPACE", " "}, {"COMMA", ", "}, - {"provName.not.a.provider", "{0} not a provider"}, - {"signerClass.is.not.a.signing.mechanism", "{0} is not a signing mechanism"}, + {"provclass.not.a.provider", "%s not a provider"}, + {"provider.name.not.found", "Provider named \"%s\" not found"}, + {"provider.class.not.found", "Provider \"%s\" not found"}, {"jarsigner.error.", "jarsigner error: "}, {"Illegal.option.", "Illegal option: "}, {"This.option.is.deprecated", "This option is deprecated: "}, @@ -105,10 +106,14 @@ public class Resources extends java.util.ListResourceBundle { "[-protected] keystore has protected authentication path"}, {".providerName.name.provider.name", "[-providerName ] provider name"}, - {".providerClass.class.name.of.cryptographic.service.provider.s", - "[-providerClass name of cryptographic service provider's"}, - {".providerArg.arg.master.class.file.and.constructor.argument", - " [-providerArg ]] ... master class file and constructor argument"}, + {".add.provider.option", + "[-addprovider add security provider by name (e.g. SunPKCS11)"}, + {".providerArg.option.1", + " [-providerArg ]] ... configure argument for -addprovider"}, + {".providerClass.option", + "[-providerClass add security provider by fully-qualified class name"}, + {".providerArg.option.2", + " [-providerArg ]] ... configure argument for -providerClass"}, {".strict.treat.warnings.as.errors", "[-strict] treat warnings as errors"}, {".conf.url.specify.a.pre.configured.options.file", diff --git a/jdk/test/sun/security/pkcs11/fips/ImportKeyStore.java b/jdk/test/sun/security/pkcs11/fips/ImportKeyStore.java index 302df9280e6..8fecb2b2692 100644 --- a/jdk/test/sun/security/pkcs11/fips/ImportKeyStore.java +++ b/jdk/test/sun/security/pkcs11/fips/ImportKeyStore.java @@ -37,7 +37,7 @@ setenv LD_LIBRARY_PATH $WS/test/sun/security/pkcs11/nss/lib/solaris-sparc modutil -create -dbdir . modutil -changepw "NSS Internal PKCS #11 Module" -dbdir . -$JHOME/bin/keytool -list -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerarg "--name=NSS\nnssSecmodDirectory=." -v -storepass test12 +$JHOME/bin/keytool -list -storetype PKCS11 -addprovider SunPKCS11 -providerarg "--name=NSS\nnssSecmodDirectory=." -v -storepass test12 modutil -fips true -dbdir . diff --git a/jdk/test/sun/security/tools/jarsigner/AltProvider.java b/jdk/test/sun/security/tools/jarsigner/AltProvider.java new file mode 100644 index 00000000000..5c7e5a286c0 --- /dev/null +++ b/jdk/test/sun/security/tools/jarsigner/AltProvider.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016, 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 4906940 8130302 + * @summary -providerPath, -providerClass, -addprovider, and -providerArg + * @library /lib/testlibrary /test/lib/share/classes + * @modules java.base/jdk.internal.misc + */ + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.testlibrary.JarUtils; + +import java.nio.file.*; + +public class AltProvider { + + private static final String TEST_SRC = + Paths.get(System.getProperty("test.src")).toString(); + + private static final Path MOD_SRC_DIR = Paths.get(TEST_SRC, "alt"); + private static final Path MOD_DEST_DIR = Paths.get("mods"); + + private static final String ktCommand = "-keystore x.jks " + + "-storepass changeit -storetype dummyks -list -debug"; + + private static final String jsCommand = "-keystore x.jks " + + "-storepass changeit -storetype dummyks -debug x.jar x"; + + public static void main(String[] args) throws Throwable { + + // Compile the provider + CompilerUtils.compile( + MOD_SRC_DIR, MOD_DEST_DIR, + "-modulesourcepath", + MOD_SRC_DIR.toString()); + + // Create a keystore + tool("keytool", "-keystore x.jks -storetype jks -genkeypair" + + " -storepass changeit -keypass changeit -alias x -dname CN=X") + .shouldHaveExitValue(0); + + // Create a jar file + JarUtils.createJar("x.jar", "x.jks"); + + // Test starts here + + // Without new provider + testBoth("", 1, "DUMMYKS not found"); + + // legacy use (-providerPath only supported by keytool) + testKeytool("-providerPath mods/test.dummy " + + "-providerClass org.test.dummy.DummyProvider -providerArg full", + 0, "loadProviderByClass: org.test.dummy.DummyProvider"); + + // legacy, on classpath + testBoth("-J-cp -Jmods/test.dummy " + + "-providerClass org.test.dummy.DummyProvider -providerArg full", + 0, "loadProviderByClass: org.test.dummy.DummyProvider"); + + // Wrong name + testBoth("-J-cp -Jmods/test.dummy " + + "-providerClass org.test.dummy.Dummy -providerArg full", + 1, "Provider \"org.test.dummy.Dummy\" not found"); + + // Not a provider name + testBoth("-J-cp -Jmods/test.dummy " + + "-providerClass java.lang.Object -providerArg full", + 1, "java.lang.Object not a provider"); + + // without arg + testBoth("-J-cp -Jmods/test.dummy " + + "-providerClass org.test.dummy.DummyProvider", + 1, "DUMMYKS not found"); + + // old -provider still works + testBoth("-J-cp -Jmods/test.dummy " + + "-provider org.test.dummy.DummyProvider -providerArg full", + 0, "loadProviderByClass: org.test.dummy.DummyProvider"); + + // name in a module + testBoth("-J-mp -Jmods " + + "-addprovider Dummy -providerArg full", + 0, "loadProviderByName: Dummy"); + + // -providerClass does not work + testBoth("-J-mp -Jmods " + + "-providerClass org.test.dummy.DummyProvider -providerArg full", + 1, "Provider \"org.test.dummy.DummyProvider\" not found"); + + // -addprovider with class does not work + testBoth("-J-mp -Jmods " + + "-addprovider org.test.dummy.DummyProvider -providerArg full", + 1, "Provider named \"org.test.dummy.DummyProvider\" not found"); + + // -addprovider without arg does not work + testBoth("-J-mp -Jmods " + + "-addprovider Dummy", + 1, "DUMMYKS not found"); + } + + // Test both tools with the same extra options + private static void testBoth(String args, int exitValue, String contains) + throws Throwable { + testKeytool(args, exitValue, contains); + testJarsigner(args, exitValue, contains); + } + + // Test keytool with extra options and check exitValue and output + private static void testKeytool(String args, int exitValue, String contains) + throws Throwable { + tool("keytool", ktCommand + " " + args) + .shouldHaveExitValue(exitValue) + .shouldContain(contains); + } + + // Test jarsigner with extra options and check exitValue and output + private static void testJarsigner(String args, int exitValue, String contains) + throws Throwable { + tool("jarsigner", jsCommand + " " + args) + .shouldHaveExitValue(exitValue) + .shouldContain(contains); + } + + // Launch a tool with args (space separated string) + private static OutputAnalyzer tool(String tool, String args) + throws Throwable { + JDKToolLauncher l = JDKToolLauncher.createUsingTestJDK(tool); + for (String a: args.split("\\s+")) { + if (a.startsWith("-J")) { + l.addVMArg(a.substring(2)); + } else { + l.addToolArg(a); + } + } + return ProcessTools.executeCommand(l.getCommand()); + } +} diff --git a/jdk/test/sun/security/tools/jarsigner/alt/test.dummy/module-info.java b/jdk/test/sun/security/tools/jarsigner/alt/test.dummy/module-info.java new file mode 100644 index 00000000000..503e64f365a --- /dev/null +++ b/jdk/test/sun/security/tools/jarsigner/alt/test.dummy/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 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. + */ + +module test.dummy { + provides java.security.Provider with org.test.dummy.DummyProvider; +} diff --git a/jdk/test/sun/security/tools/keytool/DummyProvider.java b/jdk/test/sun/security/tools/jarsigner/alt/test.dummy/org/test/dummy/DummyProvider.java similarity index 89% rename from jdk/test/sun/security/tools/keytool/DummyProvider.java rename to jdk/test/sun/security/tools/jarsigner/alt/test.dummy/org/test/dummy/DummyProvider.java index 6ff07b39ec4..99647e31e08 100644 --- a/jdk/test/sun/security/tools/keytool/DummyProvider.java +++ b/jdk/test/sun/security/tools/jarsigner/alt/test.dummy/org/test/dummy/DummyProvider.java @@ -21,22 +21,22 @@ * questions. */ -/* - * - * - * @bug 4906490 - * @summary Dummy security service provider. - * It is cited by the AltProviderPath.sh script. - */ package org.test.dummy; -import java.util.*; import java.security.*; public class DummyProvider extends Provider { public DummyProvider() { - super("Dummy", 0.1, "Dummy Provider"); + super("Dummy", 0.1, "Dummy Provider with nothing"); + } + @Override + public Provider configure(String configArg) { + return new DummyProvider(configArg); + } + + private DummyProvider(String arg) { + super("Dummy", 0.2, "Dummy Provider with " + arg); // // KeyStore // diff --git a/jdk/test/sun/security/tools/keytool/AltProviderPath.sh b/jdk/test/sun/security/tools/keytool/AltProviderPath.sh deleted file mode 100644 index d19ace1a8d2..00000000000 --- a/jdk/test/sun/security/tools/keytool/AltProviderPath.sh +++ /dev/null @@ -1,122 +0,0 @@ -# -# Copyright (c) 2004, 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 -# @bug 4906940 -# @summary Add -providerPath option for keytool allowing one to specify -# an additional classpath to search for providers. -# @author Andrew Fan -# -# @run build DummyProvider -# @run shell AltProviderPath.sh -# set a few environment variables so that the shell-script can run stand-alone -# in the source directory -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi -if [ "${TESTCLASSES}" = "" ] ; then - TESTCLASSES="." -fi -if [ "${TESTJAVA}" = "" ] ; then - echo "TESTJAVA not set. Test cannot execute." - echo "FAILED!!!" - exit 1 -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin | AIX ) - NULL=/dev/null - PS=":" - FS="/" - ;; - CYGWIN* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - ;; - * ) - echo "Unrecognized operating system!" - exit 1; - ;; -esac - -# the test code -#genkey -${TESTJAVA}${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -genkey -v -alias dummyTestCA \ - -keyalg "RSA" -keysize 1024 -sigalg "ShA1WithRSA" \ - -dname "cn=Dummy Test CA, ou=JSN, o=JavaSoft, c=US" -validity 3650 \ - -keypass storepass -keystore keystoreCA.dks -storepass storepass \ - -storetype "dummyks" -provider "org.test.dummy.DummyProvider" \ - -providerPath ${TESTCLASSES} - -if [ $? -ne 0 ]; then - exit 1 -fi - -#Change keystore password -${TESTJAVA}${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepasswd -new storepass2 \ - -keystore keystoreCA.dks -storetype "dummyks" -storepass storepass \ - -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} - -if [ $? -ne 0 ]; then - exit 1 -fi - - -#Change keystore key password -${TESTJAVA}${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -keypasswd -alias "dummyTestCA" \ - -keypass storepass -new keypass -keystore keystoreCA.dks \ - -storetype "dummyks" -storepass storepass2 \ - -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} - -if [ $? -ne 0 ]; then - exit 1 -fi - -#Export certificate -${TESTJAVA}${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -v -export -rfc -alias "dummyTestCA" \ - -file "dummyTestCA.der" -keystore keystoreCA.dks -storetype "dummyks" \ - -storepass storepass2 -provider "org.test.dummy.DummyProvider" \ - -providerPath ${TESTCLASSES} - -if [ $? -ne 0 ]; then - exit 1 -fi - -#list keystore -${TESTJAVA}${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -v -list -keystore keystoreCA.dks \ - -storetype "dummyks" -storepass storepass2 \ - -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} - -if [ $? -ne 0 ]; then - exit 1 -fi - -exit 0 diff --git a/jdk/test/sun/security/tools/keytool/KeyToolTest.java b/jdk/test/sun/security/tools/keytool/KeyToolTest.java index a036db96da0..a783c4e9dbd 100644 --- a/jdk/test/sun/security/tools/keytool/KeyToolTest.java +++ b/jdk/test/sun/security/tools/keytool/KeyToolTest.java @@ -82,8 +82,9 @@ public class KeyToolTest { static final String NSS_P11_ARG = "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nss " + - "-providerClass sun.security.pkcs11.SunPKCS11 " + + "-addprovider SunPKCS11 " + "-providerArg p11-nss.txt "; + // Use -providerClass here, to confirm it still works for SunPKCS11. static final String NSS_SRC_P11_ARG = "-srckeystore NONE -srcstoretype PKCS11 " + "-srcproviderName SunPKCS11-nss " + @@ -91,12 +92,12 @@ public class KeyToolTest { "-providerArg p11-nss.txt "; static final String NZZ_P11_ARG = "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nzz " + - "-providerClass sun.security.pkcs11.SunPKCS11 " + + "-addprovider SunPKCS11 " + "-providerArg p11-nzz.txt "; static final String NZZ_SRC_P11_ARG = "-srckeystore NONE -srcstoretype PKCS11 " + "-srcproviderName SunPKCS11-nzz " + - "-providerClass sun.security.pkcs11.SunPKCS11 " + + "-addprovider SunPKCS11 " + "-providerArg p11-nzz.txt "; static final String SUN_P11_ARG = "-keystore NONE -storetype PKCS11 "; static final String SUN_SRC_P11_ARG = @@ -1715,9 +1716,9 @@ public class KeyToolTest { // 14. keytool -printcert -file cert testOK("", "-printcert -file cert -keystore x.jks -storetype JKS"); remove("cert"); - // 15. keytool -list -storepass password -provider sun.security.provider.Sun + // 15. keytool -list -storepass password -addprovider SUN testOK("", "-list -storepass password" + - " -provider sun.security.provider.Sun" + + " -addprovider SUN" + " -keystore x.jks -storetype JKS"); //Error tests diff --git a/jdk/test/sun/security/tools/keytool/i18n.html b/jdk/test/sun/security/tools/keytool/i18n.html index 4803c3d24bb..86d125a5e52 100644 --- a/jdk/test/sun/security/tools/keytool/i18n.html +++ b/jdk/test/sun/security/tools/keytool/i18n.html @@ -50,7 +50,7 @@ from keytool is correct (you can read everything in english fine).
  • keytool -import -v -file /tmp/cert -storepass password Check error (Certificate reply and cert are the same)
  • keytool -printcert -file /tmp/cert -
  • keytool -list -storepass password -provider sun.security.provider.Sun +
  • keytool -list -storepass password -addprovider SUN Error tests @@ -93,19 +93,19 @@ PKCS#11 tests
    1. sccs edit cert8.db key3.db -
    2. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -genkey -alias genkey -dname cn=genkey -keysize 512 -keyalg rsa -
    3. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -list -
    4. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -list -alias genkey -
    5. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -certreq -alias genkey -file genkey.certreq -
    6. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -export -alias genkey -file genkey.cert +
    7. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -genkey -alias genkey -dname cn=genkey -keysize 512 -keyalg rsa +
    8. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -list +
    9. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -list -alias genkey +
    10. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -certreq -alias genkey -file genkey.certreq +
    11. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -export -alias genkey -file genkey.cert
    12. keytool -printcert -file genkey.cert -
    13. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -selfcert -alias genkey -dname cn=selfCert +
    14. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -selfcert -alias genkey -dname cn=selfCert -
    15. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -list -alias genkey -v +
    16. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -list -alias genkey -v (check that cert subject DN is [cn=selfCert]) -
    17. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -delete -alias genkey -
    18. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -providerClass sun.security.pkcs11.SunPKCS11 -providerArg p11-nss.txt -list +
    19. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -delete -alias genkey +
    20. keytool -keystore NONE -storepass test12 -storetype PKCS11 -providerName SunPKCS11-nss -addprovider SunPKCS11 -providerArg p11-nss.txt -list (check for empty database listing)
    21. sccs unedit cert8.db key3.db From d5e84de014424422748dd1cda4fdedc5a72cef30 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 12 Jul 2016 11:29:01 +0100 Subject: [PATCH 13/43] 8159245: Loggers created by system classes are not initialized correctly when configured programmatically from application code Loggers of the same name now share the same configuration. Reviewed-by: mchung, mli --- .../classes/java/util/logging/LogManager.java | 18 +- .../classes/java/util/logging/Logger.java | 243 ++++++++-- .../Logger/default/DefaultLoggerTest.java | 8 +- .../DefaultLoggerFinderTest.java | 7 +- .../DefaultLoggerBridgeTest.java | 14 +- .../DefaultPlatformLoggerTest.java | 13 +- .../util/logging/SystemLoggerConfigTest.java | 423 ++++++++++++++++++ 7 files changed, 673 insertions(+), 53 deletions(-) create mode 100644 jdk/test/java/util/logging/SystemLoggerConfigTest.java diff --git a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java index f429452419e..e8f96449fae 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, 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 @@ -387,11 +387,15 @@ public class LogManager { assert rootLogger == null; assert initializedCalled && !initializationDone; + // create root logger before reading primordial + // configuration - to ensure that it will be added + // before the global logger, and not after. + owner.rootLogger = owner.new RootLogger(); + // Read configuration. owner.readPrimordialConfiguration(); // Create and retain Logger for the root of the namespace. - owner.rootLogger = owner.new RootLogger(); owner.addLogger(owner.rootLogger); if (!owner.rootLogger.isLevelInitialized()) { owner.rootLogger.setLevel(defaultLevel); @@ -516,7 +520,7 @@ public class LogManager { if (result == null) { // only allocate the new logger once Logger newLogger = new Logger(name, resourceBundleName, - module == null ? null : module, this, false); + module, this, false); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we @@ -569,15 +573,13 @@ public class LogManager { } while (logger == null); // LogManager will set the sysLogger's handlers via LogManager.addLogger method. - if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) { - // if logger already exists but handlers not set + if (logger != sysLogger) { + // if logger already exists we merge the two logger configurations. final Logger l = logger; AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - for (Handler hdl : l.accessCheckedHandlers()) { - sysLogger.addHandler(hdl); - } + l.mergeWithSystemLogger(sysLogger); return null; } }); diff --git a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java index ca055b06af1..b196283a6bd 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java @@ -259,13 +259,185 @@ public class Logger { private static final RuntimePermission GET_CLASS_LOADER_PERMISSION = new RuntimePermission("getClassLoader"); + // A value class that holds the logger configuration data. + // This configuration can be shared between an application logger + // and a system logger of the same name. + private static final class ConfigurationData { + + // The delegate field is used to avoid races while + // merging configuration. This will ensure that any pending + // configuration action on an application logger will either + // be finished before the merge happens, or will be forwarded + // to the system logger configuration after the merge is completed. + // By default delegate=this. + private volatile ConfigurationData delegate; + + volatile boolean useParentHandlers; + volatile Filter filter; + volatile Level levelObject; + volatile int levelValue; // current effective level value + final CopyOnWriteArrayList handlers = + new CopyOnWriteArrayList<>(); + + ConfigurationData() { + delegate = this; + useParentHandlers = true; + levelValue = Level.INFO.intValue(); + } + + void setUseParentHandlers(boolean flag) { + useParentHandlers = flag; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.useParentHandlers = useParentHandlers; + } + } + } + + void setFilter(Filter f) { + filter = f; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.filter = filter; + } + } + } + + void setLevelObject(Level l) { + levelObject = l; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.levelObject = levelObject; + } + } + } + + void setLevelValue(int v) { + levelValue = v; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.levelValue = levelValue; + } + } + } + + void addHandler(Handler h) { + if (handlers.add(h)) { + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.handlers.addIfAbsent(h); + } + } + } + } + + void removeHandler(Handler h) { + if (handlers.remove(h)) { + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.handlers.remove(h); + } + } + } + } + + ConfigurationData merge(Logger systemPeer) { + if (!systemPeer.isSystemLogger) { + // should never come here + throw new InternalError("not a system logger"); + } + + ConfigurationData system = systemPeer.config; + + if (system == this) { + // nothing to do + return system; + } + + synchronized (system) { + // synchronize before checking on delegate to counter + // race conditions where two threads might attempt to + // merge concurrently + if (delegate == system) { + // merge already performed; + return system; + } + + // publish system as the temporary delegate configuration. + // This should take care of potential race conditions where + // an other thread might attempt to call e.g. setlevel on + // the application logger while merge is in progress. + // (see implementation of ConfigurationData::setLevel) + delegate = system; + + // merge this config object data into the system config + system.useParentHandlers = useParentHandlers; + system.filter = filter; + system.levelObject = levelObject; + system.levelValue = levelValue; + + // Prevent race condition in case two threads attempt to merge + // configuration and add handlers at the same time. We don't want + // to add the same handlers twice. + // + // Handlers are created and loaded by LogManager.addLogger. If we + // reach here, then it means that the application logger has + // been created first and added with LogManager.addLogger, and the + // system logger was created after - and no handler has been added + // to it by LogManager.addLogger. Therefore, system.handlers + // should be empty. + // + // A non empty cfg.handlers list indicates a race condition + // where two threads might attempt to merge the configuration + // or add handlers concurrently. Though of no consequence for + // the other data (level etc...) this would be an issue if we + // added the same handlers twice. + // + for (Handler h : handlers) { + if (!system.handlers.contains(h)) { + systemPeer.addHandler(h); + } + } + system.handlers.retainAll(handlers); + system.handlers.addAllAbsent(handlers); + } + + // sanity: update effective level after merging + synchronized(treeLock) { + systemPeer.updateEffectiveLevel(); + } + + return system; + } + + } + + // The logger configuration data. Ideally, this should be final + // for system loggers, and replace-once for application loggers. + // When an application requests a logger by name, we do not know a-priori + // whether that corresponds to a system logger name or not. + // So if no system logger by that name already exists, we simply return an + // application logger. + // If a system class later requests a system logger of the same name, then + // the application logger and system logger configurations will be merged + // in a single instance of ConfigurationData that both loggers will share. + private volatile ConfigurationData config; + private volatile LogManager manager; private String name; - private final CopyOnWriteArrayList handlers = - new CopyOnWriteArrayList<>(); private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE; - private volatile boolean useParentHandlers = true; - private volatile Filter filter; private boolean anonymous; // Cache to speed up behavior of findResourceBundle: @@ -280,8 +452,6 @@ public class Logger { // references from children to parents. private volatile Logger parent; // our nearest parent. private ArrayList kids; // WeakReferences to loggers that have us as parent - private volatile Level levelObject; - private volatile int levelValue; // current effective level value private WeakReference callerModuleRef; private final boolean isSystemLogger; @@ -384,9 +554,29 @@ public class Logger { LogManager manager, boolean isSystemLogger) { this.manager = manager; this.isSystemLogger = isSystemLogger; - setupResourceInfo(resourceBundleName, caller); + this.config = new ConfigurationData(); this.name = name; - levelValue = Level.INFO.intValue(); + setupResourceInfo(resourceBundleName, caller); + } + + // Called by LogManager when a system logger is created + // after a user logger of the same name. + // Ensure that both loggers will share the same + // configuration. + final void mergeWithSystemLogger(Logger system) { + // sanity checks + if (!system.isSystemLogger + || anonymous + || name == null + || !name.equals(system.name)) { + // should never come here + throw new InternalError("invalid logger merge"); + } + checkPermission(); + final ConfigurationData cfg = config; + if (cfg != system.config) { + config = cfg.merge(system); + } } private void setCallerModuleRef(Module callerModule) { @@ -408,7 +598,7 @@ public class Logger { // The manager field is not initialized here. this.name = name; this.isSystemLogger = true; - levelValue = Level.INFO.intValue(); + config = new ConfigurationData(); } // It is called from LoggerContext.addLocalLogger() when the logger @@ -451,7 +641,7 @@ public class Logger { private static Logger demandLogger(String name, String resourceBundleName, Class caller) { LogManager manager = LogManager.getLogManager(); if (!SystemLoggerHelper.disableCallerCheck) { - if (caller.getClassLoader() == null) { + if (isSystem(caller.getModule())) { return manager.demandSystemLogger(name, resourceBundleName, caller); } } @@ -740,7 +930,7 @@ public class Logger { */ public void setFilter(Filter newFilter) throws SecurityException { checkPermission(); - filter = newFilter; + config.setFilter(newFilter); } /** @@ -749,7 +939,7 @@ public class Logger { * @return a filter object (may be null) */ public Filter getFilter() { - return filter; + return config.filter; } /** @@ -765,7 +955,7 @@ public class Logger { if (!isLoggable(record.getLevel())) { return; } - Filter theFilter = filter; + Filter theFilter = config.filter; if (theFilter != null && !theFilter.isLoggable(record)) { return; } @@ -784,7 +974,7 @@ public class Logger { } final boolean useParentHdls = isSystemLogger - ? logger.useParentHandlers + ? logger.config.useParentHandlers : logger.getUseParentHandlers(); if (!useParentHdls) { @@ -1804,13 +1994,13 @@ public class Logger { public void setLevel(Level newLevel) throws SecurityException { checkPermission(); synchronized (treeLock) { - levelObject = newLevel; + config.setLevelObject(newLevel); updateEffectiveLevel(); } } final boolean isLevelInitialized() { - return levelObject != null; + return config.levelObject != null; } /** @@ -1821,7 +2011,7 @@ public class Logger { * @return this Logger's level */ public Level getLevel() { - return levelObject; + return config.levelObject; } /** @@ -1833,6 +2023,7 @@ public class Logger { * @return true if the given message level is currently being logged. */ public boolean isLoggable(Level level) { + int levelValue = config.levelValue; if (level.intValue() < levelValue || levelValue == offValue) { return false; } @@ -1862,7 +2053,7 @@ public class Logger { public void addHandler(Handler handler) throws SecurityException { Objects.requireNonNull(handler); checkPermission(); - handlers.add(handler); + config.addHandler(handler); } /** @@ -1880,7 +2071,7 @@ public class Logger { if (handler == null) { return; } - handlers.remove(handler); + config.removeHandler(handler); } /** @@ -1895,7 +2086,7 @@ public class Logger { // This method should ideally be marked final - but unfortunately // it needs to be overridden by LogManager.RootLogger Handler[] accessCheckedHandlers() { - return handlers.toArray(emptyHandlers); + return config.handlers.toArray(emptyHandlers); } /** @@ -1912,7 +2103,7 @@ public class Logger { */ public void setUseParentHandlers(boolean useParentHandlers) { checkPermission(); - this.useParentHandlers = useParentHandlers; + config.setUseParentHandlers(useParentHandlers); } /** @@ -1922,7 +2113,7 @@ public class Logger { * @return true if output is to be sent to the logger's parent */ public boolean getUseParentHandlers() { - return useParentHandlers; + return config.useParentHandlers; } /** @@ -2256,11 +2447,13 @@ public class Logger { // Figure out our current effective level. int newLevelValue; + final ConfigurationData cfg = config; + final Level levelObject = cfg.levelObject; if (levelObject != null) { newLevelValue = levelObject.intValue(); } else { if (parent != null) { - newLevelValue = parent.levelValue; + newLevelValue = parent.config.levelValue; } else { // This may happen during initialization. newLevelValue = Level.INFO.intValue(); @@ -2268,11 +2461,11 @@ public class Logger { } // If our effective value hasn't changed, we're done. - if (levelValue == newLevelValue) { + if (cfg.levelValue == newLevelValue) { return; } - levelValue = newLevelValue; + cfg.setLevelValue(newLevelValue); // System.err.println("effective level: \"" + getName() + "\" := " + level); diff --git a/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java b/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java index 63ab20e2777..4a2be556bf9 100644 --- a/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java +++ b/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java @@ -539,6 +539,7 @@ public class DefaultLoggerTest { throw new RuntimeException("identical loggers"); } + final java.util.logging.Logger sink; final java.util.logging.Logger appSink; final java.util.logging.Logger sysSink; final java.util.logging.Handler appHandler; @@ -548,10 +549,9 @@ public class DefaultLoggerTest { try { appSink = java.util.logging.Logger.getLogger("foo"); sysSink = accessSystemLogger.demandSystemLogger("foo"); - appSink.addHandler(appHandler = new MyHandler()); - sysSink.addHandler(sysHandler = new MyHandler()); - appSink.setUseParentHandlers(false); - sysSink.setUseParentHandlers(false); + sink = java.util.logging.Logger.getLogger("foo"); + sink.addHandler(appHandler = sysHandler = new MyHandler()); + sink.setUseParentHandlers(false); provider = LoggerFinder.getLoggerFinder(); } finally { allowAll.get().set(false); diff --git a/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java index 43150eb0f00..5a84b16a0ed 100644 --- a/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java @@ -299,10 +299,9 @@ public class DefaultLoggerFinderTest { final java.util.logging.Logger appSink = java.util.logging.Logger.getLogger("foo"); final java.util.logging.Logger sysSink = accessSystemLogger.demandSystemLogger("foo"); - appSink.addHandler(new MyHandler()); - sysSink.addHandler(new MyHandler()); - appSink.setUseParentHandlers(VERBOSE); - sysSink.setUseParentHandlers(VERBOSE); + final java.util.logging.Logger sink = java.util.logging.Logger.getLogger("foo"); + sink.addHandler(new MyHandler()); + sink.setUseParentHandlers(VERBOSE); Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { LoggerFinder provider; diff --git a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java index c796cd1888d..cba6f7b1b44 100644 --- a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -390,6 +390,7 @@ public class DefaultLoggerBridgeTest { throw new RuntimeException("identical loggers"); } + final java.util.logging.Logger sink; final java.util.logging.Logger appSink; final java.util.logging.Logger sysSink; final MyHandler appHandler; @@ -404,10 +405,13 @@ public class DefaultLoggerBridgeTest { if (appSink == sysSink) { throw new RuntimeException("identical backend loggers"); } - appSink.addHandler(appHandler = new MyHandler()); - sysSink.addHandler(sysHandler = new MyHandler()); - appSink.setUseParentHandlers(VERBOSE); - sysSink.setUseParentHandlers(VERBOSE); + sink = java.util.logging.Logger.getLogger("foo"); + if (appSink != sink) { + throw new RuntimeException("expected same application logger"); + } + + sink.addHandler(appHandler = sysHandler = new MyHandler()); + sink.setUseParentHandlers(VERBOSE); } finally { allowAll.get().set(old); } diff --git a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java index 99b7ee38b2a..200b169b7c7 100644 --- a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -42,9 +42,9 @@ import java.util.logging.Handler; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.lang.System.LoggerFinder; +import java.util.logging.Logger; import sun.util.logging.PlatformLogger; import sun.util.logging.internal.LoggingProviderImpl; -import java.lang.reflect.Module; /** * @test @@ -248,10 +248,9 @@ public class DefaultPlatformLoggerTest { DefaultPlatformLoggerTest.class.getModule()); java.util.logging.Logger sysSink = LoggingProviderImpl.getLogManagerAccess() .demandLoggerFor(LogManager.getLogManager(),"foo", Thread.class.getModule()); - appSink.addHandler(new MyHandler()); - sysSink.addHandler(new MyHandler()); - appSink.setUseParentHandlers(VERBOSE); - sysSink.setUseParentHandlers(VERBOSE); + java.util.logging.Logger sink = Logger.getLogger("foo"); + sink.addHandler(new MyHandler()); + sink.setUseParentHandlers(VERBOSE); System.out.println("\n*** Without Security Manager\n"); test(provider, true, appSink, sysSink); @@ -274,7 +273,7 @@ public class DefaultPlatformLoggerTest { public static void test(LoggerFinder provider, boolean hasRequiredPermissions, java.util.logging.Logger appSink, java.util.logging.Logger sysSink) throws Exception { - // No way to giva a resource bundle to a platform logger. + // No way to give a resource bundle to a platform logger. // ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName()); final Map loggerDescMap = new HashMap<>(); diff --git a/jdk/test/java/util/logging/SystemLoggerConfigTest.java b/jdk/test/java/util/logging/SystemLoggerConfigTest.java new file mode 100644 index 00000000000..501e3124bce --- /dev/null +++ b/jdk/test/java/util/logging/SystemLoggerConfigTest.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2016, 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. + */ +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.ref.Reference; +import java.security.Permission; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import sun.util.logging.PlatformLogger; + + +/** + * @test + * @bug 8159245 + * @summary Tests configuration of loggers. + * @modules java.logging/sun.util.logging.internal java.base/sun.util.logging + * @run main/othervm SystemLoggerConfigTest NOSECURITY + * @run main/othervm SystemLoggerConfigTest WITHSECURITY + * + * @author danielfuchs + */ +public class SystemLoggerConfigTest { + + static Logger createSystemLogger(String name) { + return sun.util.logging.internal.LoggingProviderImpl.getLogManagerAccess() + .demandLoggerFor(LogManager.getLogManager(), name, + Thread.class.getModule()); + } + + static PlatformLogger createPlatformLogger(String name) { + return PlatformLogger.getLogger(name); + } + + private static void assertFalse(boolean value, String msg) { + assertEquals(false, value, msg); + } + private static void assertEquals(boolean expected, boolean actual, String msg) { + if (expected != actual) { + throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); + } + } + private static void assertEquals(int expected, int actual, String msg) { + if (expected != actual) { + throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); + } + } + private static void assertEquals(long expected, long actual, String msg) { + if (expected != actual) { + throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); + } + } + private static void assertEquals(Object expected, Object actual, String msg) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); + } + } + + static class TestHandler extends Handler { + private final List records = new CopyOnWriteArrayList<>(); + public TestHandler() { + super(); + setLevel(Level.ALL); + } + + @Override + public void publish(LogRecord lr) { + records.add(lr); + } + + public List drain() { + List list = new ArrayList<>(records); + records.clear(); + return list; + } + + public void close() { + records.clear(); + } + + public void flush() { + } + + } + + public static class TestHandler1 extends TestHandler { + final static AtomicLong COUNT = new AtomicLong(); + public TestHandler1() { + COUNT.incrementAndGet(); + } + } + + public static class TestHandler2 extends TestHandler { + final static AtomicLong COUNT = new AtomicLong(); + public TestHandler2() { + COUNT.incrementAndGet(); + } + } + + static enum TestCase { WITHSECURITY, NOSECURITY } + + public static void main(String[] args) { + if (args == null || args.length == 0) { + args = Stream.of(TestCase.values()) + .map(String::valueOf) + .collect(Collectors.toList()) + .toArray(new String[0]); + } + Stream.of(args) + .map(TestCase::valueOf) + .forEach(SystemLoggerConfigTest::launch); + } + + public static void launch(TestCase test) { + switch(test) { + case WITHSECURITY: + Policy.setPolicy(new Policy() { + @Override + public boolean implies(ProtectionDomain domain, Permission permission) { + return true; + } + }); + System.setSecurityManager(new SecurityManager()); + break; + case NOSECURITY: + break; + default: + throw new InternalError("Unexpected enum: " + test); + } + try { + test(test.name(), ".1", ".child"); + test(test.name(), ".2", ""); + testUpdateConfiguration(test.name(), ".3"); + testSetPlatformLevel(test.name(), ".4"); + } catch (IOException io) { + throw new UncheckedIOException(io); + } + } + + public static void test(String name, String step, String ext) + throws IOException { + + System.out.println("\n*** Testing " + name + step + ext); + + final String systemName1a = "system.logger.one.a." + name + step + ext; + final String systemName1b = "system.logger.one.b." + name + step + ext; + final String appName1a = "system.logger.one.a." + name + step; + final String appName1b = "system.logger.one.b." + name + step; + final String msg1a = "logger name: " + systemName1a; + final String msg1b = "logger name: " + systemName1b; + final String systemName2 = "system.logger.two." + name + step + ext; + final String appName2 = "system.logger.two." + name + step; + final String msg2 = "logger name: " + systemName2; + final String systemName3 = "system.logger.three." + name + step + ext; + final String appName3 = "system.logger.three." + name + step; + final String msg3 = "logger name: " + systemName3; + List records; + + System.out.println("\n[Case #1] Creating platform logger: " + systemName1a); + PlatformLogger system1a = createPlatformLogger(systemName1a); + System.out.println(" Creating platform logger: " + systemName1b); + PlatformLogger system1b = createPlatformLogger(systemName1b); + System.out.println(" Adding handler on root logger..."); + TestHandler test1 = new TestHandler(); + Logger.getLogger("").addHandler(test1); + + System.out.println(" Creating and configuring app logger: " + appName1a + + ", " + appName1b); + Logger app1a = Logger.getLogger(appName1a); + app1a.setLevel(Level.INFO); + Logger app1b = Logger.getLogger(appName1b); + app1b.setLevel(Level.INFO); + assertFalse(system1a.isLoggable(PlatformLogger.Level.FINEST), + "Unexpected level for " + system1a); + System.out.println(" Configuring root logger..."); + Logger.getLogger("").setLevel(Level.FINEST); + System.out.println(" Logging through system logger: " + systemName1a); + system1a.finest(msg1a); + Reference.reachabilityFence(app1a); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + System.out.println(" Logging through system logger: " + systemName1b); + system1b.finest(msg1b); + Reference.reachabilityFence(app1b); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); + records = test1.drain(); + assertEquals("system.logger.one.a", records.get(0).getMessage(), "Unexpected message: "); + Logger.getLogger("").setLevel(Level.INFO); + Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + + Reference.reachabilityFence(system1a); + Reference.reachabilityFence(system1b); + + System.out.println("\n[Case #2] Creating system logger: " + systemName2); + Logger system2 = createSystemLogger(systemName2); + System.out.println(" Creating app logger: " + appName2); + Logger app2 = Logger.getLogger(appName2); + System.out.println(" Configuring app logger..."); + TestHandler test2 = new TestHandler(); + app2.setLevel(Level.ALL); + app2.setUseParentHandlers(false); + app2.addHandler(test2); + System.out.println(" Logging through system logger: " + systemName2); + system2.finest(msg2); + records = test2.drain(); + assertEquals(1, records.size(), "Unexpected size for " + records.toString()); + assertEquals(msg2, records.get(0).getMessage(), "Unexpected message: "); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + + Reference.reachabilityFence(app2); + Reference.reachabilityFence(system2); + + System.out.println("\n[Case #3] Creating app logger: " + appName3); + Logger app3 = Logger.getLogger(appName3); + System.out.println(" Configuring app logger..."); + TestHandler test3 = new TestHandler(); + app3.setLevel(Level.ALL); + app3.setUseParentHandlers(false); + app3.addHandler(test3); + System.out.println(" Creating system logger: " + systemName3); + Logger system3 = createSystemLogger(systemName3); + System.out.println(" Logging through system logger: " + systemName3); + system3.finest(msg3); + records = test3.drain(); + assertEquals(1, records.size(), "Unexpected size for " + records.toString()); + assertEquals(msg3, records.get(0).getMessage(), "Unexpected message: "); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + + Reference.reachabilityFence(app3); + Reference.reachabilityFence(system3); + System.gc(); + + } + + @SuppressWarnings("deprecated") + static void setPlatformLevel(PlatformLogger logger, PlatformLogger.Level level) { + logger.setLevel(level); + } + + public static void testSetPlatformLevel(String name, String step) { + System.out.println("\n*** Testing PlatformLogger.setLevel " + name + step); + + System.out.println("\n[Case #5] Creating app logger: " + name + step); + // this should return named logger in the global context + Logger foo = Logger.getLogger(name + step); + foo.setLevel(Level.FINE); + + System.out.println(" Creating platform logger: " + name + step); + PlatformLogger foo1 = PlatformLogger.getLogger(name + step); + System.out.println(" Configuring platform logger..."); + setPlatformLevel(foo1, PlatformLogger.Level.INFO); + + System.out.println(" Checking levels..."); + assertEquals(foo.getName(), foo1.getName(), "Bad logger names"); + // both logger share the same config + assertEquals(foo.getLevel(), Level.INFO, "Bad level for user logger"); + assertEquals(foo1.level(), PlatformLogger.Level.INFO, + "Bad level for platform logger"); + + } + + static void updateConfiguration(Properties props) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + props.store(baos, ""); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + LogManager.getLogManager().updateConfiguration(bais, (k) -> (o,n) -> n != null ? n : o); + } + + static void readConfiguration(Properties props) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + props.store(baos, ""); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + LogManager.getLogManager().readConfiguration(bais); + } + + // Tests that though two loggers exist, only one handler is created for the + // pair when reading configuration. + // + public static void testUpdateConfiguration(String name, String step) throws IOException { + + System.out.println("\n*** Testing LogManager.updateConfiguration " + name + step); + + final String name1a = "system.logger.one.a." + name + step; + final String name1b = "system.logger.one.b." + name + step; + final String msg1a = "logger name: " + name1a; + final String msg1b = "logger name: " + name1b; + List records; + + TestHandler1.COUNT.set(0); + TestHandler2.COUNT.set(0); + Properties props = new Properties(); + props.setProperty(name1a+".handlers", TestHandler1.class.getName()); + updateConfiguration(props); + assertEquals(0, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + System.out.println("\n[Case #4] Creating app logger: " + name1a); + Logger app1a = Logger.getLogger(name1a); + System.out.println(" Configuring app logger..."); + TestHandler test1 = new TestHandler(); + app1a.setLevel(Level.ALL); + app1a.setUseParentHandlers(false); + app1a.addHandler(test1); + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + System.out.println(" Creating system logger: " + name1a); + Logger system1a = createSystemLogger(name1a); + assertEquals(Level.ALL, system1a.getLevel(), "Bad level for system logger " + name1a); + System.out.println(" Logging through system logger: " + name1a); + system1a.finest(msg1a); + records = test1.drain(); + assertEquals(1, records.size(), "Unexpected size for " + records.toString()); + assertEquals(msg1a, records.get(0).getMessage(), "Unexpected message: "); + records = test1.drain(); + assertEquals(0, records.size(), "Unexpected size for " + records.toString()); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + props.setProperty(name1a+".handlers", TestHandler2.class.getName()); + updateConfiguration(props); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + updateConfiguration(props); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + readConfiguration(props); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + // readConfiguration reset handlers but does not recreate them + assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + updateConfiguration(props); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + LogManager.getLogManager().reset(); + updateConfiguration(props); + + assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(2, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + props.setProperty(name1a+".handlers", + TestHandler2.class.getName() + "," + TestHandler1.class.getName()); + updateConfiguration(props); + + assertEquals(2, TestHandler1.COUNT.get(), "Bad instance count for " + + TestHandler1.class.getName()); + assertEquals(3, TestHandler2.COUNT.get(), "Bad instance count for " + + TestHandler2.class.getName()); + + Reference.reachabilityFence(app1a); + Reference.reachabilityFence(system1a); + + LogManager.getLogManager().readConfiguration(); + System.gc(); + } + + + +} From e4226ff2f23607e4d98ba15731636ec30c96be68 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Tue, 12 Jul 2016 10:58:58 -0300 Subject: [PATCH 14/43] 8161067: jlink: Enable plugins to use the module pool for class lookup Reviewed-by: sundar, psandoz --- .../jlink/internal/ImagePluginStack.java | 8 +++++++ .../jlink/internal/ModuleEntryFactory.java | 24 +++++++++++++++---- .../tools/jlink/internal/ModulePoolImpl.java | 19 +++++++++++++++ .../internal/plugins/ClassForNamePlugin.java | 21 +++++++--------- .../jdk/tools/jlink/plugin/ModulePool.java | 11 ++++++++- jdk/test/tools/jlink/JLinkPluginsTest.java | 8 +++++++ 6 files changed, 73 insertions(+), 18 deletions(-) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java index b8f44d84906..f49683f2fee 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java @@ -399,6 +399,14 @@ public final class ImagePluginStack { return res.isPresent()? Optional.of(getUncompressed(res.get())) : Optional.empty(); } + @Override + public Optional findEntryInContext(String path, ModuleEntry context) { + Objects.requireNonNull(path); + Objects.requireNonNull(context); + Optional res = pool.findEntryInContext(path, context); + return res.map(this::getUncompressed); + } + @Override public boolean contains(ModuleEntry res) { return pool.contains(res); diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryFactory.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryFactory.java index 620e8ffef0b..3d685f00cab 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryFactory.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryFactory.java @@ -51,16 +51,32 @@ public final class ModuleEntryFactory { original.getPath(), original.getType(), file); } - private static String moduleFrom(String path) { + static String moduleFrom(String path) { Objects.requireNonNull(path); if (path.isEmpty() || path.charAt(0) != '/') { throw new IllegalArgumentException(path + " must start with /"); } - String noRoot = path.substring(1); - int idx = noRoot.indexOf('/'); + int idx = path.indexOf('/', 1); if (idx == -1) { throw new IllegalArgumentException("/ missing after module: " + path); } - return noRoot.substring(0, idx); + return path.substring(1, idx); + } + + static String packageFrom(String path) { + Objects.requireNonNull(path); + int idx = path.lastIndexOf('/'); + if (idx == -1) { + throw new IllegalArgumentException("/ missing from path: " + path); + } + if (path.startsWith("/")) { + int jdx = path.indexOf('/', 1); + if (jdx == -1) { + throw new IllegalArgumentException("/ missing after module: " + path); + } + return path.substring(jdx + 1, idx); + } else { + return path.substring(0, idx); + } } } diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java index 467da23ae68..172e21cbb26 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java @@ -264,6 +264,25 @@ public class ModulePoolImpl implements ModulePool { return Optional.ofNullable(resources.get(path)); } + /** + * Get the ModuleEntry for the passed path restricted to supplied context. + * + * @param path A data path + * @param context A context of the search + * @return A ModuleEntry instance or null if the data is not found + */ + @Override + public Optional findEntryInContext(String path, ModuleEntry context) { + Objects.requireNonNull(path); + Objects.requireNonNull(context); + LinkModule module = modules.get(context.getModule()); + Objects.requireNonNull(module); + Optional entry = module.findEntry(path); + // Navigating other modules via requires and exports is problematic + // since we cannot construct the runtime model of loaders and layers. + return entry; + } + /** * Check if the ModulePool contains the given ModuleEntry. * diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ClassForNamePlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ClassForNamePlugin.java index 7f126e4f203..1c8c54705c3 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ClassForNamePlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ClassForNamePlugin.java @@ -28,7 +28,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; +import java.util.Optional; import jdk.tools.jlink.plugin.ModulePool; import jdk.tools.jlink.plugin.Plugin.Category; import jdk.internal.org.objectweb.asm.ClassReader; @@ -67,7 +67,7 @@ public final class ClassForNamePlugin implements Plugin { return index == -1 ? "" : binaryName.substring(0, index); } - private ModuleEntry transform(ModuleEntry resource, Map classes) { + private ModuleEntry transform(ModuleEntry resource, ModulePool pool) { byte[] inBytes = resource.getBytes(); ClassReader cr = new ClassReader(inBytes); ClassNode cn = new ClassNode(); @@ -96,10 +96,11 @@ public final class ClassForNamePlugin implements Plugin { min.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { String ldcClassName = ldc.cst.toString(); String thatClassName = ldcClassName.replaceAll("\\.", "/"); - ModuleEntry thatClass = classes.get(thatClassName); + Optional thatClass = + pool.findEntryInContext(thatClassName + ".class", resource); - if (thatClass != null) { - int thatAccess = getAccess(thatClass); + if (thatClass.isPresent()) { + int thatAccess = getAccess(thatClass.get()); String thatPackage = getPackage(thatClassName); if ((thatAccess & Opcodes.ACC_PRIVATE) != Opcodes.ACC_PRIVATE && @@ -142,19 +143,13 @@ public final class ClassForNamePlugin implements Plugin { public void visit(ModulePool in, ModulePool out) { Objects.requireNonNull(in); Objects.requireNonNull(out); - Map classes = in.entries() - .filter(resource -> resource != null && - resource.getPath().endsWith(".class") && - !resource.getPath().endsWith("/module-info.class")) - .collect(Collectors.toMap(resource -> binaryClassName(resource.getPath()), - resource -> resource)); + in.entries() - .filter(resource -> resource != null) .forEach(resource -> { String path = resource.getPath(); if (path.endsWith(".class") && !path.endsWith("/module-info.class")) { - out.add(transform(resource, classes)); + out.add(transform(resource, in)); } else { out.add(resource); } diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java index 4d0f230e1c6..de24a417293 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java @@ -89,7 +89,16 @@ public interface ModulePool { * @param path A data path * @return A ModuleEntry instance or null if the data is not found */ - public Optional findEntry(String path); + public Optional findEntry(String path); + + /** + * Get the ModuleEntry for the passed path restricted to supplied context. + * + * @param path A data path + * @param context A context of the search + * @return A ModuleEntry instance or null if the data is not found + */ + public Optional findEntryInContext(String path, ModuleEntry context); /** * Check if the ModulePool contains the given ModuleEntry. diff --git a/jdk/test/tools/jlink/JLinkPluginsTest.java b/jdk/test/tools/jlink/JLinkPluginsTest.java index 560fc53f9a3..da9e112238b 100644 --- a/jdk/test/tools/jlink/JLinkPluginsTest.java +++ b/jdk/test/tools/jlink/JLinkPluginsTest.java @@ -75,5 +75,13 @@ public class JLinkPluginsTest { Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); helper.checkImage(imageDir, moduleName, res, null); } + { + // Optimize Class.forName + String[] userOptions = {"--class-for-name"}; + String moduleName = "classforname"; + helper.generateDefaultJModule(moduleName, "composite2"); + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, null, null); + } } } From cd2dd88b9eb786d78acab960a8c63e687160c768 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Tue, 12 Jul 2016 14:39:08 -0700 Subject: [PATCH 15/43] 8161233: ProblemList sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java on macOS Reviewed-by: ascarpino --- jdk/test/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 167e2493cf3..2214bd66fc1 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -284,6 +284,7 @@ sun/security/pkcs11/tls/TestPremaster.java 8077138,8023434 sun/security/krb5/auto/HttpNegotiateServer.java 8038079 generic-all sun/security/tools/keytool/autotest.sh 8130302 generic-all +sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java 8161232 macosx-all ############################################################################ From caddf21da808c1f4a86ef7f61aa6f8da8a9d5b37 Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Wed, 13 Jul 2016 10:26:11 +0800 Subject: [PATCH 16/43] 8132548: java/lang/ThreadGroup/Stop.java fails with "RuntimeException: Failure" Reviewed-by: dholmes, martin, darcy --- jdk/test/java/lang/ThreadGroup/Stop.java | 75 +++++++++--------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/jdk/test/java/lang/ThreadGroup/Stop.java b/jdk/test/java/lang/ThreadGroup/Stop.java index 156bc9d4bdd..c0be8c08fca 100644 --- a/jdk/test/java/lang/ThreadGroup/Stop.java +++ b/jdk/test/java/lang/ThreadGroup/Stop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -28,60 +28,41 @@ * unpredictable results. */ -public class Stop implements Runnable { - private static boolean groupStopped = false ; - private static final Object lock = new Object(); +import java.util.concurrent.CountDownLatch; - private static final ThreadGroup group = new ThreadGroup(""); - private static final Thread first = new Thread(group, new Stop()); - private static final Thread second = new Thread(group, new Stop()); - - public void run() { - while (true) { - // Give the other thread a chance to start - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - - // When the first thread runs, it will stop the group. - if (Thread.currentThread() == first) { - synchronized (lock) { - try { - group.stop(); - } finally { - // Signal the main thread it is time to check - // that the stopped thread group was successful - groupStopped = true; - lock.notifyAll(); - } - } - } - } - } +public class Stop { public static void main(String[] args) throws Exception { + final CountDownLatch ready = new CountDownLatch(1); + final ThreadGroup group = new ThreadGroup(""); + + final Thread second = new Thread(group, () -> { + ready.countDown(); + while (true) { + try { + Thread.sleep(60000); + } catch (InterruptedException shouldNotHappen) { + } + } + }); + + final Thread first = new Thread(group, () -> { + // Wait until "second" is started + try { + ready.await(); + } catch (InterruptedException shouldNotHappen) { + } + // Now stop the group + group.stop(); + }); + // Launch two threads as part of the same thread group first.start(); second.start(); - // Wait for the thread group stop to be issued - synchronized(lock){ - while (!groupStopped) { - lock.wait(); - // Give the other thread a chance to stop - Thread.sleep(1000); - } - } - // Check that the second thread is terminated when the // first thread terminates the thread group. - boolean failed = second.isAlive(); - - // Clean up any threads that may have not been terminated - first.stop(); - second.stop(); - if (failed) - throw new RuntimeException("Failure."); + second.join(); + // Test passed - if never get here the test times out and fails. } } From e4a671e63585264d1020a8c12b41123c1e5d9fec Mon Sep 17 00:00:00 2001 From: Steve Drach Date: Tue, 12 Jul 2016 11:05:27 -0700 Subject: [PATCH 17/43] 8155770: Correct URLClassLoader API documentation to explicitly say jar-scheme URL's are accepted Reviewed-by: psandoz --- .../share/classes/java/net/URLClassLoader.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index 025e9467811..0808a6e9962 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -59,9 +59,11 @@ import sun.security.util.SecurityConstants; /** * This class loader is used to load classes and resources from a search - * path of URLs referring to both JAR files and directories. Any URL that - * ends with a '/' is assumed to refer to a directory. Otherwise, the URL - * is assumed to refer to a JAR file which will be opened as needed. + * path of URLs referring to both JAR files and directories. Any {@code jar:} + * scheme URL (see {@link java.net.JarURLConnection}) is assumed to refer to a + * JAR file. Any {@code file:} scheme URL that ends with a '/' is assumed to + * refer to a directory. Otherwise, the URL is assumed to refer to a JAR file + * which will be opened as needed. *

      * The AccessControlContext of the thread that created the instance of * URLClassLoader will be used when subsequently loading classes and @@ -83,9 +85,11 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { /** * Constructs a new URLClassLoader for the given URLs. The URLs will be * searched in the order specified for classes and resources after first - * searching in the specified parent class loader. Any URL that ends with - * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed - * to refer to a JAR file which will be downloaded and opened as needed. + * searching in the specified parent class loader. Any {@code jar:} + * scheme URL is assumed to refer to a JAR file. Any {@code file:} scheme + * URL that ends with a '/' is assumed to refer to a directory. Otherwise, + * the URL is assumed to refer to a JAR file which will be downloaded and + * opened as needed. * *

      If there is a security manager, this method first * calls the security manager's {@code checkCreateClassLoader} method From c748cd54ac5c8f29bd52fe021b10dc485989a6c7 Mon Sep 17 00:00:00 2001 From: Rob McKenna Date: Wed, 13 Jul 2016 14:56:00 +0100 Subject: [PATCH 18/43] 8141148: LDAP "follow" throws ClassCastException with Java 8 Reviewed-by: prappo, xuelei --- .../com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java | 4 ++-- .../classes/com/sun/jndi/ldap/LdapBindingEnumeration.java | 4 ++-- .../classes/com/sun/jndi/ldap/LdapNamingEnumeration.java | 4 ++-- .../classes/com/sun/jndi/ldap/LdapSearchEnumeration.java | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java index be3315674fa..8bef0da95ca 100644 --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java @@ -300,7 +300,7 @@ abstract class AbstractLdapNamingEnumeration errEx = e; } - protected abstract AbstractLdapNamingEnumeration getReferredResults( + protected abstract AbstractLdapNamingEnumeration getReferredResults( LdapReferralContext refCtx) throws NamingException; /* @@ -360,7 +360,7 @@ abstract class AbstractLdapNamingEnumeration * Merge the entries and/or referrals from the supplied enumeration * with those of the current enumeration. */ - protected void update(AbstractLdapNamingEnumeration ne) { + protected void update(AbstractLdapNamingEnumeration ne) { // Cleanup previous context first homeCtx.decEnumCount(); diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java index 65c80512596..8d385d3d7e7 100644 --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java @@ -104,9 +104,9 @@ final class LdapBindingEnumeration } @Override - protected LdapBindingEnumeration getReferredResults( + protected AbstractLdapNamingEnumeration getReferredResults( LdapReferralContext refCtx) throws NamingException{ // repeat the original operation at the new context - return (LdapBindingEnumeration)refCtx.listBindings(listArg); + return (AbstractLdapNamingEnumeration)refCtx.listBindings(listArg); } } diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapNamingEnumeration.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapNamingEnumeration.java index 422ce79b5fd..c923fda26f7 100644 --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapNamingEnumeration.java +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapNamingEnumeration.java @@ -72,9 +72,9 @@ final class LdapNamingEnumeration } @Override - protected LdapNamingEnumeration getReferredResults( + protected AbstractLdapNamingEnumeration getReferredResults( LdapReferralContext refCtx) throws NamingException { // repeat the original operation at the new context - return (LdapNamingEnumeration)refCtx.list(listArg); + return (AbstractLdapNamingEnumeration)refCtx.list(listArg); } } diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java index 4af58a8b0dd..43d040a1c44 100644 --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java @@ -199,15 +199,15 @@ final class LdapSearchEnumeration } @Override - protected LdapSearchEnumeration getReferredResults( + protected AbstractLdapNamingEnumeration getReferredResults( LdapReferralContext refCtx) throws NamingException { // repeat the original operation at the new context - return (LdapSearchEnumeration)refCtx.search( + return (AbstractLdapNamingEnumeration)refCtx.search( searchArgs.name, searchArgs.filter, searchArgs.cons); } @Override - protected void update(AbstractLdapNamingEnumeration ne) { + protected void update(AbstractLdapNamingEnumeration ne) { super.update(ne); // Update search-specific variables From d996c5d95f88f76fea828c8566ac92217c48171c Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Thu, 7 Jul 2016 21:15:24 -0700 Subject: [PATCH 19/43] 8132379: -J options can cause crash or "Warning: app args parsing error passing arguments as-is" Reviewed-by: ksrini --- jdk/src/java.base/share/native/libjli/args.c | 2 +- .../java.base/windows/native/libjli/java_md.c | 67 +++++++++---------- jdk/test/tools/launcher/Arrrghs.java | 8 ++- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/jdk/src/java.base/share/native/libjli/args.c b/jdk/src/java.base/share/native/libjli/args.c index 268046cd693..55f67f355ce 100644 --- a/jdk/src/java.base/share/native/libjli/args.c +++ b/jdk/src/java.base/share/native/libjli/args.c @@ -130,7 +130,7 @@ static void checkArg(const char *arg) { expectingNoDashArg = JNI_FALSE; } // only update on java mode and not yet found main class - if (firstAppArgIndex == -1 && idx != 0) { + if (firstAppArgIndex == NOT_FOUND && idx != 0) { firstAppArgIndex = (int) idx; } } diff --git a/jdk/src/java.base/windows/native/libjli/java_md.c b/jdk/src/java.base/windows/native/libjli/java_md.c index 65422bc039f..ffe4358e81d 100644 --- a/jdk/src/java.base/windows/native/libjli/java_md.c +++ b/jdk/src/java.base/windows/native/libjli/java_md.c @@ -943,26 +943,6 @@ ProcessPlatformOption(const char *arg) return JNI_FALSE; } -int -filterArgs(StdArg *stdargs, const int nargc, StdArg **pargv) { - StdArg* argv = NULL; - int nargs = 0; - int i; - - /* Copy the non-vm args */ - for (i = 0; i < nargc ; i++) { - const char *arg = stdargs[i].arg; - if (arg[0] == '-' && arg[1] == 'J') - continue; - argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg)); - argv[nargs].arg = JLI_StringDup(arg); - argv[nargs].has_wildcard = stdargs[i].has_wildcard; - nargs++; - } - *pargv = argv; - return nargs; -} - /* * At this point we have the arguments to the application, and we need to * check with original stdargs in order to compare which of these truly @@ -975,12 +955,13 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) int i, j, idx; size_t tlen; jobjectArray outArray, inArray; - char *ostart, *astart, **nargv; + char *arg, **nargv; jboolean needs_expansion = JNI_FALSE; jmethodID mid; - int filteredargc, stdargc; + int stdargc; StdArg *stdargs; - StdArg *filteredargs; + int *appArgIdx; + int isTool; jclass cls = GetLauncherHelperClass(env); NULL_CHECK0(cls); @@ -991,8 +972,6 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) stdargs = JLI_GetStdArgs(); stdargc = JLI_GetStdArgc(); - filteredargc = filterArgs(stdargs, stdargc, &filteredargs); - // sanity check, this should never happen if (argc > stdargc) { JLI_TraceLauncher("Warning: app args is larger than the original, %d %d\n", argc, stdargc); @@ -1001,22 +980,35 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) } // sanity check, match the args we have, to the holy grail - idx = filteredargc - argc; - ostart = filteredargs[idx].arg; - astart = strv[0]; - // sanity check, ensure that the first argument of the arrays are the same - if (JLI_StrCmp(ostart, astart) != 0) { - // some thing is amiss the args don't match - JLI_TraceLauncher("Warning: app args parsing error\n"); - JLI_TraceLauncher("passing arguments as-is\n"); + idx = JLI_GetAppArgIndex(); + isTool = (idx == 0); + if (isTool) { idx++; } // skip tool name + JLI_TraceLauncher("AppArgIndex: %d points to %s\n", idx, stdargs[idx].arg); + + appArgIdx = calloc(argc, sizeof(int)); + for (i = idx, j = 0; i < stdargc; i++) { + if (isTool) { // filter -J used by tools to pass JVM options + arg = stdargs[i].arg; + if (arg[0] == '-' && arg[1] == 'J') { + continue; + } + } + appArgIdx[j++] = i; + } + // sanity check, ensure same number of arguments for application + if (j != argc) { + JLI_TraceLauncher("Warning: app args count doesn't match, %d %d\n", j, argc); + JLI_TraceLauncher("passing arguments as-is.\n"); + JLI_MemFree(appArgIdx); return NewPlatformStringArray(env, strv, argc); } // make a copy of the args which will be expanded in java if required. nargv = (char **)JLI_MemAlloc(argc * sizeof(char*)); - for (i = 0, j = idx; i < argc; i++, j++) { - jboolean arg_expand = (JLI_StrCmp(filteredargs[j].arg, strv[i]) == 0) - ? filteredargs[j].has_wildcard + for (i = 0; i < argc; i++) { + j = appArgIdx[i]; + jboolean arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0) + ? stdargs[j].has_wildcard : JNI_FALSE; if (needs_expansion == JNI_FALSE) needs_expansion = arg_expand; @@ -1039,6 +1031,7 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); + JLI_MemFree(appArgIdx); return NewPlatformStringArray(env, strv, argc); } NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, @@ -1053,6 +1046,6 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); - JLI_MemFree(filteredargs); + JLI_MemFree(appArgIdx); return outArray; } diff --git a/jdk/test/tools/launcher/Arrrghs.java b/jdk/test/tools/launcher/Arrrghs.java index 4d799f35efe..f9bc9f955da 100644 --- a/jdk/test/tools/launcher/Arrrghs.java +++ b/jdk/test/tools/launcher/Arrrghs.java @@ -24,7 +24,7 @@ /** * @test * @bug 5030233 6214916 6356475 6571029 6684582 6742159 4459600 6758881 6753938 - * 6894719 6968053 7151434 7146424 8007333 8077822 8143640 + * 6894719 6968053 7151434 7146424 8007333 8077822 8143640 8132379 * @summary Argument parsing validation. * @compile -XDignore.symbol.file Arrrghs.java * @run main/othervm Arrrghs @@ -383,6 +383,12 @@ public class Arrrghs extends TestHelper { checkArgumentWildcard("empty\\*?", "empty\\*?"); checkArgumentWildcard("empty\\?*", "empty\\?*"); + // 8132379: java should not filter out -J options for application + String[] args = { "-J-one", "-Jtwo", "lib\\???.java", "-J-Dsomething", + "a", "-J-Dlast.arg" }; + String[] expected = { "-J-one", "-Jtwo", "lib\\Fbo.java", + "lib\\Foo.java", "-J-Dsomething", "a", "-J-Dlast.arg" }; + checkArgumentWildcard(args, expected); } void doArgumentCheck(String inArgs, String... expArgs) { From 9d97255ffdcdbfa320b9bdb3d40d12e61bef48fe Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Tue, 12 Jul 2016 10:39:46 +0200 Subject: [PATCH 20/43] 8161032: GPL header incorrect - address wrong - not swapped in licensee bundles Reviewed-by: dholmes, kvn --- .../src/com/sun/hotspot/tools/compiler/UncommonTrap.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java index c4401c59a87..63001d35f7f 100644 --- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java @@ -16,9 +16,9 @@ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * 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 com.sun.hotspot.tools.compiler; From 5d404c26b1721f180fcea030a755a0e5770c5558 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 12 Jul 2016 07:58:40 -0700 Subject: [PATCH 21/43] 8160221: jdk/test/java/nio/channels/FileChannel/Transfers.java leaving files behind Create temporary files in the test scratch directory instead of in the default temporary file directory. Reviewed-by: alanb --- .../nio/channels/FileChannel/Transfers.java | 105 +++++++++--------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/jdk/test/java/nio/channels/FileChannel/Transfers.java b/jdk/test/java/nio/channels/FileChannel/Transfers.java index 70591316077..a414b591cc5 100644 --- a/jdk/test/java/nio/channels/FileChannel/Transfers.java +++ b/jdk/test/java/nio/channels/FileChannel/Transfers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, 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 @@ -489,69 +489,72 @@ public class Transfers { debug = verbose = true; } - sourceFile = File.createTempFile("xfer.src.", ""); + File testDir = new File(System.getProperty("test.dir", ".")); + + sourceFile = File.createTempFile("xfer.src.", "", testDir); sourceFile.deleteOnExit(); - targetFile = File.createTempFile("xfer.tgt.", ""); + targetFile = File.createTempFile("xfer.tgt.", "", testDir); targetFile.deleteOnExit(); - File fn = File.createTempFile("xfer.fch.", ""); + File fn = File.createTempFile("xfer.fch.", "", testDir); fn.deleteOnExit(); - FileChannel fc = new RandomAccessFile(fn, "rw").getChannel(); Random rnd = new Random(); int failures = 0; - for (boolean to = false;; to = true) { - for (boolean user = false;; user = true) { - if (!verbose) - out.print((to ? "To " : "From ") + - (user ? "user channel" : "file channel") - + ":"); - IntGenerator offGen = new IntGenerator(MAX_XFER_SIZE + 2); - while (offGen.hasNext()) { - int off = offGen.next(); - if (!verbose) out.print(" " + off); - IntGenerator lenGen = new IntGenerator(MAX_XFER_SIZE + 2); - while (lenGen.hasNext()) { - int len = lenGen.next(); - long s = rnd.nextLong(); - String chName = null; - try { - if (to) { - Target tgt; - if (user) - tgt = new UserTarget(len, s); - else - tgt = new FileTarget(len, s); - chName = tgt.name(); - testTo(s, fc, off, len, tgt); + try (FileChannel fc = new RandomAccessFile(fn, "rw").getChannel()) { + for (boolean to = false;; to = true) { + for (boolean user = false;; user = true) { + if (!verbose) + out.print((to ? "To " : "From ") + + (user ? "user channel" : "file channel") + + ":"); + IntGenerator offGen = new IntGenerator(MAX_XFER_SIZE + 2); + while (offGen.hasNext()) { + int off = offGen.next(); + if (!verbose) out.print(" " + off); + IntGenerator lenGen = new IntGenerator(MAX_XFER_SIZE + 2); + while (lenGen.hasNext()) { + int len = lenGen.next(); + long s = rnd.nextLong(); + String chName = null; + try { + if (to) { + Target tgt; + if (user) + tgt = new UserTarget(len, s); + else + tgt = new FileTarget(len, s); + chName = tgt.name(); + testTo(s, fc, off, len, tgt); + } + else { + Source src; + if (user) + src = new UserSource(len, s); + else + src = new FileSource(len, s); + chName = src.name(); + testFrom(s, src, fc, off, len); + } + } catch (Failure x) { + out.println(); + out.println("FAILURE: " + chName + + ", offset " + off + + ", length " + len); + x.printStackTrace(out); + failures++; } - else { - Source src; - if (user) - src = new UserSource(len, s); - else - src = new FileSource(len, s); - chName = src.name(); - testFrom(s, src, fc, off, len); - } - } catch (Failure x) { - out.println(); - out.println("FAILURE: " + chName - + ", offset " + off - + ", length " + len); - x.printStackTrace(out); - failures++; } } + if (!verbose) + out.println(); + if (user) + break; } - if (!verbose) - out.println(); - if (user) + if (to) break; } - if (to) - break; } sourceFile.delete(); @@ -563,6 +566,6 @@ public class Transfers { throw new RuntimeException("Some tests failed"); } + out.println("Test succeeded."); } - } From 47c84f9fe6d336d34717377a289e271b5f0d086f Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Wed, 13 Jul 2016 16:37:24 -0700 Subject: [PATCH 22/43] 7031075: GZIPInputStream's available() reports 1, but read() gives -1 Reviewed-by: bpb --- .../java/util/zip/InflaterInputStream.java | 4 + .../InflaterInputStream/TestAvailable.java | 94 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java diff --git a/jdk/src/java.base/share/classes/java/util/zip/InflaterInputStream.java b/jdk/src/java.base/share/classes/java/util/zip/InflaterInputStream.java index 163f619c101..57e38b341c8 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +++ b/jdk/src/java.base/share/classes/java/util/zip/InflaterInputStream.java @@ -179,6 +179,10 @@ class InflaterInputStream extends FilterInputStream { ensureOpen(); if (reachEOF) { return 0; + } else if (inf.finished()) { + // the end of the compressed data stream has been reached + reachEOF = true; + return 0; } else { return 1; } diff --git a/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java b/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java new file mode 100644 index 00000000000..1ac4d4b1779 --- /dev/null +++ b/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, 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 + * @library /lib/testlibrary/ + * @build jdk.testlibrary.* + * @run main TestAvailable + * @bug 7031075 + * @summary Make sure that available() method behaves as expected. + * @key randomness + */ + +import java.io.*; +import java.util.Random; +import java.util.zip.*; +import jdk.testlibrary.RandomFactory; + +public class TestAvailable { + + public static void main(String args[]) throws Throwable { + Random r = RandomFactory.getRandom(); + for (int n = 0; n < 10; n++) { + byte[] src = new byte[r.nextInt(100)]; + r.nextBytes(src); + + // test InflaterInputStream + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DeflaterOutputStream dos = new DeflaterOutputStream(baos)) { + dos.write(src); + } + try (InflaterInputStream iis = new InflaterInputStream( + new ByteArrayInputStream(baos.toByteArray()))) { + test(iis, src); + } + + // test GZIPInputStream + baos = new ByteArrayOutputStream(); + try (GZIPOutputStream dos = new GZIPOutputStream(baos)) { + dos.write(src); + } + try (GZIPInputStream gis = new GZIPInputStream( + new ByteArrayInputStream(baos.toByteArray()))) { + test(gis, src); + } + } + } + + private static void test(InputStream is, byte[] expected) throws IOException { + int cnt = 0; + do { + int available = is.available(); + if (available > 0) { + int b = is.read(); + if (b == -1) { + throw new RuntimeException("available() > 0, read() == -1 : failed!"); + } + if (expected[cnt++] != (byte)b) { + throw new RuntimeException("read() : failed!"); + } + } else if (available == 0) { + if (is.read() != -1) { + throw new RuntimeException("available() == 0, read() != -1 : failed!"); + } + break; + } else { + throw new RuntimeException("available() < 0 : failed!"); + } + } while (true); + if (cnt != expected.length) { + throw new RuntimeException("read : failed!"); + } + } + +} From 1a75a21846837370573d52879227b8fcd8999e02 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Wed, 13 Jul 2016 16:53:31 -0700 Subject: [PATCH 23/43] 8161011: Mark RMI tests DownloadActivationGroup, UseCustomSocketFactory, and RestartService as itnermittent Reviewed-by: bpb --- .../activation/Activatable/restartService/RestartService.java | 3 ++- .../downloadActivationGroup/DownloadActivationGroup.java | 3 ++- .../useSocketFactory/activatable/UseCustomSocketFactory.java | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java b/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java index 221ae5b3401..2d1aa50e56e 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java +++ b/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -23,6 +23,7 @@ /* @test * @bug 4095165 4321151 + * @key intermittent * @summary synopsis: activator should restart daemon services * @author Ann Wollrath * diff --git a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java index 5906f991a40..8560b070c0c 100644 --- a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java +++ b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 4510355 + * @key intermittent * @summary ActivationGroup implementations cannot be downloaded by default; * Creates a custom activation group without setting a security manager * in activation group's descriptor. The custom activation group diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java index a9cb118ebea..86512a9d225 100644 --- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java +++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -23,7 +23,7 @@ /* @test * @bug 4115696 - + * @key intermittent * @summary synopsis: cannot use socket factories with Activatable objects * @author Ann Wollrath * From 4e8a2de21a62d0065b6293e986a1665bae67467d Mon Sep 17 00:00:00 2001 From: Rachna Goel Date: Thu, 14 Jul 2016 10:30:23 +0900 Subject: [PATCH 24/43] 8154797: Localization data for "GMT" Reviewed-by: naoto, okutsu --- .../tools/cldrconverter/CLDRConverter.java | 2 + .../tools/cldrconverter/CopyrightHeaders.java | 6 +- .../tools/cldrconverter/LDMLParseHandler.java | 6 ++ .../text/resources/JavaTimeSupplementary.java | 4 + .../ext/JavaTimeSupplementary_ar.java | 2 + .../ext/JavaTimeSupplementary_be.java | 2 + .../ext/JavaTimeSupplementary_bg.java | 2 + .../ext/JavaTimeSupplementary_cs.java | 2 + .../ext/JavaTimeSupplementary_da.java | 2 + .../ext/JavaTimeSupplementary_et.java | 2 + .../ext/JavaTimeSupplementary_fi.java | 4 + .../ext/JavaTimeSupplementary_fr.java | 4 + .../ext/JavaTimeSupplementary_ga.java | 2 + .../ext/JavaTimeSupplementary_hr.java | 2 + .../ext/JavaTimeSupplementary_in.java | 2 + .../ext/JavaTimeSupplementary_iw.java | 4 + .../ext/JavaTimeSupplementary_lt.java | 2 + .../ext/JavaTimeSupplementary_no.java | 2 + .../ext/JavaTimeSupplementary_sl.java | 2 + .../ext/JavaTimeSupplementary_sq.java | 2 + .../ext/JavaTimeSupplementary_sr.java | 2 + .../ext/JavaTimeSupplementary_sv.java | 2 + jdk/test/java/util/Locale/Bug8154797.java | 99 +++++++++++++++++++ .../resources/JavaTimeSupplementaryTest.java | 3 +- 24 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 jdk/test/java/util/Locale/Bug8154797.java diff --git a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java index f1c1b7dfa64..59b1054a000 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -693,6 +693,8 @@ public class CLDRConverter { "field.weekday", "field.dayperiod", "field.hour", + "timezone.hourFormat", + "timezone.gmtFormat", "field.minute", "field.second", "field.zone", diff --git a/jdk/make/src/classes/build/tools/cldrconverter/CopyrightHeaders.java b/jdk/make/src/classes/build/tools/cldrconverter/CopyrightHeaders.java index 082dd429961..89c7e0f41aa 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/CopyrightHeaders.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/CopyrightHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -41,12 +41,12 @@ class CopyrightHeaders { " * Copyright (c) 2012, %d, Oracle and/or its affiliates. All rights reserved.\n" + " */\n"; - // Last updated: - 1/16/2015, 1:42:31 PM + // Last updated: - 6/06/2016, 1:42:31 PM private static final String UNICODE = "/*\n" + " * COPYRIGHT AND PERMISSION NOTICE\n" + " *\n" + - " * Copyright (C) 1991-2015 Unicode, Inc. All rights reserved.\n" + + " * Copyright (C) 1991-2016 Unicode, Inc. All rights reserved.\n" + " * Distributed under the Terms of Use in \n" + " * http://www.unicode.org/copyright.html.\n" + " *\n" + diff --git a/jdk/make/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/jdk/make/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 720f5e3c088..8683f282581 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -417,6 +417,12 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "timeZoneNames": pushContainer(qName, attributes); break; + case "hourFormat": + pushStringEntry(qName, attributes, "timezone.hourFormat"); + break; + case "gmtFormat": + pushStringEntry(qName, attributes, "timezone.gmtFormat"); + break; case "zone": { String tzid = attributes.getValue("type"); // Olson tz id diff --git a/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary.java b/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary.java index 2a7de9bde43..cd7f4df1305 100644 --- a/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary.java +++ b/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementary.java @@ -343,6 +343,10 @@ public class JavaTimeSupplementary extends OpenListResourceBundle { sharedShortEras }, { "roc.short.Eras", sharedShortEras }, + { "timezone.gmtFormat", + "GMT{0}" }, + { "timezone.hourFormat", + "+HH:mm;-HH:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java index 93df2b4f089..a46891f4270 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java @@ -371,6 +371,8 @@ public class JavaTimeSupplementary_ar extends OpenListResourceBundle { sharedShortEras }, { "roc.short.Eras", sharedShortEras }, + { "timezone.gmtFormat", + "\u062c\u0631\u064a\u0646\u062a\u0634{0}" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_be.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_be.java index 0ab0654ae06..2e530eb4dbc 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_be.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_be.java @@ -308,6 +308,8 @@ public class JavaTimeSupplementary_be extends OpenListResourceBundle { sharedAbbreviatedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedNarrowAmPmMarkers }, + { "timezone.hourFormat", + "+HH.mm;-HH.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_bg.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_bg.java index 0d3c3d8f317..6615e82e845 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_bg.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_bg.java @@ -309,6 +309,8 @@ public class JavaTimeSupplementary_bg extends OpenListResourceBundle { sharedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedAmPmMarkers }, + { "timezone.gmtFormat", + "\u0413\u0440\u0438\u043d\u0443\u0438\u0447{0}" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_cs.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_cs.java index 9467f3e7fdb..64d72dab0fa 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_cs.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_cs.java @@ -298,6 +298,8 @@ public class JavaTimeSupplementary_cs extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+H:mm;-H:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_da.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_da.java index 31eb458e419..1e5acf8832e 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_da.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_da.java @@ -308,6 +308,8 @@ public class JavaTimeSupplementary_da extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH.mm;-HH.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_et.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_et.java index e8df6930c81..5dc9739f706 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_et.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_et.java @@ -280,6 +280,8 @@ public class JavaTimeSupplementary_et extends OpenListResourceBundle { sharedTimePatterns }, { "roc.narrow.AmPmMarkers", sharedNarrowAmPmMarkers }, + { "timezone.hourFormat", + "+HH:mm;\u2212HH:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fi.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fi.java index 8a935e09d6b..2456945df4b 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fi.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fi.java @@ -324,6 +324,10 @@ public class JavaTimeSupplementary_fi extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.gmtFormat", + "UTC{0}" }, + { "timezone.hourFormat", + "+H.mm;-H.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fr.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fr.java index 0e86ade889a..1bebe8ee829 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fr.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_fr.java @@ -329,6 +329,10 @@ public class JavaTimeSupplementary_fr extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.gmtFormat", + "UTC{0}" }, + { "timezone.hourFormat", + "+HH:mm;\u2212HH:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ga.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ga.java index 4d1debee254..33594de7548 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ga.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ga.java @@ -284,6 +284,8 @@ public class JavaTimeSupplementary_ga extends OpenListResourceBundle { sharedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedNarrowAmPmMarkers }, + { "timezone.gmtFormat", + "MAG{0}" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java index b8bb2b1ef08..e73d296ddc7 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java @@ -335,6 +335,8 @@ public class JavaTimeSupplementary_hr extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH:mm; -HH:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java index dcb2c112372..4e62f071f15 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java @@ -347,6 +347,8 @@ public class JavaTimeSupplementary_in extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH.mm;-HH.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_iw.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_iw.java index 76e9c8ee1a2..3170efd769b 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_iw.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_iw.java @@ -324,6 +324,10 @@ public class JavaTimeSupplementary_iw extends OpenListResourceBundle { sharedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedAmPmMarkers }, + { "timezone.gmtFormat", + "GMT{0}\u200e" }, + { "timezone.hourFormat", + "\u200e+HH:mm;-HH:mm\u200e" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java index 6158a2f8a8d..735200db979 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java @@ -325,6 +325,8 @@ public class JavaTimeSupplementary_lt extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH:mm;\u2212HH:mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java index 5bf80bd3523..f2b3b8ef1a3 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java @@ -389,6 +389,8 @@ public class JavaTimeSupplementary_no extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH.mm;-HH.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sl.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sl.java index 26149956100..7b6712baa11 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sl.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sl.java @@ -286,6 +286,8 @@ public class JavaTimeSupplementary_sl extends OpenListResourceBundle { sharedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedNarrowAmPmMarkers }, + { "timezone.hourFormat", + "+HH.mm;-HH.mm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sq.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sq.java index b4daea70146..e6b640764e0 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sq.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sq.java @@ -294,6 +294,8 @@ public class JavaTimeSupplementary_sq extends OpenListResourceBundle { sharedAmPmMarkers }, { "roc.narrow.AmPmMarkers", sharedAmPmMarkers }, + { "timezone.gmtFormat", + "Ora e Grenui\u00e7it: {0}" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java index 1aa88241665..5f127a00dcb 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java @@ -386,6 +386,8 @@ public class JavaTimeSupplementary_sr extends OpenListResourceBundle { sharedShortEras }, { "roc.short.Eras", sharedShortEras }, + { "timezone.hourFormat", + "+HHmm;-HHmm" }, }; } } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java index 637f500918c..160cfec9f38 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java @@ -345,6 +345,8 @@ public class JavaTimeSupplementary_sv extends OpenListResourceBundle { sharedEras }, { "roc.short.Eras", sharedEras }, + { "timezone.hourFormat", + "+HH:mm;\u2212HH:mm" }, }; } } diff --git a/jdk/test/java/util/Locale/Bug8154797.java b/jdk/test/java/util/Locale/Bug8154797.java new file mode 100644 index 00000000000..95599f25df8 --- /dev/null +++ b/jdk/test/java/util/Locale/Bug8154797.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 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 8154797 + * @modules java.base/sun.util.locale.provider + * java.base/sun.util.resources + * jdk.localedata + * @summary Test for checking HourFormat and GmtFormat resources are retrieved from + * COMPAT and CLDR Providers. +*/ + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; +import sun.util.locale.provider.LocaleProviderAdapter.Type; +import sun.util.locale.provider.LocaleProviderAdapter; + +public class Bug8154797 { + static Map expectedResourcesMap = new HashMap<>(); + static final String GMT_RESOURCE_KEY = "timezone.gmtFormat"; + static final String HMT_RESOURCE_KEY = "timezone.hourFormat"; + static final String GMT = "Gmt"; + static final String HMT = "Hmt"; + + static void generateExpectedValues() { + expectedResourcesMap.put("FR" + GMT, "UTC{0}"); + expectedResourcesMap.put("FR" + HMT, "+HH:mm;\u2212HH:mm"); + expectedResourcesMap.put("FI" + HMT, "+H.mm;-H.mm"); + expectedResourcesMap.put("FI" + GMT, "UTC{0}"); + /* For root locale, en_US, de_DE, hi_IN, ja_JP,Root locale resources + * should be returned. + */ + expectedResourcesMap.put(GMT, "GMT{0}"); //Root locale resource + expectedResourcesMap.put(HMT, "+HH:mm;-HH:mm"); //Root locale resource + } + + static void compareResources(Locale loc) { + String mapKeyHourFormat = HMT, mapKeyGmtFormat = GMT; + ResourceBundle compatBundle, cldrBundle; + compatBundle = LocaleProviderAdapter.forJRE().getLocaleResources(loc) + .getJavaTimeFormatData(); + cldrBundle = LocaleProviderAdapter.forType(Type.CLDR) + .getLocaleResources(loc).getJavaTimeFormatData(); + if (loc.getCountry() == "FR" || loc.getCountry() == "FI") { + mapKeyHourFormat = loc.getCountry() + HMT; + mapKeyGmtFormat = loc.getCountry() + GMT; + } + + if (!(expectedResourcesMap.get(mapKeyGmtFormat) + .equals(compatBundle.getString(GMT_RESOURCE_KEY)) + && expectedResourcesMap.get(mapKeyHourFormat) + .equals(compatBundle.getString(HMT_RESOURCE_KEY)) + && expectedResourcesMap.get(mapKeyGmtFormat) + .equals(cldrBundle.getString(GMT_RESOURCE_KEY)) + && expectedResourcesMap.get(mapKeyHourFormat) + .equals(cldrBundle.getString(HMT_RESOURCE_KEY)))) { + + throw new RuntimeException("Retrieved resource does not match with " + + " expected string for Locale " + compatBundle.getLocale()); + + } + + } + + public static void main(String args[]) { + Bug8154797.generateExpectedValues(); + Locale[] locArr = {new Locale("hi", "IN"), Locale.UK, new Locale("fi", "FI"), + Locale.ROOT, Locale.GERMAN, Locale.JAPANESE, + Locale.ENGLISH, Locale.FRANCE}; + for (Locale loc : locArr) { + Bug8154797.compareResources(loc); + } + } + +} + diff --git a/jdk/test/sun/text/resources/JavaTimeSupplementaryTest.java b/jdk/test/sun/text/resources/JavaTimeSupplementaryTest.java index 46a7bfc854f..8e727dcbd45 100644 --- a/jdk/test/sun/text/resources/JavaTimeSupplementaryTest.java +++ b/jdk/test/sun/text/resources/JavaTimeSupplementaryTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8159943 + * @bug 8159943 8154797 * @modules java.base/sun.util.locale.provider * java.base/sun.util.resources * jdk.localedata @@ -65,6 +65,7 @@ public class JavaTimeSupplementaryTest { "field.", "islamic.", "roc.", + "timezone." }; // All available locales for the COMPAT FormatData resource bundles From 3db1a80a5f83e6725862dc187c14d5d9c22f6103 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 14 Jul 2016 10:37:36 +0800 Subject: [PATCH 25/43] 8161341: Garbage in ProblemList.txt Reviewed-by: xuelei --- jdk/test/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 2214bd66fc1..2e7da24b031 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -215,7 +215,7 @@ java/rmi/transport/dgcDeadLock/DGCDeadLock.java 8029360 macosx-a sun/security/pkcs11/ec/TestKeyFactory.java 7157786 generic-all -sun/security/krb5/auto/Unreachable.java 7164518 macosx-all no PortUnreachableException on Mac +sun/security/krb5/auto/Unreachable.java 7164518 macosx-all sun/security/tools/keytool/ListKeychainStore.sh 8156889 macosx-all From 0062a02e07a116e55ebe0c7f85b90a1a66911152 Mon Sep 17 00:00:00 2001 From: Steve Drach Date: Wed, 13 Jul 2016 11:43:45 -0700 Subject: [PATCH 26/43] 8150680: JarFile.Release enum needs reconsideration with respect to it's values Reviewed-by: alanb, psandoz --- .../classes/java/lang/module/ModulePath.java | 2 +- .../java/lang/module/ModuleReferences.java | 2 +- .../share/classes/java/util/jar/JarFile.java | 186 +++++++----------- .../jdk/internal/loader/URLClassPath.java | 2 +- .../sun/net/www/protocol/jar/URLJarFile.java | 14 +- .../jar/JarFile/mrjar/MultiReleaseJarAPI.java | 110 +++++------ .../mrjar/MultiReleaseJarHttpProperties.java | 6 - .../mrjar/MultiReleaseJarIterators.java | 14 +- .../mrjar/MultiReleaseJarProperties.java | 21 +- .../mrjar/MultiReleaseJarSecurity.java | 2 +- .../jar/MultiReleaseJarURLConnection.java | 4 +- jdk/test/tools/jar/multiRelease/Basic.java | 2 +- 12 files changed, 159 insertions(+), 206 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java index 43d8e56974d..92c16bdfbc2 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java @@ -523,7 +523,7 @@ class ModulePath implements ConfigurableModuleFinder { try (JarFile jf = new JarFile(file.toFile(), true, // verify ZipFile.OPEN_READ, - JarFile.Release.RUNTIME)) + JarFile.runtimeVersion())) { ModuleDescriptor md; JarEntry entry = jf.getJarEntry(MODULE_INFO); diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java index eccd0d493f4..18caa15d71c 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java @@ -201,7 +201,7 @@ class ModuleReferences { return new JarFile(path.toFile(), true, // verify ZipFile.OPEN_READ, - JarFile.Release.RUNTIME); + JarFile.runtimeVersion()); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } diff --git a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java index aab2474fd66..10abc4d9198 100644 --- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java @@ -64,8 +64,8 @@ import sun.security.util.SignatureFileVerifier; * file, and as such an entry name is associated with at most one base entry. * The {@code JarFile} may be configured to process a multi-release jar file by * creating the {@code JarFile} with the - * {@link JarFile#JarFile(File, boolean, int, Release)} constructor. The - * {@code Release} object sets a maximum version used when searching for + * {@link JarFile#JarFile(File, boolean, int, Runtime.Version)} constructor. The + * {@code Runtime.Version} object sets a maximum version used when searching for * versioned entries. When so configured, an entry name * can correspond with at most one base entry and zero or more versioned * entries. A search is required to associate the entry name with the latest @@ -74,8 +74,8 @@ import sun.security.util.SignatureFileVerifier; * *

      Class loaders that utilize {@code JarFile} to load classes from the * contents of {@code JarFile} entries should construct the {@code JarFile} - * by invoking the {@link JarFile#JarFile(File, boolean, int, Release)} - * constructor with the value {@code Release.RUNTIME} assigned to the last + * by invoking the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)} + * constructor with the value {@code Runtime.version()} assigned to the last * argument. This assures that classes compatible with the major * version of the running JVM are loaded from multi-release jar files. * @@ -99,12 +99,12 @@ import sun.security.util.SignatureFileVerifier; *

    22. * {@code jdk.util.jar.version} can be assigned a value that is the * {@code String} representation of a non-negative integer - * {@code <= Version.current().major()}. The value is used to set the effective + * {@code <= Runtime.version().major()}. The value is used to set the effective * runtime version to something other than the default value obtained by - * evaluating {@code Version.current().major()}. The effective runtime version - * is the version that the {@link JarFile#JarFile(File, boolean, int, Release)} + * evaluating {@code Runtime.version().major()}. The effective runtime version + * is the version that the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)} * constructor uses when the value of the last argument is - * {@code Release.RUNTIME}. + * {@code JarFile.runtimeVersion()}. *
    23. *
    24. * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three @@ -116,7 +116,7 @@ import sun.security.util.SignatureFileVerifier; * the method {@link JarFile#isMultiRelease()} returns false. The value * force causes the {@code JarFile} to be initialized to runtime * versioning after construction. It effectively does the same as this code: - * {@code (new JarFile(File, boolean, int, Release.RUNTIME)}. + * {@code (new JarFile(File, boolean, int, JarFile.runtimeVersion())}. *
    25. * * @@ -129,8 +129,9 @@ import sun.security.util.SignatureFileVerifier; */ public class JarFile extends ZipFile { - private final static int BASE_VERSION; - private final static int RUNTIME_VERSION; + private final static Runtime.Version BASE_VERSION; + private final static int BASE_VERSION_MAJOR; + private final static Runtime.Version RUNTIME_VERSION; private final static boolean MULTI_RELEASE_ENABLED; private final static boolean MULTI_RELEASE_FORCED; private SoftReference manRef; @@ -138,10 +139,10 @@ class JarFile extends ZipFile { private JarVerifier jv; private boolean jvInitialized; private boolean verify; - private final int version; - private boolean notVersioned; - private final boolean runtimeVersioned; - private boolean isMultiRelease; // is jar multi-release? + private final Runtime.Version version; // current version + private final int versionMajor; // version.major() + private boolean notVersioned; // legacy constructor called + private boolean isMultiRelease; // is jar multi-release? // indicates if Class-Path attribute present private boolean hasClassPathAttribute; @@ -151,17 +152,18 @@ class JarFile extends ZipFile { static { // Set up JavaUtilJarAccess in SharedSecrets SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); - - BASE_VERSION = 8; // one less than lowest version for versioned entries + // multi-release jar file versions >= 9 + BASE_VERSION = Runtime.Version.parse(Integer.toString(8)); + BASE_VERSION_MAJOR = BASE_VERSION.major(); + String jarVersion = GetPropertyAction.privilegedGetProperty("jdk.util.jar.version"); int runtimeVersion = Runtime.version().major(); - String jarVersion = - GetPropertyAction.privilegedGetProperty("jdk.util.jar.version"); if (jarVersion != null) { int jarVer = Integer.parseInt(jarVersion); runtimeVersion = (jarVer > runtimeVersion) - ? runtimeVersion : Math.max(jarVer, 0); + ? runtimeVersion + : Math.max(jarVer, BASE_VERSION_MAJOR); } - RUNTIME_VERSION = runtimeVersion; + RUNTIME_VERSION = Runtime.Version.parse(Integer.toString(runtimeVersion)); String enableMultiRelease = GetPropertyAction .privilegedGetProperty("jdk.util.jar.enableMultiRelease", "true"); switch (enableMultiRelease) { @@ -181,61 +183,6 @@ class JarFile extends ZipFile { } } - /** - * A set of constants that represent the entries in either the base directory - * or one of the versioned directories in a multi-release jar file. It's - * possible for a multi-release jar file to contain versioned directories - * that are not represented by the constants of the {@code Release} enum. - * In those cases, the entries will not be located by this {@code JarFile} - * through the aliasing mechanism, but they can be directly accessed by - * specifying the full path name of the entry. - * - * @since 9 - */ - public enum Release { - /** - * Represents unversioned entries, or entries in "regular", as opposed - * to multi-release jar files. - */ - BASE(BASE_VERSION), - - /** - * Represents entries found in the META-INF/versions/9 directory of a - * multi-release jar file. - */ - VERSION_9(9), - - // fill in the "blanks" for future releases - - /** - * Represents entries found in the META-INF/versions/{n} directory of a - * multi-release jar file, where {@code n} is the effective runtime - * version of the jar file. - * - * @implNote - *
      - * The effective runtime version is determined - * by evaluating {@code Version.current().major()} or by using the value - * of the {@code jdk.util.jar.version} System property if it exists. - *
      - */ - RUNTIME(RUNTIME_VERSION); - - Release(int version) { - this.version = version; - } - - private static Release valueOf(int version) { - return version <= BASE.value() ? BASE : valueOf("VERSION_" + version); - } - - private final int version; - - private int value() { - return this.version; - } - } - private static final String META_INF = "META-INF/"; private static final String META_INF_VERSIONS = META_INF + "versions/"; @@ -245,6 +192,32 @@ class JarFile extends ZipFile { */ public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF"; + /** + * The version that represents the unversioned configuration of a multi-release jar file. + * + * @return Runtime.Version that represents the unversioned configuration + * + * @since 9 + */ + public static Runtime.Version baseVersion() { + return BASE_VERSION; + } + + /** + * The version that represents the effective runtime versioned configuration of a + * multi-release jar file. In most cases, {@code runtimeVersion()} is equal to + * {@code Runtime.version()}. However, if the {@code jdk.util.jar.version} property is set, + * {@code runtimeVersion()} is derived from that property and may not be equal to + * {@code Runtime.version()}. + * + * @return Runtime.Version that represents the runtime versioned configuration + * + * @since 9 + */ + public static Runtime.Version runtimeVersion() { + return RUNTIME_VERSION; + } + /** * Creates a new {@code JarFile} to read from the specified * file {@code name}. The {@code JarFile} will be verified if @@ -316,7 +289,7 @@ class JarFile extends ZipFile { * @since 1.3 */ public JarFile(File file, boolean verify, int mode) throws IOException { - this(file, verify, mode, Release.BASE); + this(file, verify, mode, BASE_VERSION); this.notVersioned = true; } @@ -324,8 +297,13 @@ class JarFile extends ZipFile { * Creates a new {@code JarFile} to read from the specified * {@code File} object in the specified mode. The mode argument * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}. - * The version argument configures the {@code JarFile} for processing + * The version argument, after being converted to a canonical form, is + * used to configure the {@code JarFile} for processing * multi-release jar files. + *

      + * The canonical form derived from the version parameter is + * {@code Runtime.Version.parse(Integer.toString(n))} where {@code n} is + * {@code Math.max(version.major(), JarFile.baseVersion().major())}. * * @param file the jar file to be opened for reading * @param verify whether or not to verify the jar file if @@ -340,47 +318,31 @@ class JarFile extends ZipFile { * @throws NullPointerException if {@code version} is {@code null} * @since 9 */ - public JarFile(File file, boolean verify, int mode, Release version) throws IOException { + public JarFile(File file, boolean verify, int mode, Runtime.Version version) throws IOException { super(file, mode); - Objects.requireNonNull(version); this.verify = verify; - // version applies to multi-release jar files, ignored for regular jar files - if (MULTI_RELEASE_FORCED) { + Objects.requireNonNull(version); + if (MULTI_RELEASE_FORCED || version.major() == RUNTIME_VERSION.major()) { + // This deals with the common case where the value from JarFile.runtimeVersion() is passed this.version = RUNTIME_VERSION; - version = Release.RUNTIME; + } else if (version.major() <= BASE_VERSION_MAJOR) { + // This also deals with the common case where the value from JarFile.baseVersion() is passed + this.version = BASE_VERSION; } else { - this.version = version.value(); - } - this.runtimeVersioned = version == Release.RUNTIME; - - assert runtimeVersionExists(); - } - - private boolean runtimeVersionExists() { - int version = Runtime.version().major(); - try { - Release.valueOf(version); - return true; - } catch (IllegalArgumentException x) { - System.err.println("No JarFile.Release object for release " + version); - return false; + // Canonicalize + this.version = Runtime.Version.parse(Integer.toString(version.major())); } + this.versionMajor = this.version.major(); } /** * Returns the maximum version used when searching for versioned entries. * - * @return the maximum version, or {@code Release.BASE} if this jar file is - * processed as if it is an unversioned jar file or is not a - * multi-release jar file + * @return the maximum version * @since 9 */ - public final Release getVersion() { - if (isMultiRelease()) { - return runtimeVersioned ? Release.RUNTIME : Release.valueOf(version); - } else { - return Release.BASE; - } + public final Runtime.Version getVersion() { + return isMultiRelease() ? this.version : BASE_VERSION; } /** @@ -393,7 +355,7 @@ class JarFile extends ZipFile { if (isMultiRelease) { return true; } - if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) { + if (MULTI_RELEASE_ENABLED && versionMajor != BASE_VERSION_MAJOR) { try { checkForSpecialAttributes(); } catch (IOException io) { @@ -639,7 +601,7 @@ class JarFile extends ZipFile { ZipEntry vze = null; String sname = "/" + name; int i = version; - while (i > BASE_VERSION) { + while (i > BASE_VERSION_MAJOR) { vze = super.getEntry(META_INF_VERSIONS + i + sname); if (vze != null) break; i--; @@ -649,10 +611,10 @@ class JarFile extends ZipFile { private ZipEntry getVersionedEntry(ZipEntry ze) { ZipEntry vze = null; - if (version > BASE_VERSION && !ze.isDirectory()) { + if (BASE_VERSION_MAJOR < versionMajor && !ze.isDirectory()) { String name = ze.getName(); if (!name.startsWith(META_INF)) { - vze = searchForVersionedEntry(version, name); + vze = searchForVersionedEntry(versionMajor, name); } } return vze == null ? ze : vze; @@ -1038,7 +1000,7 @@ class JarFile extends ZipFile { hasClassPathAttribute = match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC) != -1; // is this a multi-release jar file - if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) { + if (MULTI_RELEASE_ENABLED && versionMajor != BASE_VERSION_MAJOR) { int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC); if (i != -1) { i += MULTIRELEASE_CHARS.length; diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index aa2722c5e63..695d8028068 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -695,7 +695,7 @@ public class URLClassPath { throw new FileNotFoundException(p.getPath()); } return checkJar(new JarFile(new File(p.getPath()), true, ZipFile.OPEN_READ, - JarFile.Release.RUNTIME)); + JarFile.runtimeVersion())); } URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection(); uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION); diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java index fe1a1f3c8f2..a320045ba75 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java @@ -66,7 +66,9 @@ public class URLJarFile extends JarFile { static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException { if (isFileURL(url)) { - Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE; + Runtime.Version version = "runtime".equals(url.getRef()) + ? JarFile.runtimeVersion() + : JarFile.baseVersion(); return new URLJarFile(url, closeController, version); } else { return retrieve(url, closeController); @@ -90,12 +92,14 @@ public class URLJarFile extends JarFile { this.closeController = closeController; } - private URLJarFile(File file, URLJarFileCloseController closeController, Release version) throws IOException { + private URLJarFile(File file, URLJarFileCloseController closeController, Runtime.Version version) + throws IOException { super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version); this.closeController = closeController; } - private URLJarFile(URL url, URLJarFileCloseController closeController, Release version) throws IOException { + private URLJarFile(URL url, URLJarFileCloseController closeController, Runtime.Version version) + throws IOException { super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version); this.closeController = closeController; } @@ -200,7 +204,9 @@ public class URLJarFile extends JarFile { { JarFile result = null; - Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE; + Runtime.Version version = "runtime".equals(url.getRef()) + ? JarFile.runtimeVersion() + : JarFile.baseVersion(); /* get the stream before asserting privileges */ try (final InputStream in = url.openConnection().getInputStream()) { diff --git a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java index 54b889f9427..bae8265be67 100644 --- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java +++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java @@ -40,25 +40,19 @@ import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import static java.util.jar.JarFile.Release; - import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; - public class MultiReleaseJarAPI { - static final int MAJOR_VERSION = Runtime.version().major(); - String userdir = System.getProperty("user.dir","."); CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); File unversioned = new File(userdir, "unversioned.jar"); File multirelease = new File(userdir, "multi-release.jar"); File signedmultirelease = new File(userdir, "signed-multi-release.jar"); - Release[] values = JarFile.Release.values(); - @BeforeClass public void initialize() throws Exception { @@ -81,7 +75,7 @@ public class MultiReleaseJarAPI { Assert.assertFalse(jf.isMultiRelease()); } - try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.version())) { Assert.assertFalse(jf.isMultiRelease()); } @@ -89,7 +83,7 @@ public class MultiReleaseJarAPI { Assert.assertFalse(jf.isMultiRelease()); } - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.version())) { Assert.assertTrue(jf.isMultiRelease()); } @@ -110,68 +104,68 @@ public class MultiReleaseJarAPI { private void testCustomMultiReleaseValue(String value, boolean expected) throws Exception { creator.buildCustomMultiReleaseJar("custom-mr.jar", value); File custom = new File(userdir, "custom-mr.jar"); - try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Runtime.version())) { Assert.assertEquals(jf.isMultiRelease(), expected); } Files.delete(custom.toPath()); } - @Test - public void testVersioning() throws Exception { - // multi-release jar - JarFile jar = new JarFile(multirelease); - Assert.assertEquals(Release.BASE, jar.getVersion()); - jar.close(); + @DataProvider(name = "versions") + public Object[][] createVersionData() throws Exception { + return new Object[][]{ + {JarFile.baseVersion(), 8}, + {JarFile.runtimeVersion(), Runtime.version().major()}, + {Runtime.version(), Runtime.version().major()}, + {Runtime.Version.parse("7.1"), JarFile.baseVersion().major()}, + {Runtime.Version.parse("9"), 9}, + {Runtime.Version.parse("9.1.5-ea+200"), 9} + }; + } - for (Release value : values) { - System.err.println("test versioning for Release " + value); - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) { - Assert.assertEquals(value, jf.getVersion()); - } + @Test(dataProvider="versions") + public void testVersioning(Runtime.Version value, int xpected) throws Exception { + Runtime.Version expected = Runtime.Version.parse(String.valueOf(xpected)); + Runtime.Version base = JarFile.baseVersion(); + + // multi-release jar, opened as unversioned + try (JarFile jar = new JarFile(multirelease)) { + Assert.assertEquals(jar.getVersion(), base); + } + + System.err.println("test versioning for Release " + value); + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) { + Assert.assertEquals(jf.getVersion(), expected); } // regular, unversioned, jar - for (Release value : values) { - try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) { - Assert.assertEquals(Release.BASE, jf.getVersion()); - } - } - - // assure that we have a Release object corresponding to the actual runtime version - String version = "VERSION_" + MAJOR_VERSION; - boolean runtimeVersionExists = false; - for (Release value : values) { - if (version.equals(value.name())) runtimeVersionExists = true; - } - Assert.assertTrue(runtimeVersionExists); - } - - @Test - public void testAliasing() throws Exception { - for (Release value : values) { - System.err.println("test aliasing for Release " + value); - String name = value.name(); - String prefix; - if (name.equals("BASE")) { - prefix = ""; - } else if (name.equals("RUNTIME")) { - prefix = "META-INF/versions/" + MAJOR_VERSION + "/"; - } else { - prefix = "META-INF/versions/" + name.substring(8) + "/"; - } - // test both multi-release jars - readAndCompare(multirelease, value, "README", prefix + "README"); - readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class"); - // and signed multi-release jars - readAndCompare(signedmultirelease, value, "README", prefix + "README"); - readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class"); + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) { + Assert.assertEquals(jf.getVersion(), base); } } - private void readAndCompare(File jar, Release version, String name, String realName) throws Exception { + @Test(dataProvider="versions") + public void testAliasing(Runtime.Version version, int xpected) throws Exception { + int n = Math.max(version.major(), JarFile.baseVersion().major()); + Runtime.Version value = Runtime.Version.parse(String.valueOf(n)); + System.err.println("test aliasing for Release " + version); + String prefix; + if (JarFile.baseVersion().equals(value)) { + prefix = ""; + } else { + prefix = "META-INF/versions/" + value.major() + "/"; + } + // test both multi-release jars + readAndCompare(multirelease, value, "README", prefix + "README"); + readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class"); + // and signed multi-release jars + readAndCompare(signedmultirelease, value, "README", prefix + "README"); + readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class"); + } + + private void readAndCompare(File jar, Runtime.Version version, String name, String realName) throws Exception { byte[] baseBytes; byte[] versionedBytes; - try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, Release.BASE)) { + try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, JarFile.baseVersion())) { ZipEntry ze = jf.getEntry(realName); try (InputStream is = jf.getInputStream(ze)) { baseBytes = is.readAllBytes(); @@ -200,7 +194,7 @@ public class MultiReleaseJarAPI { ze1 = jf.getEntry(vname); } Assert.assertEquals(ze1.getName(), vname); - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) { + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) { ze2 = jf.getEntry(rname); } Assert.assertEquals(ze2.getName(), rname); diff --git a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java index 9cff19fcfb3..ee48fbed30d 100644 --- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java +++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java @@ -47,14 +47,8 @@ */ import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import org.testng.Assert; import org.testng.annotations.AfterClass; diff --git a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java index 60d5063ba71..f51f012f256 100644 --- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java +++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java @@ -43,8 +43,6 @@ import java.util.jar.JarFile; import java.util.stream.Collectors; import java.util.zip.ZipFile; -import static java.util.jar.JarFile.Release; - import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -111,17 +109,17 @@ public class MultiReleaseJarIterators { testStream(jf, mrEntries); } - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.BASE)) { + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, JarFile.baseVersion())) { testEnumeration(jf, baseEntries); testStream(jf, baseEntries); } - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) { + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) { testEnumeration(jf, v9Entries); testStream(jf, v9Entries); } - try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.version())) { Map expectedEntries; switch (MAJOR_VERSION) { case 9: @@ -147,17 +145,17 @@ public class MultiReleaseJarIterators { testStream(jf, uvEntries); } - try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.BASE)) { + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, JarFile.baseVersion())) { testEnumeration(jf, uvEntries); testStream(jf, uvEntries); } - try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.VERSION_9)) { + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) { testEnumeration(jf, uvEntries); testStream(jf, uvEntries); } - try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.version())) { testEnumeration(jf, uvEntries); testStream(jf, uvEntries); } diff --git a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java index d729c438a66..86b8b907c76 100644 --- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java +++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java @@ -60,11 +60,10 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; + public class MultiReleaseJarProperties { + final static int BASE_VERSION = JarFile.baseVersion().major(); - static final int MAJOR_VERSION = Runtime.version().major(); - - final static int ROOTVERSION = 8; // magic number from knowledge of internals final static String userdir = System.getProperty("user.dir", "."); final static File multirelease = new File(userdir, "multi-release.jar"); protected int rtVersion; @@ -77,15 +76,15 @@ public class MultiReleaseJarProperties { CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); creator.compileEntries(); creator.buildMultiReleaseJar(); - - rtVersion = Integer.getInteger("jdk.util.jar.version", MAJOR_VERSION); + int RUNTIME_VERSION = Runtime.version().major(); + rtVersion = Integer.getInteger("jdk.util.jar.version", RUNTIME_VERSION); String mrprop = System.getProperty("jdk.util.jar.enableMultiRelease", ""); if (mrprop.equals("false")) { - rtVersion = ROOTVERSION; - } else if (rtVersion < ROOTVERSION) { - rtVersion = ROOTVERSION; - } else if (rtVersion > MAJOR_VERSION) { - rtVersion = MAJOR_VERSION; + rtVersion = BASE_VERSION; + } else if (rtVersion < BASE_VERSION) { + rtVersion = BASE_VERSION; + } else if (rtVersion > RUNTIME_VERSION) { + rtVersion = RUNTIME_VERSION; } force = mrprop.equals("force"); @@ -135,7 +134,7 @@ public class MultiReleaseJarProperties { if (force) throw x; } } - invokeMethod(vcls, force ? rtVersion : ROOTVERSION); + invokeMethod(vcls, force ? rtVersion : BASE_VERSION); } } diff --git a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java index 538742ce192..39319aac062 100644 --- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java +++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java @@ -70,7 +70,7 @@ public class MultiReleaseJarSecurity { @Test public void testCertsAndSigners() throws IOException { - try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, JarFile.Release.RUNTIME)) { + try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, Runtime.version())) { CertsAndSigners vcas = new CertsAndSigners(jf, jf.getJarEntry("version/Version.class")); CertsAndSigners rcas = new CertsAndSigners(jf, jf.getJarEntry("META-INF/versions/" + MAJOR_VERSION + "/version/Version.class")); Assert.assertTrue(Arrays.equals(rcas.getCertificates(), vcas.getCertificates())); diff --git a/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java index fe9ce71de78..d3660e45c2e 100644 --- a/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java +++ b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java @@ -132,12 +132,12 @@ public class MultiReleaseJarURLConnection { URL rootUrl = new URL(urlFile); JarURLConnection juc = (JarURLConnection)rootUrl.openConnection(); JarFile rootJar = juc.getJarFile(); - JarFile.Release root = rootJar.getVersion(); + Runtime.Version root = rootJar.getVersion(); URL runtimeUrl = new URL(urlFile + "#runtime"); juc = (JarURLConnection)runtimeUrl.openConnection(); JarFile runtimeJar = juc.getJarFile(); - JarFile.Release runtime = runtimeJar.getVersion(); + Runtime.Version runtime = runtimeJar.getVersion(); if (style.equals("unversioned")) { Assert.assertEquals(root, runtime); } else { diff --git a/jdk/test/tools/jar/multiRelease/Basic.java b/jdk/test/tools/jar/multiRelease/Basic.java index a1b595338e0..cd5c195a169 100644 --- a/jdk/test/tools/jar/multiRelease/Basic.java +++ b/jdk/test/tools/jar/multiRelease/Basic.java @@ -220,7 +220,7 @@ public class Basic { private void checkMultiRelease(String jarFile, boolean expected) throws IOException { try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ, - JarFile.Release.RUNTIME)) { + JarFile.runtimeVersion())) { assertEquals(jf.isMultiRelease(), expected); } } From 29852f47c03927ddcb98342f2910a059867d6170 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Wed, 13 Jul 2016 14:23:53 -0700 Subject: [PATCH 27/43] 8161255: jdk build "all" (docs) fails on all platforms, error from DefaultLoggerFinder.java Reviewed-by: tbell, ksrini, darcy --- make/Javadoc.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/Javadoc.gmk b/make/Javadoc.gmk index f194dd95f89..d1607b24bab 100644 --- a/make/Javadoc.gmk +++ b/make/Javadoc.gmk @@ -424,7 +424,7 @@ $(COREAPI_OPTIONS_FILE): $(COREAPI_OVERVIEW) @($(call COMMON_JAVADOCFLAGS) ; \ $(call COMMON_JAVADOCTAGS) ; \ $(call OptionOnly,-Xdoclint:reference) ; \ - $(call OptionOnly,-Xdoclint/package:-org.omg.*) ; \ + $(call OptionOnly,-Xdoclint/package:-org.omg.*$(COMMA)jdk.internal.logging.*) ; \ $(call OptionPair,-system,none) ; \ $(call OptionPair,-modulesourcepath,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ $(call OptionPair,-addmods,$(COREAPI_MODULES)) ; \ From 1c7cd18b25c89ff10045bc54b249998c3bc80bd2 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 13 Jul 2016 14:42:09 -0700 Subject: [PATCH 28/43] 8160398: (jdeps) Replace a list of JDK 8 internal API for detecting if it's removed in JDK 9 or later Reviewed-by: dfuchs --- make/CompileJavaModules.gmk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index a53f2b13887..f377d6687c5 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -409,6 +409,8 @@ jdk.jconsole_CLEAN_FILES := $(wildcard \ ################################################################################ +jdk.jdeps_COPY := .txt + jdk.jdeps_CLEAN_FILES := $(wildcard \ $(JDK_TOPDIR)/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/*.properties \ $(JDK_TOPDIR)/src/jdk.jdeps/share/classes/com/sun/tools/javap/resources/*.properties) From e883900ac7175e7b15d3e79927d0f5af9197b367 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 14 Jul 2016 19:31:43 +0800 Subject: [PATCH 29/43] 8161354: policytool fails if it needs to show an error dialog before the main window appears Reviewed-by: mullan --- .../classes/sun/security/tools/policytool/PolicyTool.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java b/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java index f8083997c09..b560e053d97 100644 --- a/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java +++ b/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java @@ -1376,10 +1376,6 @@ class ToolWindow extends JFrame { ToolDialog ed = new ToolDialog (PolicyTool.getMessage("Error"), tool, this, true); - // find where the PolicyTool gui is - Point location = ((w == null) ? - getLocationOnScreen() : w.getLocationOnScreen()); - //ed.setBounds(location.x + 50, location.y + 50, 600, 100); ed.setLayout(new GridBagLayout()); JLabel label = new JLabel(error); From d09561f8c678960fd2f74c631d46367973a0f63a Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Thu, 14 Jul 2016 16:49:30 +0200 Subject: [PATCH 30/43] 8160564: TEST: Add a test to check the implementation of VersionProps.versionNumbers() Reviewed-by: mchung, redestad --- .../java/lang/VersionProps.java.template | 34 ++++-- .../lang/Runtime/Version/VersionProps.java | 102 ++++++++++++++++++ 2 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 jdk/test/java/lang/Runtime/Version/VersionProps.java diff --git a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template index a9f12e708ff..a51702fa093 100644 --- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template +++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template @@ -67,19 +67,35 @@ class VersionProps { System.setProperty("java.runtime.name", java_runtime_name); } - static List versionNumbers() { - List versionNumbers = new ArrayList<>(4); + private static int parseVersionNumber(String version, int prevIndex, int index) { + if (index - prevIndex > 1 && + Character.digit(version.charAt(prevIndex), 10) <= 0) + throw new IllegalArgumentException("Leading zeros not supported (" + + version.substring(prevIndex, index) + ")"); + return Integer.parseInt(version, prevIndex, index, 10); + } + + // This method is reflectively used by regression tests. + static List parseVersionNumbers(String version) { + List verNumbers = new ArrayList<>(4); int prevIndex = 0; - int index = VERSION_NUMBER.indexOf('.'); + int index = version.indexOf('.'); while (index > 0) { - versionNumbers.add( - Integer.parseInt(VERSION_NUMBER, prevIndex, index, 10)); + verNumbers.add(parseVersionNumber(version, prevIndex, index)); prevIndex = index + 1; // Skip the period - index = VERSION_NUMBER.indexOf('.', prevIndex); + index = version.indexOf('.', prevIndex); } - versionNumbers.add(Integer.parseInt(VERSION_NUMBER, - prevIndex, VERSION_NUMBER.length(), 10)); - return versionNumbers; + verNumbers.add(parseVersionNumber(version, prevIndex, version.length())); + + if (verNumbers.get(0) == 0 || verNumbers.get(verNumbers.size() - 1) == 0) + throw new IllegalArgumentException("Leading/trailing zeros not supported (" + + verNumbers + ")"); + + return verNumbers; + } + + static List versionNumbers() { + return parseVersionNumbers(VERSION_NUMBER); } static Optional pre() { diff --git a/jdk/test/java/lang/Runtime/Version/VersionProps.java b/jdk/test/java/lang/Runtime/Version/VersionProps.java new file mode 100644 index 00000000000..ddbaa081d4f --- /dev/null +++ b/jdk/test/java/lang/Runtime/Version/VersionProps.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 SAP SE. 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 8160564 + * @summary check the implementation of VersionProps.versionNumbers() + * @run main VersionProps + * @author Volker Simonis + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +public class VersionProps { + + final static String[] validVersions = { + "1", "1.2", "1.2.3", "1.2.3.4", "1.0.0.1", + "1.10000.1", "1.0.2.0.0.3.0.0.0.4.5.0.0.6", + "1000001", "1.2.3.4.5.6.7.8.9.0.9.8.7.6.5.4.3.2.1" }; + + @SuppressWarnings("rawtypes") + final static List[] validLists = { + Arrays.asList(1), + Arrays.asList(1, 2), + Arrays.asList(1, 2, 3), + Arrays.asList(1, 2, 3, 4), + Arrays.asList(1, 0, 0, 1), + Arrays.asList(1, 10000, 1), + Arrays.asList(1, 0, 2, 0, 0, 3, 0, 0, 0, 4, 5, 0, 0, 6), + Arrays.asList(1000001), + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1) }; + + final static String[] invalidVersions = { + "01", "0.1.2", "1.02.3", "1.2.03.4", "1.0.0.1.0", + "1.0.1.0.0", "1.00.1", "1.0.1.00", "1.10000." }; + + public static void main(String[] args) throws Exception { + Class versionProps = Class.forName("java.lang.VersionProps"); + Method parseVersionNumbers = + versionProps.getDeclaredMethod("parseVersionNumbers", String.class); + parseVersionNumbers.setAccessible(true); + + for (int i = 0; i < validVersions.length; i++) { + @SuppressWarnings("unchecked") + List li = + (List)parseVersionNumbers.invoke(null, validVersions[i]); + System.out.println(li); + if (!validLists[i].equals(li)) + throw new Exception(li + " != " + validLists[i]); + li = Runtime.Version.parse(validVersions[i]).version(); + if (!validLists[i].equals(li)) + throw new Exception(li + " != " + validLists[i]); + } + + for (int i = 0; i < invalidVersions.length; i++) { + try { + List li = + (List)parseVersionNumbers.invoke(null, invalidVersions[i]); + throw new Exception(invalidVersions[i] + + " not recognized as invalid by VersionProps.parseVersionNumbers()"); + } catch (InvocationTargetException ex) { + if (ex.getCause() instanceof IllegalArgumentException) { + System.out.println("OK - caught bad version string " + + invalidVersions[i]); + } else { + throw ex; + } + } + + try { + List li = Runtime.Version.parse(invalidVersions[i]).version(); + throw new Exception(invalidVersions[i] + + " not recognized as invalid by Runtime.Version.parse()"); + } catch (IllegalArgumentException ex) { + continue; + } + } + } +} From 9ff51bb7bb3f16ab9b52ad2105231597814a4ce2 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Thu, 14 Jul 2016 15:47:44 +0000 Subject: [PATCH 31/43] Added tag jdk-9+127 for changeset 6a80821ee59f --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 783312526e8..b4f5b7c73a6 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -369,3 +369,4 @@ cae471d3b87783e0a3deea658e1e1c84b2485b6c jdk-9+121 f80c841ae2545eaf9acd2724bccc305d98cefbe2 jdk-9+124 9aa7d40f3a453f51e47f4c1b19eff5740a74a9f8 jdk-9+125 3a58466296d36944454756ef01e7513ac5e14a16 jdk-9+126 +8fa686245bd2a072ece3392743460030f0854520 jdk-9+127 From 5593c544a5269aedf8516592356ce038f2415a07 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Thu, 14 Jul 2016 15:47:44 +0000 Subject: [PATCH 32/43] Added tag jdk-9+127 for changeset 8e5b413c199b --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 393252486a7..7415efbd4d7 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -529,3 +529,4 @@ af6b4ad908e732d23021f12e8322b204433d5cf6 jdk-9+122 479631362b4930be985245ea063d87d821a472eb jdk-9+124 bb640b49741af3f57f9994129934c46fc173219f jdk-9+125 adc8c84b7cf8c540d920182f78a2bc982366432a jdk-9+126 +352357128f602dcf0426b1cbe011a4685a4d9f97 jdk-9+127 From 6cbadc73483239fad9f4ae0670dc73e900a97db1 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Thu, 14 Jul 2016 15:47:44 +0000 Subject: [PATCH 33/43] Added tag jdk-9+127 for changeset a7aae19b3746 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index d514b137ea5..2667a3cc368 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -369,3 +369,4 @@ e33a34cc551907617d8129c4faaf1a5a7e61d21c jdk-9+123 45121d5afb9d5bfadab75378572ad96832e0809e jdk-9+124 1d48e67d1b91eb9f72e49e69a4021edb85e357fc jdk-9+125 c7f5ba08fcd4b8416e62c21229f9a07c95498919 jdk-9+126 +8fab452b6f4710762ba1d8e55fd62db00b1355fe jdk-9+127 From 58b0b8efb5df8e62ecaef8bd672e61dc3521ad4f Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Thu, 14 Jul 2016 15:47:46 +0000 Subject: [PATCH 34/43] Added tag jdk-9+127 for changeset a5744c1725a0 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 5a0ef0ed7ad..f2f2ce61f7e 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -369,3 +369,4 @@ c40c8739bcdc88892ff58ebee3fd8a3f287be94d jdk-9+123 7ff61c55b5c6c124592f09b18953222009a204a6 jdk-9+124 073ab1d4edf5590cf1af7b6d819350c14e425c1a jdk-9+125 6fda66a5bdf2da8994032b9da2078a4137f4d954 jdk-9+126 +7a97b89ba83077ca62e4aa5a05437adc8f315343 jdk-9+127 From ac12555ea3985946b1d30df380eb7c14ec6b9d94 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Thu, 14 Jul 2016 16:04:38 -0700 Subject: [PATCH 35/43] 8161426: Test java/util/zip/InflaterInputStream/TestAvailable.java fails on open-only linux Reviewed-by: bpb --- .../java/util/zip/InflaterInputStream/TestAvailable.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java b/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java index 1ac4d4b1779..1a8f3ba71e2 100644 --- a/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java +++ b/jdk/test/java/util/zip/InflaterInputStream/TestAvailable.java @@ -25,7 +25,7 @@ * @library /lib/testlibrary/ * @build jdk.testlibrary.* * @run main TestAvailable - * @bug 7031075 + * @bug 7031075 8161426 * @summary Make sure that available() method behaves as expected. * @key randomness */ @@ -40,9 +40,8 @@ public class TestAvailable { public static void main(String args[]) throws Throwable { Random r = RandomFactory.getRandom(); for (int n = 0; n < 10; n++) { - byte[] src = new byte[r.nextInt(100)]; + byte[] src = new byte[r.nextInt(100) + 1]; r.nextBytes(src); - // test InflaterInputStream ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DeflaterOutputStream dos = new DeflaterOutputStream(baos)) { From 799d14348e7f335fbf49fb22077219f5dab94549 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 15 Jul 2016 00:24:35 +0000 Subject: [PATCH 36/43] 8161171: Missed the make/common/Modules.gmk file when integrating JDK-8154191 Re-apply the same changes as reviewed under JDK-8154191. Reviewed-by: mchung --- make/common/Modules.gmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 92cc11b95ac..bd4747891f8 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2016, 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 @@ -71,7 +71,6 @@ BOOT_MODULES += \ # to be deprivileged BOOT_MODULES += \ - java.smartcardio \ jdk.naming.rmi \ # @@ -104,6 +103,7 @@ PLATFORM_MODULES += \ PLATFORM_MODULES += \ java.compiler \ java.scripting \ + java.smartcardio \ java.sql \ java.sql.rowset \ jdk.accessibility \ From 99cea12e9087841db179a0d7b3c6a8d579a22b66 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 15 Jul 2016 01:24:22 +0000 Subject: [PATCH 37/43] 8136459: MessageDigest.isEqual is not a "simple byte compare" Update the corresponding javadoc with @implNote and clarification. Reviewed-by: mullan, darcy --- .../share/classes/java/security/MessageDigest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/security/MessageDigest.java b/jdk/src/java.base/share/classes/java/security/MessageDigest.java index a226bfd3da2..3c08a64fbf8 100644 --- a/jdk/src/java.base/share/classes/java/security/MessageDigest.java +++ b/jdk/src/java.base/share/classes/java/security/MessageDigest.java @@ -439,7 +439,12 @@ public abstract class MessageDigest extends MessageDigestSpi { } /** - * Compares two digests for equality. Does a simple byte compare. + * Compares two digests for equality. Two digests are equal if they have + * the same length and all bytes at corresponding positions are equal. + * + * @implNote + * If the digests are the same length, all bytes are examined to + * determine equality. * * @param digesta one of the digests to compare. * From 0475827ed55191a4bdb06e18a37bb2e07c51bfa9 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Thu, 14 Jul 2016 19:42:16 -0700 Subject: [PATCH 38/43] 8154821: Update issue number for sun/security/pkcs11/ec/TestKeyFactory.java in ProblemList Sun/security/pkcs11/ec/TestKeyFactory.java is tracked by 8026976 instead of 7157786 Reviewed-by: xuelei --- jdk/test/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 2e7da24b031..760c10816e1 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -213,7 +213,7 @@ java/rmi/transport/dgcDeadLock/DGCDeadLock.java 8029360 macosx-a # jdk_security -sun/security/pkcs11/ec/TestKeyFactory.java 7157786 generic-all +sun/security/pkcs11/ec/TestKeyFactory.java 8026976 generic-all sun/security/krb5/auto/Unreachable.java 7164518 macosx-all From 05b3d5c63f6407aa85e8bc4c87179b8f97102c62 Mon Sep 17 00:00:00 2001 From: Vyom Tewari Date: Fri, 15 Jul 2016 14:06:50 +0530 Subject: [PATCH 39/43] 8151788: NullPointerException from ntlm.Client.type3 Reviewed-by: chegar, prappo, weijun --- .../classes/com/sun/security/ntlm/NTLM.java | 2 +- .../www/protocol/http/NULLTargetInfoTest.java | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/net/www/protocol/http/NULLTargetInfoTest.java diff --git a/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java b/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java index 0d13d83411c..cb558c6d072 100644 --- a/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java +++ b/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java @@ -169,7 +169,7 @@ class NTLM { byte[] readSecurityBuffer(int offset) throws NTLMException { int pos = readInt(offset+4); - if (pos == 0) return null; + if (pos == 0) return new byte[0]; try { return Arrays.copyOfRange( internal, pos, pos + readShort(offset)); diff --git a/jdk/test/sun/net/www/protocol/http/NULLTargetInfoTest.java b/jdk/test/sun/net/www/protocol/http/NULLTargetInfoTest.java new file mode 100644 index 00000000000..d8e88554f86 --- /dev/null +++ b/jdk/test/sun/net/www/protocol/http/NULLTargetInfoTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, 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 8151788 + * @summary NullPointerException from ntlm.Client.type3 + * @modules java.base/com.sun.security.ntlm + * @run main NULLTargetInfoTest + */ +import com.sun.security.ntlm.Client; + +public class NULLTargetInfoTest { + + public static void main(String[] args) throws Exception { + Client c = new Client(null, "host", "user", "domain", "pass".toCharArray()); + c.type1(); + // this input does have the 0x800000 bit(NTLMSSP_NEGOTIATE_TARGET_INFO) set + // but after offset 40 all eight bytes are all zero which means there is no + // security buffer for target info. + byte[] type2 = hex( + "4E 54 4C 4D 53 53 50 00 02 00 00 00 00 00 00 00" + + "00 00 00 00 05 82 89 00 0B 87 81 B6 2D 6E 8B C1" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + byte[] nonce = new byte[10]; + c.type3(type2, nonce); + } + + private static byte[] hex(String str) { + str = str.replaceAll("\\s", ""); + byte[] response = new byte[str.length() / 2]; + int index = 0; + for (int i = 0; i < str.length(); i += 2) { + response[index++] = Integer.valueOf(str.substring(i, i + 2), 16).byteValue(); + } + return response; + } +} From 4b1893fad98a76850572abce293f2080799dfe77 Mon Sep 17 00:00:00 2001 From: Vyom Tewari Date: Fri, 15 Jul 2016 13:59:03 +0530 Subject: [PATCH 40/43] 8144692: HttpServer API: use of non-existant method in example in package Javadoc Reviewed-by: chegar, prappo --- .../share/classes/com/sun/net/httpserver/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java b/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java index 9737f97cca7..f0af11d3959 100644 --- a/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java +++ b/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java @@ -54,7 +54,7 @@ } ... - HttpServer server = HttpServer.create(new InetSocketAddress(8000)); + HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/applications/myapp", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); From 90e6b1dedda11d90d094e623ae6de9af41ca4144 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 15 Jul 2016 17:31:30 +0100 Subject: [PATCH 41/43] 8161036: Fix copyright header Reviewed-by: mchung --- .../java.base/share/classes/java/lang/module/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/lang/module/package-info.java b/jdk/src/java.base/share/classes/java/lang/module/package-info.java index a1c44d68145..f641638cb2c 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/package-info.java +++ b/jdk/src/java.base/share/classes/java/lang/module/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 From d46ee264dff6171a9024380a36515531026fc242 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 15 Jul 2016 12:30:10 -0700 Subject: [PATCH 42/43] 8161413: Math.fma javadoc doesn't have @since 9 Add @since tag for float and double versions of fma(). Reviewed-by: rriggs --- jdk/src/java.base/share/classes/java/lang/Math.java | 4 ++++ jdk/src/java.base/share/classes/java/lang/StrictMath.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/jdk/src/java.base/share/classes/java/lang/Math.java b/jdk/src/java.base/share/classes/java/lang/Math.java index aa678b875ec..4261bd2c3f1 100644 --- a/jdk/src/java.base/share/classes/java/lang/Math.java +++ b/jdk/src/java.base/share/classes/java/lang/Math.java @@ -1613,6 +1613,8 @@ public final class Math { * @return (a × b + c) * computed, as if with unlimited range and precision, and rounded * once to the nearest {@code double} value + * + * @since 9 */ // @HotSpotIntrinsicCandidate public static double fma(double a, double b, double c) { @@ -1728,6 +1730,8 @@ public final class Math { * @return (a × b + c) * computed, as if with unlimited range and precision, and rounded * once to the nearest {@code float} value + * + * @since 9 */ // @HotSpotIntrinsicCandidate public static float fma(float a, float b, float c) { diff --git a/jdk/src/java.base/share/classes/java/lang/StrictMath.java b/jdk/src/java.base/share/classes/java/lang/StrictMath.java index 998fc1eb426..3ef67145d0c 100644 --- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java +++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java @@ -1276,6 +1276,8 @@ public final class StrictMath { * @return (a × b + c) * computed, as if with unlimited range and precision, and rounded * once to the nearest {@code double} value + * + * @since 9 */ public static double fma(double a, double b, double c) { return Math.fma(a, b, c); @@ -1328,6 +1330,8 @@ public final class StrictMath { * @return (a × b + c) * computed, as if with unlimited range and precision, and rounded * once to the nearest {@code float} value + * + * @since 9 */ public static float fma(float a, float b, float c) { return Math.fma(a, b, c); From 9d9145a699e2fff02b7a375d0d1fe5932aa6b23b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 15 Jul 2016 13:23:02 -0700 Subject: [PATCH 43/43] 8161455: Missing word in API documentation Change "file has created" to "file has been created" in two places. Reviewed-by: rriggs, alanb --- jdk/src/java.base/share/classes/java/nio/file/Files.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/nio/file/Files.java b/jdk/src/java.base/share/classes/java/nio/file/Files.java index e1ab41b7759..3a6491440a7 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/Files.java +++ b/jdk/src/java.base/share/classes/java/nio/file/Files.java @@ -3290,8 +3290,8 @@ public final class Files { * a size of {@code 0}. All bytes in the byte array are written to the file. * The method ensures that the file is closed when all bytes have been * written (or an I/O error or other runtime exception is thrown). If an I/O - * error occurs then it may do so after the file has created or truncated, - * or after some bytes have been written to the file. + * error occurs then it may do so after the file has been created or + * truncated, or after some bytes have been written to the file. * *

      Usage example: By default the method creates a new file or * overwrites an existing file. Suppose you instead want to append bytes @@ -3360,7 +3360,8 @@ public final class Files { * a size of {@code 0}. The method ensures that the file is closed when all * lines have been written (or an I/O error or other runtime exception is * thrown). If an I/O error occurs then it may do so after the file has - * created or truncated, or after some bytes have been written to the file. + * been created or truncated, or after some bytes have been written to the + * file. * * @param path * the path to the file