Repository navigation
Closed
Description
GWT version: 2.10
Browser (with version): Chrome (irrelevant)
Operating System: Windows 10
Description
If a configuration property is defined but not set, the compiler runs into a NPE which does not provide enough information to debug the issue. This may happen for instance when a project depends on gwt-safehtml but does not set org.gwtproject.safecss.ForceCheckValidStyles.
Details
[ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:111)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:276)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
at com.google.gwt.dev.jjs.ast.JBinaryOperation.traverse(JBinaryOperation.java:87)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
at com.google.gwt.dev.jjs.ast.JBinaryOperation.traverse(JBinaryOperation.java:89)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
at com.google.gwt.dev.jjs.ast.JExpressionStatement.traverse(JExpressionStatement.java:42)
at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:786)
at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:778)
at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.traverse(JModVisitor.java:169)
at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemoveImmutable(JModVisitor.java:336)
at com.google.gwt.dev.jjs.ast.JClassType.traverse(JClassType.java:147)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.ast.JProgram.visitModuleTypes(JProgram.java:1284)
at com.google.gwt.dev.jjs.ast.JProgram.traverse(JProgram.java:1249)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
at com.google.gwt.dev.jjs.impl.ResolvePermutationDependentValues.execImpl(ResolvePermutationDependentValues.java:163)
at com.google.gwt.dev.jjs.impl.ResolvePermutationDependentValues.exec(ResolvePermutationDependentValues.java:113)
at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:333)
at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:272)
at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.NullPointerException
at com.google.gwt.thirdparty.guava.common.base.Preconditions.checkNotNull(Preconditions.java:212)
at com.google.gwt.thirdparty.guava.common.base.Joiner.toString(Joiner.java:447)
at com.google.gwt.thirdparty.guava.common.base.Joiner.appendTo(Joiner.java:110)
at com.google.gwt.thirdparty.guava.common.base.Joiner.appendTo(Joiner.java:154)
at com.google.gwt.thirdparty.guava.common.base.Joiner.join(Joiner.java:197)
at com.google.gwt.thirdparty.guava.common.base.Joiner.join(Joiner.java:186)
at com.google.gwt.dev.jjs.impl.ResolvePermutationDependentValues$ValueReplacer.propertyValueExpression(ResolvePermutationDependentValues.java:79)
at com.google.gwt.dev.jjs.impl.ResolvePermutationDependentValues$ValueReplacer.endVisit(ResolvePermutationDependentValues.java:73)
at com.google.gwt.dev.jjs.ast.JPermutationDependentValue.traverse(JPermutationDependentValue.java:112)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
Steps to reproduce
See above, currently I don't have a minimal example.
Known workarounds
- Set all configuration properties that are defined. In case the project is using
gwt-safehtmldependency, that includes
<set-configuration-property name="org.gwtproject.safecss.ForceCheckValidStyles" value="false"/> - or use the patch proposed in Report the name of missing property on compile errrorΒ #9807 to get a better stacktrace
Links to further discussions
https://app.gitter.im/#/room/#gwtproject_gwt:gitter.im/$55NBoLsN4ipWnzdOjEuwp79aX5dL5CQ0f7Pi4nlZZQw
Metadata
Metadata
Assignees
Labels
No labels
Activity
niloc132 commentedon Mar 15, 2023
I've been playing with this, and there are a few other bugs in the implementation that we're stuck with. First off, the
<source info not available>comes from the brokenToStringGenerationVisitor#visit(com.google.gwt.dev.jjs.ast.JPermutationDependentValue, com.google.gwt.dev.jjs.ast.Context)implementation, it tries to emit aGWT.getProperty(...)line, but no such method exists (or ever existed) - my hunch is that before it was implemented with System.getProperty, it was going to be GWT.getProperty, and have the same contract - take a string and an optional default.So, the question is, what do we want this to do, what was the original intent, and how worried are we about adding new unexpected behavior or breakage?
UnifyAst/UnifyAstTest
UnifyAstTest.testGetProperty_error_undefinedPropertyshows that if the property doesnt exist, compile will failtestGetPropertyWithDefault_success_undefinedhowever expands to show that if the property doesn't exist, but a default is specified, the compile should not fail.UnifyAstTest.testGetProperty_error_multivaluedshows that if the property exists and is multivalued, even if there is a default, compile will fail.JPermutationDependentValue/SystemTest
SystemTest.testGetProperty()comes with a .gwt.xml file to set a few properties, inEmulSuite.gwt.xml. A single config prop is defined there, with a value set on it.SystemGetPropertyTest
So it seems that only a non-multi-value config property could be defined but never set - do we want that to behave as though it was set to null? That is,
null) passed to System.getProperty (validate in UnifyAst)?jnehlmeier commentedon Mar 15, 2023
@niloc132 As far as I can see there are non-multi-valued configuration properties in GWT that are never set. However in these cases the code always provides a default when asking for that possibly not initialized configuration property.
Some examples are:
For gwt-safehtml the property in question has been newly introduced but the code fails to provide a default value when checking the property value. So IMHO it is a bug in gwt-safehtml and we should not change anything in GWT compiler except providing a good error message and adding a test for that scenario.
Of course one could argue that the code in GWT SDK always provides a default value because it knows it would fail otherwise. I am pretty sure some code in GWT SDK would have looked the same as in gwt-safehtml if it would not fail (gwt-safehtml just does a
getProperty(..) != nullcheck). But I feel like we should not be in a situation where the code does not care about the actual value, even if the property is just an on/off toggle. That is why I would vote for keeping the current behavior and fix gwt-safehtml instead.jnehlmeier commentedon Mar 15, 2023
Meh...I used to
org.gwtproject...prefixed name for the search. The property isn't new and GWT SDK should have the same issue as it also just does a!= null, seegwt/user/src/com/google/gwt/safecss/shared/SafeStylesHostedModeUtils.java
Line 298 in 7c96744
The reason why it works in GWT SDK but not in gwt-safehtml is that GWT SDK provides a super-source version that does not check the property at all. See:
gwt/user/super/com/google/gwt/safecss/super/com/google/gwt/safecss/shared/SafeStylesHostedModeUtils.java
Line 27 in 7c96744
gwt-safehtml does not have that super-sourced version.
niloc132 commentedon Mar 15, 2023
I certainly agree that the property isn't very helpful if it is not set, and definitely agree we should fix gwt-safehtml regardless of what we do here.
However, I think it is also reasonable to expand the behavior here a bit. Specific reasons:
@define, it seems you can't have a--define, but you will still get null or be able to use your default value, and the@definedoes not have to be in the same module...).Add-on to respond to your second reply: the method in the org.gwtproject.safehtml repo isn't actually called, but GWT still tries to "fix it" in SDM when it rewrites the magic method without any dead code elimination. Not using the code is no protection against the code violating the unwritten rules (so let's make the rules make sense?).
So I'm not just asking "what was this meant to be, in the eyes of the original authors", but "what should it be, to make sense to future users". I think a reasonable case can be made for "it doesnt make sense as is, fails very poorly, and might not have been fully thought out, so maybe we can make some guarantees a bit stronger". If there is a compelling reason I'm not seeing for supporting returning null when no value was defined and no default provided (as j2cl and the jvm will do), then I can remove that extra bit from my patch and still fix the rest of this.
zbynek commentedon Mar 15, 2023
@niloc132 do you have a patch for this? Should I close the draft PR?
Proposal with enforcing a default sounds good.
niloc132 commentedon Mar 15, 2023
@zbynek yes go ahead and close yours, I'll build off it and propose something new. Want to look at the gwt-safehtml side of things instead?
niloc132 commentedon Mar 25, 2023
@zbynek I'm trying to reproduce your initial example with stock GWT to ensure that the fix we've made makes sense, because there are a few parts that don't make sense.
It turns out that the
ResolvePermutationDependentValues.ValueReplacerextendsJVisitor, and callsValueReplacer.accept(program), which has a try/catch in it (and not just forRuntimeException, but forThrowableitself):gwt/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
Lines 121 to 132 in 7c96744
I tried to modify the Hello sample to reproduce this, by just adding a configuration property to the .gwt.xml without a value, and using it with System.getProperty. Here's the full error I got - note that it looks like your error almost exactly, until the NPE's stack trace ends:
At the very least I would expect to see the
Not all permutation were compiled , completed (0/1)sub-message, and am surprised that it is missing - or is it possible that the<source info not available>were useless enough that you left the rest out? If so, simply fixing theToStringGenerationVisitorwill correct that.Did your added try/catch fix the issue in your own app? And did your log end as in the ticket, or did it have the extra (and useless)
<source info not available>on it?zbynek commentedon Mar 25, 2023
yes, equivalent of
was there in my case before the fix. With the try-catch I was able to get from
to
Fix error reporting for System.getProperty magic method nodes (#9812)
zbynek commentedon Feb 5, 2025
@jnehlmeier
Would it be acceptable for you if the behavior changed and
System.getProperty()just returned null with a warning? (see #10013 for more context)jnehlmeier commentedon Feb 12, 2025
@zbynek Yes. I am generally fine with changes that better match the behavior described in the JRE JavaDoc. It results in less surprises. In plain Java the method returns
nullif it cannot find the property and no default is given, so GWT should do the same. The only difference with GWT is that GWT has different ways of providing a property value.zbynek commentedon Feb 12, 2025
Thanks!