JDK-8189335: NPE in Lower due to class name clash
B. Blaser
bsrbnd at gmail.com
Thu Feb 22 20:09:35 UTC 2018
On 21 February 2018 at 16:58, B. Blaser <bsrbnd at gmail.com> wrote:
> On 19 February 2018 at 15:53, B. Blaser <bsrbnd at gmail.com> wrote:
>> On 19 February 2018 at 00:42, B. Blaser <bsrbnd at gmail.com> wrote:
>>> Hi,
>>>
>>> As explained in JDK-8189335, the following example crashes javac with
>>> a NPE in Lower:
>>>
>>> class R {
>>> private class R$1 {}
>>> void f() {
>>> new R$1();
>>> }
>>> }
>>> class R$1 {}
>
> Some precisions related to my laconic explanation about the problem and the fix.
>
> All starts in 'Lower.accessConstructorTag()' when searching for the
> anonymous class 'R$1':
>
> http://hg.openjdk.java.net/jdk/jdk/file/02404e27d356/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#l1238
>
> The top level class 'R$1' (not anonymous) is found and wrongly added
> to 'accessConstrTags'.
>
> Then, when checking the access constructor tags in
> 'Lower.checkAccessConstructorTags()', the 'outermostClass()' of the
> top level class 'R$1' is requested:
>
> http://hg.openjdk.java.net/jdk/jdk/file/02404e27d356/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#l778
>
> 'R$1' being a top level class, its outermost class doesn't exist,
> causing the NPE in 'Lower.makeEmptyClass()'.
Errata: 'R$1' being a top level class, its outermost class definition
('R$1') doesn't exist within 'R', causing the NPE in
'Lower.makeEmptyClass()':
http://hg.openjdk.java.net/jdk/jdk/file/02404e27d356/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#l658
> The fix I suggested two days ago (here under) is then quite
> straightforward. If a class 'R$1' exists but isn't anonymous, it has
> to be skipped and a fresh anonymous class 'R$2' has to be created as
> access constructor tag:
>
> http://hg.openjdk.java.net/jdk/jdk/file/02404e27d356/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#l1239
>
> Nothing seems to be broken and the provided example compiles successfully.
Here is a small variant of the previous patch that makes sure to reuse
the same tag when multiple private constructors are present and 'R$1'
isn't anonymous, for example:
class R {
private class A {}
private class B {}
void f() {
new A();
new B();
}
}
class R$1{}
Any comment or review is welcome!
Cheers,
Bernard
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
@@ -1232,15 +1232,19 @@
ClassSymbol accessConstructorTag() {
ClassSymbol topClass = currentClass.outermostClass();
ModuleSymbol topModle = topClass.packge().modle;
- Name flatname = names.fromString("" + topClass.getQualifiedName() +
- target.syntheticNameChar() +
- "1");
- ClassSymbol ctag = chk.getCompiled(topModle, flatname);
- if (ctag == null)
- ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
- // keep a record of all tags, to verify that all are
generated as required
- accessConstrTags = accessConstrTags.prepend(ctag);
- return ctag;
+ for (int i = 1; ; i++) {
+ Name flatname = names.fromString("" + topClass.getQualifiedName() +
+ target.syntheticNameChar() +
+ i);
+ ClassSymbol ctag = chk.getCompiled(topModle, flatname);
+ if (ctag == null)
+ ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
+ else if (!ctag.isAnonymous())
+ continue;
+ // keep a record of all tags, to verify that all are
generated as required
+ accessConstrTags = accessConstrTags.prepend(ctag);
+ return ctag;
+ }
}
/** Add all required access methods for a private symbol to
enclosing class.
> What do you think (I hope this is clearer)?
>
> Thanks,
> Bernard
>
>
>> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
>> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
>> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
>> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
>> @@ -1236,7 +1236,7 @@
>> target.syntheticNameChar() +
>> "1");
>> ClassSymbol ctag = chk.getCompiled(topModle, flatname);
>> - if (ctag == null)
>> + if (ctag == null || !ctag.isAnonymous())
>> ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
>> // keep a record of all tags, to verify that all are
>> generated as required
>> accessConstrTags = accessConstrTags.prepend(ctag);
More information about the compiler-dev
mailing list