google / closure-compiler

A JavaScript checker and optimizer.
https://developers.google.com/closure/compiler/
Apache License 2.0
7.4k stars 1.15k forks source link

java.lang.IllegalStateException: Object method calls can not be decomposed #3592

Open luisggpina opened 4 years ago

luisggpina commented 4 years ago

Input for SIMPLE_OPTIMIZATIONS:

throw (a_0 <= (a_0 => null)[(() => 762)(++ a_0)]())

Error output:

java.lang.IllegalStateException: Object method calls can not be decomposed.
    at com.google.common.base.Preconditions.checkState(Preconditions.java:508)
    at com.google.javascript.jscomp.ExpressionDecomposer.exposeExpression(ExpressionDecomposer.java:218)
    at com.google.javascript.jscomp.ExpressionDecomposer.exposeExpression(ExpressionDecomposer.java:136)
    at com.google.javascript.jscomp.ExpressionDecomposer.maybeExposeExpression(ExpressionDecomposer.java:110)
    at com.google.javascript.jscomp.FunctionInjector$CallSiteType$6.prepare(FunctionInjector.java:520)
    at com.google.javascript.jscomp.FunctionInjector.maybePrepareCall(FunctionInjector.java:593)
    at com.google.javascript.jscomp.InlineFunctions.decomposeExpressions(InlineFunctions.java:794)
    at com.google.javascript.jscomp.InlineFunctions.process(InlineFunctions.java:152)
    at com.google.javascript.jscomp.PhaseOptimizer$NamedPass.process(PhaseOptimizer.java:317)
    at com.google.javascript.jscomp.PhaseOptimizer$Loop.process(PhaseOptimizer.java:462)
    at com.google.javascript.jscomp.PhaseOptimizer.process(PhaseOptimizer.java:232)
    at com.google.javascript.jscomp.Compiler.performOptimizations(Compiler.java:2417)
    at com.google.javascript.jscomp.Compiler.lambda$stage2Passes$1(Compiler.java:802)
    at com.google.javascript.jscomp.CompilerExecutor.runInCompilerThread(CompilerExecutor.java:129)
    at com.google.javascript.jscomp.Compiler.runInCompilerThread(Compiler.java:829)
    at com.google.javascript.jscomp.Compiler.stage2Passes(Compiler.java:799)
    at com.google.javascript.jscomp.Compiler.compileModules(Compiler.java:744)
    at com.google.javascript.jscomp.debugger.CompilationServlet.service(CompilationServlet.java:99)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:848)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1772)
    at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:582)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at com.google.apphosting.runtime.jetty9.ParseBlobUploadHandler.handle(ParseBlobUploadHandler.java:119)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1182)
    at com.google.apphosting.runtime.jetty9.AppEngineWebAppContext.doHandle(AppEngineWebAppContext.java:187)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at com.google.apphosting.runtime.jetty9.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:293)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at org.eclipse.jetty.server.Server.handle(Server.java:539)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:333)
    at com.google.apphosting.runtime.jetty9.RpcConnection.handle(RpcConnection.java:213)
    at com.google.apphosting.runtime.jetty9.RpcConnector.serviceRequest(RpcConnector.java:81)
    at com.google.apphosting.runtime.jetty9.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchServletRequest(JavaRuntime.java:757)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchRequest(JavaRuntime.java:720)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:690)
    at com.google.apphosting.runtime.JavaRuntime$NullSandboxRequestRunnable.run(JavaRuntime.java:882)
    at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:270)
    at java.lang.Thread.run(Thread.java:748)

Reproduce URL: https://closure-compiler-debugger.appspot.com/#input0%3Dthrow%2520(a_0%2520%253C%253D%2520(a_0%2520%253D%253E%2520null)%255B(()%2520%253D%253E%2520762)(%252B%252B%2520a_0)%255D())%250A%26input1%26conformanceConfig%26externs%26refasterjs-template%26includeDefaultExterns%3Dtrue%26ALIAS_ALL_STRINGS%3Dtrue%26AMBIGUATE_PROPERTIES%3Dtrue%26COALESCE_VARIABLE_NAMES%3Dtrue%26COLLAPSE_VARIABLE_DECLARATIONS%3Dtrue%26COLLAPSE_ANONYMOUS_FUNCTIONS%3Dtrue%26COLLAPSE_PROPERTIES%3Dtrue%26COLLAPSE_OBJECT_LITERALS%3Dtrue%26COMPUTE_FUNCTION_SIDE_EFFECTS%3Dtrue%26CONVERT_TO_DOTTED_PROPERTIES%3Dtrue%26CROSS_CHUNK_CODE_MOTION%3Dtrue%26CROSS_CHUNK_METHOD_MOTION%3Dtrue%26DEAD_ASSIGNMENT_ELIMINATION%3Dtrue%26DISAMBIGUATE_PROPERTIES%3Dtrue%26EXTRACT_PROTOTYPE_MEMBER_DECLARATIONS%3Dtrue%26FOLD_CONSTANTS%3Dtrue%26INLINE_CONSTANTS%3Dtrue%26INLINE_FUNCTIONS%3Dtrue%26INLINE_PROPERTIES%3Dtrue%26INLINE_VARIABLES%3Dtrue%26LABEL_RENAMING%3Dtrue%26OPTIMIZE_CALLS%3Dtrue%26REMOVE_ABSTRACT_METHODS%3Dtrue%26REMOVE_DEAD_CODE%3Dtrue%26REMOVE_UNUSED_CLASS_PROPERTIES%3Dtrue%26REMOVE_UNUSED_PROTOTYPE_PROPERTIES%3Dtrue%26REMOVE_UNUSED_PROTOTYPE_PROPERTIES_IN_EXTERNS%3Dtrue%26REMOVE_UNUSED_VARIABLES%3Dtrue%26REWRITE_FUNCTION_EXPRESSIONS%3Dtrue%26SMART_NAME_REMOVAL%3Dtrue%26USE_TYPES_FOR_LOCAL_OPTIMIZATION%3Dtrue%26VARIABLE_RENAMING%3Dtrue%26PROPERTY_RENAMING%3Dtrue%26MOVE_FUNCTION_DECLARATIONS%3Dtrue%26SYNTHETIC_BLOCK_MARKER%3Dtrue%26CHROME_PASS%3Dtrue%26PRESERVE_TYPE_ANNOTATIONS%3Dtrue%26PRETTY_PRINT%3Dtrue

This error can also be reproduced with the following input:

() => (a_0(this[(() => (762))(++ a_0)]()))

Passed to the following class:

import com.google.javascript.jscomp.CompilationLevel;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.Result;
import com.google.javascript.jscomp.SourceFile;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import static org.junit.Assume.assumeTrue;

public class Compiler {

    static {
        java.util.logging.LogManager.getLogManager().reset();
    }

    // Compiler, options, and predefined JS environment
    private com.google.javascript.jscomp.Compiler compiler = new com.google.javascript.jscomp.Compiler(new PrintStream(new ByteArrayOutputStream(), false));
    private CompilerOptions options = new CompilerOptions();
    private SourceFile externs = SourceFile.fromCode("externs", "");

    public void initCompiler() {
        // Don't use threads
        compiler.disableThreads();
        // Don't print things
        options.setPrintConfig(false);
        // Enable all safe optimizations
        CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
    }

    /** Compiles an input and returns its result */
    private Result compile(SourceFile input) {
        return compiler.compile(externs, input, options);
    }

    public static void main(String[] args) {
        Compiler t = new Compiler();
        t.compiler = new com.google.javascript.jscomp.Compiler(System.out);
        t.initCompiler();
        t.compiler.compile(t.externs, SourceFile.fromFile(args[0]), t.options);
    }
}

Compiler Options (default options)

aggressiveFusion=false
 aliasableStrings=[]
 aliasAllStrings=false
 aliasHandler=com.google.javascript.jscomp.CompilerOptions$NullAliasTransformationHandler@5bb21b69
 aliasStringsBlacklist=
 allowHotswapReplaceScript=false
 ambiguateProperties=false
 angularPass=false
 anonymousFunctionNaming=OFF
 assumeClosuresOnlyCaptureReferences=false
 assumeGettersArePure=true
 assumeStrictThis=false
 browserResolverPrefixReplacements={}
 brokenClosureRequiresLevel=ERROR
 checkDeterminism=false
 checkGlobalNamesLevel=OFF
 checkGlobalThisLevel=OFF
 checkMissingGetCssNameLevel=OFF
 checksOnly=false
 checkSuspiciousCode=false
 checkSymbols=false
 checkTypes=false
 closurePass=true
 coalesceVariableNames=true
 collapseAnonymousFunctions=false
 collapseObjectLiterals=true
 collapseProperties=NONE
 collapseVariableDeclarations=true
 colorizeErrorOutput=false
 computeFunctionSideEffects=false
 conformanceConfigs=[]
 conformanceRemoveRegexFromPath=Optional.of(^((.*/)?google3/)?((^/)?(blaze|bazel)-out/[^/]+/bin/)?)
 continueAfterErrors=false
 convertToDottedProperties=true
 crossChunkCodeMotion=false
 crossChunkCodeMotionNoStubMethods=false
 crossChunkMethodMotion=false
 dartPass=false
 deadAssignmentElimination=true
 declaredGlobalExternsOnWindow=true
 defineReplacements={}
 dependencyOptions=DependencyOptions{mode=SORT_ONLY
 entryPoints=[]}
 devirtualizeMethods=false
 devMode=OFF
 disambiguatePrivateProperties=false
 disambiguateProperties=false
 enableModuleRewriting=true
 enforceAccessControlCodingConventions=false
 environment=BROWSER
 errorFormat=SINGLELINE
 es6ModuleTranspilation=COMPILE
 exportLocalPropertyDefinitions=false
 exportTestFunctions=false
 externExports=false
 extractPrototypeMemberDeclarations=OFF
 extraSmartNameRemoval=false
 filesToPrintAfterEachPassRegexList=[]
 flowSensitiveInlineVariables=false
 foldConstants=true
 forceLibraryInjection=[]
 gatherCssNames=false
 generateExports=false
 generatePseudoNames=false
 generateTypedExterns=false
 idGenerators={}
 incrementalCheckMode=OFF
 inferConsts=true
 inferTypes=false
 inlineConstantVars=false
 inlineFunctionsLevel=LOCAL_ONLY
 inlineGetters=false
 inlineLocalVariables=true
 inlineProperties=false
 inlineVariables=false
 inputDelimiter=// Input %num%
 inputSourceMaps={}
 instrumentForCoverage=false
 instrumentForCoverageOnly=false
 instrumentBranchCoverage=false
 isolatePolyfills=false
 j2clMinifierEnabled=true
 j2clPassMode=AUTO
 labelRenaming=true
 languageIn=ECMASCRIPT_2019
 languageOutIsDefaultStrict=Optional.absent()
 legacyCodeCompile=false
 lineBreak=false
 lineLengthThreshold=500
 markAsCompiled=false
 maxFunctionSizeAfterInlining=-1
 moduleRoots=[./]
 chunksToPrintAfterEachPassRegexList=[]
 moveFunctionDeclarations=false
 nameGenerator=com.google.javascript.jscomp.DefaultNameGenerator@32464a14
 optimizeArgumentsArray=true
 optimizeCalls=false
 outputFeatureSet=Optional.absent()
 outputJs=NORMAL
 outputJsStringUsage=false
 parentChunkCanSeeSymbolsDeclaredInChildren=false
 parseJsDocDocumentation=TYPES_ONLY
 pathEscaper=ESCAPE
 polymerExportPolicy=LEGACY
 preferLineBreakAtEndOfFile=false
 preferSingleQuotes=false
 preferStableNames=false
 preserveDetailedSourceInfo=false
 preserveGoogProvidesAndRequires=false
 preserveTypeAnnotations=false
 prettyPrint=false
 preventLibraryInjection=false
 printConfig=true
 printInputDelimiter=false
 printSourceAfterEachPass=false
 processCommonJSModules=false
 propertyInvalidationErrors={}
 propertyRenaming=OFF
 protectHiddenSideEffects=true
 quoteKeywordProperties=false
 removeAbstractMethods=false
 removeClosureAsserts=false
 removeJ2clAsserts=true
 removeDeadCode=true
 removeUnusedClassProperties=false
 removeUnusedConstructorProperties=false
 removeUnusedLocalVars=true
 removeUnusedPrototypeProperties=false
 removeUnusedPrototypePropertiesInExterns=false
 removeUnusedVars=false
 renamePrefixNamespaceAssumeCrossChunkNames=false
 replaceIdGenerators=false
 replaceMessagesWithChromeI18n=false
 replaceStringsFunctionDescriptions=[]
 replaceStringsPlaceholderToken=
 replaceStringsReservedStrings=[]
 reserveRawExports=false
 rewriteFunctionExpressions=false
 rewritePolyfills=false
 runtimeTypeCheck=false
 shadowVariables=true
 rewriteModulesBeforeTypechecking=true
 skipNonTranspilationPasses=false
 smartNameRemoval=false
 sourceMapDetailLevel=ALL
 sourceMapFormat=DEFAULT
 sourceMapLocationMappings=[]
 stripNamePrefixes=[]
 stripNameSuffixes=[]
 stripTypePrefixes=[]
 stripTypes=[]
 summaryDetailLevel=1
 tracer=OFF
 transformAMDToCJSModules=false
 trustedStrings=false
 tweakProcessing=OFF
 tweakReplacements={}
 emitUseStrict=Optional.absent()
 useTypesForLocalOptimization=false
 variableRenaming=LOCAL
 warningsGuard=DiagnosticGroup<checkVars>(OFF)
 DiagnosticGroup<es5Strict>(ERROR)
 DiagnosticGroup<boundedGenerics>(OFF)
 com.google.javascript.jscomp.DiagnosticGroup@4e4aea35(OFF)
 wrapGoogModulesForWhitespaceOnly=true

Affects: v20200405

rrdelaney commented 4 years ago

What is your use-case here? I don't think this JS would ever be run in a browser.

luisggpina commented 4 years ago

We found this crashing input using a fuzzing tool that generates inputs automatically which may result in a crash. In this case, our tool found such an input: A piece of JavaScript that results in the compiler crashing with a IllegalStateException.

Our tool only generates valid JavaScript (as per the JavaScript grammar), so this is a bug as the compiler should reject the input instead of crashing.