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