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

Javac generates invalid signatures for local types

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 8u20
    • 7u51, 8, 9
    • tools
    • b20
    • x86_64
    • 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

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

                Dates

                  Created:
                  Updated:
                  Resolved: