handling invalid ConstantValue attributes

Alex Buckley alex.buckley at oracle.com
Thu Nov 3 22:52:48 UTC 2016


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