8174740: RuntimeException: Module m's descriptor returns inconsistent package set

Reviewed-by: alanb
This commit is contained in:
Mandy Chung 2017-02-12 16:45:00 -08:00
parent bfe5d05b1c
commit 9d0a07ff25
3 changed files with 77 additions and 38 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017, 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
@ -46,11 +46,16 @@ import java.util.TreeSet;
import java.util.function.IntSupplier;
import jdk.internal.module.Checks;
import jdk.internal.module.ClassFileAttributes;
import jdk.internal.module.ClassFileConstants;
import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleInfo.Attributes;
import jdk.internal.module.ModuleInfoExtender;
import jdk.internal.module.ModuleResolution;
import jdk.internal.module.SystemModules;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -108,6 +113,11 @@ public final class SystemModulesPlugin implements Plugin {
return true;
}
@Override
public String getArgumentsDescription() {
return PluginsResourceBundle.getArgument(NAME);
}
@Override
public void configure(Map<String, String> config) {
String arg = config.get(NAME);
@ -171,10 +181,11 @@ public final class SystemModulesPlugin implements Plugin {
}
static class ModuleInfo {
private final ByteArrayInputStream bain;
private final Attributes attrs;
private final Set<String> packages;
private final ByteArrayInputStream bain;
private final boolean dropModuleTarget;
private final boolean addModulePackages;
private ModuleDescriptor descriptor; // may be different that the original one
ModuleInfo(byte[] bytes, Set<String> packages, boolean dropModuleTarget)
@ -182,15 +193,21 @@ public final class SystemModulesPlugin implements Plugin {
{
this.bain = new ByteArrayInputStream(bytes);
this.packages = packages;
this.attrs = jdk.internal.module.ModuleInfo.read(bain, null);
// If ModulePackages attribute is present, the packages from this
// module descriptor returns the packages in that attribute.
// If it's not present, ModuleDescriptor::packages only contains
// the exported and open packages from module-info.class
this.descriptor = attrs.descriptor();
if (descriptor.isAutomatic()) {
throw new InternalError("linking automatic module is not supported");
}
// add ModulePackages attribute if this module contains some packages
// and ModulePackages is not present
this.addModulePackages = packages.size() > 0 && !hasModulePackages();
// drop target attribute only if any OS property is present
if (dropModuleTarget) {
// drop target attribute only if any OS property is present
this.dropModuleTarget =
descriptor.osName().isPresent() ||
descriptor.osArch().isPresent() ||
@ -276,53 +293,71 @@ public final class SystemModulesPlugin implements Plugin {
}
}
boolean hasModulePackages() throws IOException {
Set<String> attrTypes = new HashSet<>();
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
@Override
public void visitAttribute(Attribute attr) {
attrTypes.add(attr.type);
}
};
// prototype of attributes that should be parsed
Attribute[] attrs = new Attribute[] {
new ClassFileAttributes.ModulePackagesAttribute()
};
try (InputStream in = getInputStream()) {
// parse module-info.class
ClassReader cr = new ClassReader(in);
cr.accept(cv, attrs, 0);
return attrTypes.contains(ClassFileConstants.MODULE_PACKAGES);
}
}
/**
* Returns true if module-info.class should be written
* 1. add ModulePackages attribute if not present; or
* 2. drop ModuleTarget attribute except java.base
*/
boolean shouldRewrite() {
return shouldAddModulePackages() || shouldDropModuleTarget();
}
boolean shouldAddModulePackages() {
return (descriptor.packages().isEmpty() && packages.size() > 0);
}
boolean shouldDropModuleTarget() {
return dropModuleTarget &&
(descriptor.osName().isPresent() ||
descriptor.osArch().isPresent() ||
descriptor.osVersion().isPresent());
return addModulePackages || dropModuleTarget;
}
/**
* Returns the bytes for the module-info.class with ModulePackages
* if it contains at least one package
* attribute added and/or with ModuleTarget attribute dropped.
*/
byte[] getBytes() throws IOException {
bain.reset();
// add ModulePackages attribute if not exist
if (shouldRewrite()) {
ModuleInfoRewriter rewriter = new ModuleInfoRewriter(bain);
if (shouldAddModulePackages()) {
rewriter.addModulePackages(packages);
try (InputStream in = getInputStream()) {
if (shouldRewrite()) {
ModuleInfoRewriter rewriter = new ModuleInfoRewriter(in);
if (addModulePackages) {
rewriter.addModulePackages(packages);
}
if (dropModuleTarget) {
rewriter.dropModuleTarget();
}
// rewritten module descriptor
byte[] bytes = rewriter.getBytes();
try (ByteArrayInputStream bain = new ByteArrayInputStream(bytes)) {
this.descriptor = ModuleDescriptor.read(bain);
}
return bytes;
} else {
return in.readAllBytes();
}
if (shouldDropModuleTarget()) {
rewriter.dropModuleTarget();
}
// rewritten module descriptor
byte[] bytes = rewriter.getBytes();
try (ByteArrayInputStream bain = new ByteArrayInputStream(bytes)) {
this.descriptor = ModuleDescriptor.read(bain);
}
return bytes;
} else {
return bain.readAllBytes();
}
}
/*
* Returns the input stream of the module-info.class
*/
InputStream getInputStream() {
bain.reset();
return bain;
}
class ModuleInfoRewriter extends ByteArrayOutputStream {
final ModuleInfoExtender extender;
ModuleInfoRewriter(InputStream in) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -45,7 +45,7 @@ import static org.testng.Assert.*;
/**
* @test
* @bug 8142968 8173381
* @bug 8142968 8173381 8174740
* @library /lib/testlibrary
* @modules jdk.compiler jdk.jlink
* @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -21,5 +21,9 @@
* questions.
*/
/*
* m1 has an exported package and also internal package
*/
module m1 {
exports p1;
}