30 import java.io.EOFException;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.UncheckedIOException;
34 import java.lang.module.ModuleDescriptor.Builder;
35 import java.lang.module.ModuleDescriptor.Requires;
36 import java.lang.module.ModuleDescriptor.Exports;
37 import java.lang.module.ModuleDescriptor.Opens;
38 import java.nio.ByteBuffer;
39 import java.nio.BufferUnderflowException;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.function.Supplier;
48
49 import jdk.internal.module.ModuleHashes;
50
51 import static jdk.internal.module.ClassFileConstants.*;
52
53
54 /**
55 * Read module information from a {@code module-info} class file.
56 *
57 * @implNote The rationale for the hand-coded reader is startup performance
58 * and fine control over the throwing of InvalidModuleDescriptorException.
59 */
60
61 final class ModuleInfo {
62
63 // supplies the set of packages when ModulePackages attribute not present
64 private final Supplier<Set<String>> packageFinder;
65
66 // indicates if the ModuleHashes attribute should be parsed
67 private final boolean parseHashes;
68
69 private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
70 packageFinder = pf;
71 parseHashes = ph;
72 }
176
177 int fields_count = in.readUnsignedShort();
178 if (fields_count > 0)
179 throw invalidModuleDescriptor("Bad #fields");
180
181 int methods_count = in.readUnsignedShort();
182 if (methods_count > 0)
183 throw invalidModuleDescriptor("Bad #methods");
184
185 int attributes_count = in.readUnsignedShort();
186
187 // the names of the attributes found in the class file
188 Set<String> attributes = new HashSet<>();
189
190 Builder builder = null;
191 Set<String> packages = null;
192 String version = null;
193 String mainClass = null;
194 String[] osValues = null;
195 ModuleHashes hashes = null;
196
197 for (int i = 0; i < attributes_count ; i++) {
198 int name_index = in.readUnsignedShort();
199 String attribute_name = cpool.getUtf8(name_index);
200 int length = in.readInt();
201
202 boolean added = attributes.add(attribute_name);
203 if (!added && isAttributeAtMostOnce(attribute_name)) {
204 throw invalidModuleDescriptor("More than one "
205 + attribute_name + " attribute");
206 }
207
208 switch (attribute_name) {
209
210 case MODULE :
211 builder = readModuleAttribute(in, cpool);
212 break;
213
214 case MODULE_PACKAGES :
215 packages = readModulePackagesAttribute(in, cpool);
218 case MODULE_VERSION :
219 version = readModuleVersionAttribute(in, cpool);
220 break;
221
222 case MODULE_MAIN_CLASS :
223 mainClass = readModuleMainClassAttribute(in, cpool);
224 break;
225
226 case MODULE_TARGET :
227 osValues = readModuleTargetAttribute(in, cpool);
228 break;
229
230 case MODULE_HASHES :
231 if (parseHashes) {
232 hashes = readModuleHashesAttribute(in, cpool);
233 } else {
234 in.skipBytes(length);
235 }
236 break;
237
238 default:
239 if (isAttributeDisallowed(attribute_name)) {
240 throw invalidModuleDescriptor(attribute_name
241 + " attribute not allowed");
242 } else {
243 in.skipBytes(length);
244 }
245
246 }
247 }
248
249 // the Module attribute is required
250 if (builder == null) {
251 throw invalidModuleDescriptor(MODULE + " attribute not found");
252 }
253
254 // If the ModulePackages attribute is not present then the packageFinder
255 // is used to find the set of packages
256 boolean usedPackageFinder = false;
257 if (packages == null && packageFinder != null) {
272 tail = " missing from ModulePackages attribute";
273 }
274 throw invalidModuleDescriptor("Package " + pn + tail);
275 }
276 packages.remove(pn);
277 }
278 builder.contains(packages);
279 }
280
281 if (version != null)
282 builder.version(version);
283 if (mainClass != null)
284 builder.mainClass(mainClass);
285 if (osValues != null) {
286 if (osValues[0] != null) builder.osName(osValues[0]);
287 if (osValues[1] != null) builder.osArch(osValues[1]);
288 if (osValues[2] != null) builder.osVersion(osValues[2]);
289 }
290 if (hashes != null)
291 builder.hashes(hashes);
292
293 return builder.build();
294 }
295
296 /**
297 * Reads the Module attribute, returning the ModuleDescriptor.Builder to
298 * build the corresponding ModuleDescriptor.
299 */
300 private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
301 throws IOException
302 {
303 // module_name
304 int module_name_index = in.readUnsignedShort();
305 String mn = cpool.getUtf8AsBinaryName(module_name_index);
306
307 Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
308
309 int module_flags = in.readUnsignedShort();
310 boolean open = ((module_flags & ACC_OPEN) != 0);
311 if (open)
512 int algorithm_index = in.readUnsignedShort();
513 String algorithm = cpool.getUtf8(algorithm_index);
514
515 int hash_count = in.readUnsignedShort();
516 Map<String, byte[]> map = new HashMap<>(hash_count);
517 for (int i=0; i<hash_count; i++) {
518 int module_name_index = in.readUnsignedShort();
519 String mn = cpool.getUtf8AsBinaryName(module_name_index);
520 int hash_length = in.readUnsignedShort();
521 if (hash_length == 0) {
522 throw invalidModuleDescriptor("hash_length == 0");
523 }
524 byte[] hash = new byte[hash_length];
525 in.readFully(hash);
526 map.put(mn, hash);
527 }
528
529 return new ModuleHashes(algorithm, map);
530 }
531
532
533 /**
534 * Returns true if the given attribute can be present at most once
535 * in the class file. Returns false otherwise.
536 */
537 private static boolean isAttributeAtMostOnce(String name) {
538
539 if (name.equals(MODULE) ||
540 name.equals(SOURCE_FILE) ||
541 name.equals(SDE) ||
542 name.equals(MODULE_PACKAGES) ||
543 name.equals(MODULE_VERSION) ||
544 name.equals(MODULE_MAIN_CLASS) ||
545 name.equals(MODULE_TARGET) ||
546 name.equals(MODULE_HASHES))
547 return true;
548
549 return false;
550 }
551
552 /**
553 * Return true if the given attribute name is the name of a pre-defined
554 * attribute that is not allowed in the class file.
555 *
556 * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
557 * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
558 */
559 private static boolean isAttributeDisallowed(String name) {
560 Set<String> notAllowed = predefinedNotAllowed;
561 if (notAllowed == null) {
562 notAllowed = Set.of(
563 "ConstantValue",
564 "Code",
565 "StackMapTable",
566 "Exceptions",
|
30 import java.io.EOFException;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.UncheckedIOException;
34 import java.lang.module.ModuleDescriptor.Builder;
35 import java.lang.module.ModuleDescriptor.Requires;
36 import java.lang.module.ModuleDescriptor.Exports;
37 import java.lang.module.ModuleDescriptor.Opens;
38 import java.nio.ByteBuffer;
39 import java.nio.BufferUnderflowException;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.function.Supplier;
48
49 import jdk.internal.module.ModuleHashes;
50 import jdk.internal.module.WarnIfResolvedReason;
51
52 import static jdk.internal.module.ClassFileConstants.*;
53 import static jdk.internal.module.WarnIfResolvedReason.fromClassFileFlags;
54
55 /**
56 * Read module information from a {@code module-info} class file.
57 *
58 * @implNote The rationale for the hand-coded reader is startup performance
59 * and fine control over the throwing of InvalidModuleDescriptorException.
60 */
61
62 final class ModuleInfo {
63
64 // supplies the set of packages when ModulePackages attribute not present
65 private final Supplier<Set<String>> packageFinder;
66
67 // indicates if the ModuleHashes attribute should be parsed
68 private final boolean parseHashes;
69
70 private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
71 packageFinder = pf;
72 parseHashes = ph;
73 }
177
178 int fields_count = in.readUnsignedShort();
179 if (fields_count > 0)
180 throw invalidModuleDescriptor("Bad #fields");
181
182 int methods_count = in.readUnsignedShort();
183 if (methods_count > 0)
184 throw invalidModuleDescriptor("Bad #methods");
185
186 int attributes_count = in.readUnsignedShort();
187
188 // the names of the attributes found in the class file
189 Set<String> attributes = new HashSet<>();
190
191 Builder builder = null;
192 Set<String> packages = null;
193 String version = null;
194 String mainClass = null;
195 String[] osValues = null;
196 ModuleHashes hashes = null;
197 int moduleResolution = 0;
198
199 for (int i = 0; i < attributes_count ; i++) {
200 int name_index = in.readUnsignedShort();
201 String attribute_name = cpool.getUtf8(name_index);
202 int length = in.readInt();
203
204 boolean added = attributes.add(attribute_name);
205 if (!added && isAttributeAtMostOnce(attribute_name)) {
206 throw invalidModuleDescriptor("More than one "
207 + attribute_name + " attribute");
208 }
209
210 switch (attribute_name) {
211
212 case MODULE :
213 builder = readModuleAttribute(in, cpool);
214 break;
215
216 case MODULE_PACKAGES :
217 packages = readModulePackagesAttribute(in, cpool);
220 case MODULE_VERSION :
221 version = readModuleVersionAttribute(in, cpool);
222 break;
223
224 case MODULE_MAIN_CLASS :
225 mainClass = readModuleMainClassAttribute(in, cpool);
226 break;
227
228 case MODULE_TARGET :
229 osValues = readModuleTargetAttribute(in, cpool);
230 break;
231
232 case MODULE_HASHES :
233 if (parseHashes) {
234 hashes = readModuleHashesAttribute(in, cpool);
235 } else {
236 in.skipBytes(length);
237 }
238 break;
239
240 case MODULE_RESOLUTION :
241 moduleResolution = readModuleResolution(in, cpool);
242 break;
243
244 default:
245 if (isAttributeDisallowed(attribute_name)) {
246 throw invalidModuleDescriptor(attribute_name
247 + " attribute not allowed");
248 } else {
249 in.skipBytes(length);
250 }
251
252 }
253 }
254
255 // the Module attribute is required
256 if (builder == null) {
257 throw invalidModuleDescriptor(MODULE + " attribute not found");
258 }
259
260 // If the ModulePackages attribute is not present then the packageFinder
261 // is used to find the set of packages
262 boolean usedPackageFinder = false;
263 if (packages == null && packageFinder != null) {
278 tail = " missing from ModulePackages attribute";
279 }
280 throw invalidModuleDescriptor("Package " + pn + tail);
281 }
282 packages.remove(pn);
283 }
284 builder.contains(packages);
285 }
286
287 if (version != null)
288 builder.version(version);
289 if (mainClass != null)
290 builder.mainClass(mainClass);
291 if (osValues != null) {
292 if (osValues[0] != null) builder.osName(osValues[0]);
293 if (osValues[1] != null) builder.osArch(osValues[1]);
294 if (osValues[2] != null) builder.osVersion(osValues[2]);
295 }
296 if (hashes != null)
297 builder.hashes(hashes);
298 if (moduleResolution != 0) {
299 builder.doNotResolveByDefault(doNotResolveFromFlags(moduleResolution));
300 builder.warnIfResolved(fromClassFileFlags(moduleResolution));
301 }
302
303 return builder.build();
304 }
305
306 /**
307 * Reads the Module attribute, returning the ModuleDescriptor.Builder to
308 * build the corresponding ModuleDescriptor.
309 */
310 private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
311 throws IOException
312 {
313 // module_name
314 int module_name_index = in.readUnsignedShort();
315 String mn = cpool.getUtf8AsBinaryName(module_name_index);
316
317 Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
318
319 int module_flags = in.readUnsignedShort();
320 boolean open = ((module_flags & ACC_OPEN) != 0);
321 if (open)
522 int algorithm_index = in.readUnsignedShort();
523 String algorithm = cpool.getUtf8(algorithm_index);
524
525 int hash_count = in.readUnsignedShort();
526 Map<String, byte[]> map = new HashMap<>(hash_count);
527 for (int i=0; i<hash_count; i++) {
528 int module_name_index = in.readUnsignedShort();
529 String mn = cpool.getUtf8AsBinaryName(module_name_index);
530 int hash_length = in.readUnsignedShort();
531 if (hash_length == 0) {
532 throw invalidModuleDescriptor("hash_length == 0");
533 }
534 byte[] hash = new byte[hash_length];
535 in.readFully(hash);
536 map.put(mn, hash);
537 }
538
539 return new ModuleHashes(algorithm, map);
540 }
541
542 /**
543 * Reads the ModuleResolution attribute.
544 */
545 private int readModuleResolution(DataInput in, ConstantPool cpool)
546 throws IOException
547 {
548 int flags = in.readUnsignedShort();
549
550 // just some basic validation
551 int reason = 0;
552 if ((flags & WARN_DEPRECATED) != 0)
553 reason = WARN_DEPRECATED;
554 if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
555 if (reason != 0)
556 throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
557 reason = WARN_DEPRECATED_FOR_REMOVAL;
558 }
559 if ((flags & WARN_INCUBATING) != 0) {
560 if (reason != 0)
561 throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
562 }
563
564 return flags;
565 }
566
567 private boolean doNotResolveFromFlags(int flags) {
568 return (flags & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
569 }
570
571 /**
572 * Returns true if the given attribute can be present at most once
573 * in the class file. Returns false otherwise.
574 */
575 private static boolean isAttributeAtMostOnce(String name) {
576
577 if (name.equals(MODULE) ||
578 name.equals(SOURCE_FILE) ||
579 name.equals(SDE) ||
580 name.equals(MODULE_PACKAGES) ||
581 name.equals(MODULE_VERSION) ||
582 name.equals(MODULE_MAIN_CLASS) ||
583 name.equals(MODULE_TARGET) ||
584 name.equals(MODULE_HASHES) ||
585 name.equals(MODULE_RESOLUTION))
586 return true;
587
588 return false;
589 }
590
591 /**
592 * Return true if the given attribute name is the name of a pre-defined
593 * attribute that is not allowed in the class file.
594 *
595 * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
596 * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
597 */
598 private static boolean isAttributeDisallowed(String name) {
599 Set<String> notAllowed = predefinedNotAllowed;
600 if (notAllowed == null) {
601 notAllowed = Set.of(
602 "ConstantValue",
603 "Code",
604 "StackMapTable",
605 "Exceptions",
|