8336585: BoundAttribute.readEntryList not type-safe
Reviewed-by: asotona
This commit is contained in:
parent
b44632aa15
commit
902c2afb67
src/java.base/share/classes/jdk/internal/classfile/impl
test/jdk/jdk/classfile
@ -25,12 +25,6 @@
|
||||
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.*;
|
||||
import java.lang.classfile.constantpool.ClassEntry;
|
||||
@ -40,7 +34,14 @@ import java.lang.classfile.constantpool.LoadableConstantEntry;
|
||||
import java.lang.classfile.constantpool.ModuleEntry;
|
||||
import java.lang.classfile.constantpool.NameAndTypeEntry;
|
||||
import java.lang.classfile.constantpool.PackageEntry;
|
||||
import java.lang.classfile.constantpool.PoolEntry;
|
||||
import java.lang.classfile.constantpool.Utf8Entry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
|
||||
import static java.lang.classfile.Attributes.*;
|
||||
@ -116,13 +117,13 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
return String.format("Attribute[name=%s]", mapper.name());
|
||||
}
|
||||
|
||||
<E> List<E> readEntryList(int p) {
|
||||
<E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
|
||||
int cnt = classReader.readU2(p);
|
||||
p += 2;
|
||||
var entries = new Object[cnt];
|
||||
int end = p + (cnt * 2);
|
||||
for (int i = 0; p < end; i++, p += 2) {
|
||||
entries[i] = classReader.readEntry(p);
|
||||
entries[i] = classReader.readEntry(p, type);
|
||||
}
|
||||
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
|
||||
}
|
||||
@ -549,7 +550,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
@Override
|
||||
public List<ClassEntry> exceptions() {
|
||||
if (exceptions == null) {
|
||||
exceptions = readEntryList(payloadStart);
|
||||
exceptions = readEntryList(payloadStart, ClassEntry.class);
|
||||
}
|
||||
return exceptions;
|
||||
}
|
||||
@ -645,7 +646,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
PackageEntry pe = classReader.readEntry(p, PackageEntry.class);
|
||||
int exportFlags = classReader.readU2(p + 2);
|
||||
p += 4;
|
||||
List<ModuleEntry> exportsTo = readEntryList(p);
|
||||
List<ModuleEntry> exportsTo = readEntryList(p, ModuleEntry.class);
|
||||
p += 2 + exportsTo.size() * 2;
|
||||
elements[i] = ModuleExportInfo.of(pe, exportFlags, exportsTo);
|
||||
}
|
||||
@ -660,7 +661,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
PackageEntry po = classReader.readEntry(p, PackageEntry.class);
|
||||
int opensFlags = classReader.readU2(p + 2);
|
||||
p += 4;
|
||||
List<ModuleEntry> opensTo = readEntryList(p);
|
||||
List<ModuleEntry> opensTo = readEntryList(p, ModuleEntry.class);
|
||||
p += 2 + opensTo.size() * 2;
|
||||
elements[i] = ModuleOpenInfo.of(po, opensFlags, opensTo);
|
||||
}
|
||||
@ -668,7 +669,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
}
|
||||
|
||||
{
|
||||
uses = readEntryList(p);
|
||||
uses = readEntryList(p, ClassEntry.class);
|
||||
p += 2 + uses.size() * 2;
|
||||
int cnt = classReader.readU2(p);
|
||||
p += 2;
|
||||
@ -677,7 +678,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
ClassEntry c = classReader.readEntry(p, ClassEntry.class);
|
||||
p += 2;
|
||||
List<ClassEntry> providesWith = readEntryList(p);
|
||||
List<ClassEntry> providesWith = readEntryList(p, ClassEntry.class);
|
||||
p += 2 + providesWith.size() * 2;
|
||||
elements[i] = ModuleProvideInfo.of(c, providesWith);
|
||||
}
|
||||
@ -697,7 +698,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
@Override
|
||||
public List<PackageEntry> packages() {
|
||||
if (packages == null) {
|
||||
packages = readEntryList(payloadStart);
|
||||
packages = readEntryList(payloadStart, PackageEntry.class);
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
@ -715,7 +716,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
@Override
|
||||
public List<ClassEntry> nestMembers() {
|
||||
if (members == null) {
|
||||
members = readEntryList(payloadStart);
|
||||
members = readEntryList(payloadStart, ClassEntry.class);
|
||||
}
|
||||
return members;
|
||||
}
|
||||
@ -744,7 +745,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
int p = payloadStart + 2;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class);
|
||||
final List<LoadableConstantEntry> args = readEntryList(p + 2);
|
||||
final List<LoadableConstantEntry> args = readEntryList(p + 2, LoadableConstantEntry.class);
|
||||
p += 4 + args.size() * 2;
|
||||
int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args);
|
||||
bs[i] = new BootstrapMethodEntryImpl(classReader, i, hash, handle, args);
|
||||
@ -924,7 +925,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
|
||||
@Override
|
||||
public List<ClassEntry> permittedSubclasses() {
|
||||
if (permittedSubclasses == null) {
|
||||
permittedSubclasses = readEntryList(payloadStart);
|
||||
permittedSubclasses = readEntryList(payloadStart, ClassEntry.class);
|
||||
}
|
||||
return permittedSubclasses;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 2024, 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,19 +23,24 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8304837
|
||||
* @bug 8304837 8336585
|
||||
* @summary Testing BoundAttributes
|
||||
* @run junit BoundAttributeTest
|
||||
*/
|
||||
import jdk.internal.classfile.impl.DirectClassBuilder;
|
||||
import jdk.internal.classfile.impl.UnboundAttribute;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.BufWriter;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.CodeBuilder;
|
||||
import java.lang.classfile.attribute.MethodParameterInfo;
|
||||
import java.lang.classfile.attribute.MethodParametersAttribute;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.lang.classfile.constantpool.ConstantPoolException;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
@ -67,4 +72,33 @@ class BoundAttributeTest {
|
||||
List<MethodParameterInfo> parameters = assertDoesNotThrow(methodParametersAttribute::parameters);
|
||||
assertTrue(parameters.get(0).name().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBadEntryTypeInList() {
|
||||
var cf = ClassFile.of();
|
||||
|
||||
// Craft an attribute list with index to badly typed attributes
|
||||
var bytes = cf.build(ClassDesc.of("Test"), clb -> {
|
||||
var cp = clb.constantPool();
|
||||
var oneClassString = cp.utf8Entry("Test$Ape");
|
||||
var oneClass = cp.classEntry(oneClassString);
|
||||
((DirectClassBuilder) clb).writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.nestMembers()) {
|
||||
@Override
|
||||
public void writeBody(BufWriter b) {
|
||||
b.writeU2(2);
|
||||
b.writeIndex(oneClass);
|
||||
b.writeIndex(oneClassString);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var nm = cf.parse(bytes).findAttribute(Attributes.nestMembers()).orElseThrow();
|
||||
Assertions.assertThrows(ConstantPoolException.class, () -> {
|
||||
int sum = 0;
|
||||
// this should throw CPE upon encountering non-ClassEntry
|
||||
for (var member : nm.nestMembers()) {
|
||||
sum += member.index();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user