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

Javac generates invalid signatures for local types

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 7u51, 8, 9
    • Fix Version/s: 8u20
    • Component/s: tools
    • Labels:
    • Subcomponent:
    • Resolved In Build:
      b20
    • CPU:
      x86_64
    • OS:
      linux_ubuntu

      Backports

        Description

        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.

          Attachments

            Issue Links

              Activity

                People

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

                  Dates

                  Created:
                  Updated:
                  Resolved: