handling invalid ConstantValue attributes
Jonathan Gibbons
jonathan.gibbons at oracle.com
Thu Nov 3 23:46:05 UTC 2016
A corresponding RFE/enhancement to javap would be to report any such
issues. It is already somewhat fault tolerant, and will print "???" or
similar as needed, but more cross-referencing and checking could be done.
-- Jon
On 11/03/2016 03:52 PM, Alex Buckley wrote:
> In Lib.class, the field A contains a ConstantValue attribute that is
> ill-formed, since the attribute points to a CONSTANT_String c.p. entry
> that is not appropriate for a Z-typed field (per JVMS8 4.7.2). A class
> file reader such as javac must reject Lib.class on this basis.
>
> In Lib.class, the field B contains a ConstantValue attribute that is
> not ill-formed, since the attribute points to a CONSTANT_Integer c.p.
> entry that is appropriate for a Z-typed field. A class file reader
> such as javac must not reject Lib.class on this basis. However, javac
> should handle an out-of-band value in the CONSTANT_Integer c.p. entry
> as a quality-of-implementation detail.
>
> Alex
>
> On 11/3/2016 3:26 PM, Liam Miller-Cushon wrote:
>> javac silently accepts class files containing ConstantValue attributes
>> of the incorrect
>> type, or outside of the allowed ranges for int, short, char, byte, and
>> booleans.
>>
>> I expected javac to either reject the invalid bytecode, or convert the
>> constants to
>> their canonical representation (e.g. constant booleans should always be
>> 0 or 1).
>>
>> ecj rejects constants with the wrong type, and normalizes values outside
>> of the
>> expected range.
>>
>> I couldn't find anything in the spec for this, is it up to the
>> implementation? Would it
>> be possible to change javac's behaviour here?
>>
>> === Dump.java
>> import java.nio.file.Files;
>> import java.nio.file.Paths;
>> import org.objectweb.asm.ClassWriter;
>> import org.objectweb.asm.Opcodes;
>>
>> public class Dump {
>>
>> public static void main(String[] args) throws Exception {
>> Files.write(Paths.get("Lib.class"), dump());
>> }
>>
>> static byte[] dump() {
>> ClassWriter cw = new ClassWriter(0);
>> cw.visit(52, Opcodes.ACC_SUPER, "Lib", null, "java/lang/Object",
>> null);
>> cw.visitField(
>> Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC,
>> "A", "Z", null, "hello");
>> cw.visitField(
>> Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC,
>> "B", "Z", null, 2);
>> cw.visitEnd();
>> return cw.toByteArray();
>> }
>> }
>> ===
>>
>> === Test.java
>> class Test {
>> static final boolean ONE = Lib.A;
>> static final boolean TWO = Lib.B;
>> }
>> ===
>>
>> === Test2.java
>> class Test2 {
>> static final boolean ONE = Lib.A || true;
>> }
>> ===
>>
>>
>> $ javac -cp asm-debug-all-5.1.jar Dump.java
>> $ java -cp asm-debug-all-5.1.jar:. Dump
>> $ javac Test.java
>> $ javap -v Test
>> ...
>> static final boolean ONE;
>> descriptor: Z
>> flags: ACC_STATIC, ACC_FINAL
>> ConstantValue: String hello
>>
>> static final boolean TWO;
>> descriptor: Z
>> flags: ACC_STATIC, ACC_FINAL
>> ConstantValue: int 2
>>
>> $ javac Test2.java
>> ...
>> java.lang.AssertionError: java.lang.ClassCastException: java.lang.String
>> (in module: java.base) cannot be cast to java.lang.Number (in module:
>> java.base)
>> at
>> com.sun.tools.javac.code.Symbol$VarSymbol.getConstValue(jdk.compiler at 9-ea/Symbol.java:1530)
>>
>> at
>> com.sun.tools.javac.comp.Attr.visitVarDef(jdk.compiler at 9-ea/Attr.java:1122)
>>
>> ...
>> Caused by: java.lang.ClassCastException: java.lang.String (in module:
>> java.base) cannot be cast to java.lang.Number (in module: java.base)
>> at
>> com.sun.tools.javac.comp.ConstFold.intValue(jdk.compiler at 9-ea/ConstFold.java:71)
>>
>> at
>> com.sun.tools.javac.comp.ConstFold.fold2(jdk.compiler at 9-ea/ConstFold.java:187)
>>
>> at
>> com.sun.tools.javac.comp.Attr.visitBinary(jdk.compiler at 9-ea/Attr.java:3211)
>>
More information about the compiler-dev
mailing list