Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8037934

Javac generates invalid signatures for local types

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 8u20
    • 7u51, 8, 9
    • tools
    • b20
    • x86_64
    • linux_ubuntu

        FULL PRODUCT VERSION :
        Tested on OpenJDK 7 and seen the same bug in OpenJDK 8 source code

        ADDITIONAL OS VERSION INFORMATION :
        Irrelevant: this is generic code

        A DESCRIPTION OF THE PROBLEM :
        The following code compiles but fails to run:

        class Foo<Outer> {
            void m(){
                class Local1{}
                class Local2 extends Local1{}
                Local2.class.getTypeParameters();
            }
            public static void main(String[] args) {
                new Foo().m();
                System.err.println("Test passed");
            }
        }

        This is because the signature attribute for Local2's super class is incorrectly generated by javac as "Lfoo/Foo.1Local1;" while it should be "Lfoo/Foo$1Local1;" (a dollar instead of a dot). Eclipse's compiler correctly generates the signature. Javac for OpenJDK 7 will generate an invalid signature resulting in the following exception at runtime:

        Exception in thread "main" java.lang.reflect.GenericSignatureFormatError
        at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:126)
        at sun.reflect.generics.parser.SignatureParser.parsePackageNameAndSimpleClassTypeSignature(SignatureParser.java:350)
        at sun.reflect.generics.parser.SignatureParser.parseClassTypeSignature(SignatureParser.java:312)
        at sun.reflect.generics.parser.SignatureParser.parseClassSignature(SignatureParser.java:214)
        at sun.reflect.generics.parser.SignatureParser.parseClassSig(SignatureParser.java:158)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:52)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:41)
        at sun.reflect.generics.repository.AbstractRepository.<init>(AbstractRepository.java:74)
        at sun.reflect.generics.repository.GenericDeclRepository.<init>(GenericDeclRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.<init>(ClassRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.make(ClassRepository.java:65)
        at java.lang.Class.getGenericInfo(Class.java:2360)
        at java.lang.Class.getTypeParameters(Class.java:640)
        at foo.Foo.m(foo.java:7)
        at foo.Foo.main(foo.java:10)

        The bug is due to com.sun.tools.javac.jvm.ClassWriter.assembleClassSig():

        ...
                if (outer.allparams().nonEmpty()) {
                    boolean rawOuter =
                        c.owner.kind == MTH || // either a local class
                        c.name == names.empty; // or anonymous
                    assembleClassSig(rawOuter
                                     ? types.erasure(outer)
                                     : outer);
                    sigbuf.appendByte('.'); // BUG HERE
                    Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
                    sigbuf.appendName(rawOuter
                                      ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength()+1,c.flatname.getByteLength())
                                      : c.name);
                } else {
        ...

        If we replace the line with "BUG HERE" with:

                    sigbuf.appendByte(rawOuter ? '$' : '.');

        Then it works.

        The same bug seems to be present in OpenJDK 8 but the code has moved to Types.java: http://hg.openjdk.java.net/jdk8/jdk8/langtools/file/1ff9d5118aae/src/share/classes/com/sun/tools/javac/code/Types.java#l4652


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Compile the sample Java code, run foo.Foo

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Expected to see "Test passed"
        ACTUAL -
        Exception in thread "main" java.lang.reflect.GenericSignatureFormatError
        at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:126)
        at sun.reflect.generics.parser.SignatureParser.parsePackageNameAndSimpleClassTypeSignature(SignatureParser.java:350)
        at sun.reflect.generics.parser.SignatureParser.parseClassTypeSignature(SignatureParser.java:312)
        at sun.reflect.generics.parser.SignatureParser.parseClassSignature(SignatureParser.java:214)
        at sun.reflect.generics.parser.SignatureParser.parseClassSig(SignatureParser.java:158)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:52)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:41)
        at sun.reflect.generics.repository.AbstractRepository.<init>(AbstractRepository.java:74)
        at sun.reflect.generics.repository.GenericDeclRepository.<init>(GenericDeclRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.<init>(ClassRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.make(ClassRepository.java:65)
        at java.lang.Class.getGenericInfo(Class.java:2360)
        at java.lang.Class.getTypeParameters(Class.java:640)
        at foo.Foo.m(foo.java:7)
        at foo.Foo.main(foo.java:10)


        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" java.lang.reflect.GenericSignatureFormatError
        at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:126)
        at sun.reflect.generics.parser.SignatureParser.parsePackageNameAndSimpleClassTypeSignature(SignatureParser.java:350)
        at sun.reflect.generics.parser.SignatureParser.parseClassTypeSignature(SignatureParser.java:312)
        at sun.reflect.generics.parser.SignatureParser.parseClassSignature(SignatureParser.java:214)
        at sun.reflect.generics.parser.SignatureParser.parseClassSig(SignatureParser.java:158)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:52)
        at sun.reflect.generics.repository.ClassRepository.parse(ClassRepository.java:41)
        at sun.reflect.generics.repository.AbstractRepository.<init>(AbstractRepository.java:74)
        at sun.reflect.generics.repository.GenericDeclRepository.<init>(GenericDeclRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.<init>(ClassRepository.java:48)
        at sun.reflect.generics.repository.ClassRepository.make(ClassRepository.java:65)
        at java.lang.Class.getGenericInfo(Class.java:2360)
        at java.lang.Class.getTypeParameters(Class.java:640)
        at foo.Foo.m(foo.java:7)
        at foo.Foo.main(foo.java:10)


        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        class Foo<Outer> {
            void m(){
                class Local1{}
                class Local2 extends Local1{}
                Local2.class.getTypeParameters();
            }
            public static void main(String[] args) {
                new Foo().m();
                System.err.println("Test passed");
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        For some reason, if the Foo outer class does not take type parameters, the bug will not trigger at runtime.

              pgovereau Paul Govereau (Inactive)
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Created:
                Updated:
                Resolved: