[ 
https://issues.apache.org/jira/browse/GROOVY-12303?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18109575#comment-18109575
 ] 

ASF GitHub Bot commented on GROOVY-12303:
-----------------------------------------

github-advanced-security[bot] commented on code in PR #2834:
URL: https://github.com/apache/groovy/pull/2834#discussion_r3888350210


##########
src/main/java/org/apache/groovy/internal/util/ClassFiles.java:
##########
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.internal.util;
+
+import org.codehaus.groovy.ast.decompiled.AsmDecompiler;
+import org.codehaus.groovy.ast.decompiled.ClassStub;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Locates a {@code .class} resource and tests whether it decompiles to the
+ * requested binary name, using {@link AsmDecompiler#parseClass(URL)}.
+ * <p>
+ * {@link groovy.lang.GroovyClassLoader} and
+ * {@link org.codehaus.groovy.control.ClassNodeResolver} both use
+ * {@link #isBytecodeNameMatch} so the bytecode-name check is one comparison
+ * ({@link ClassStub#getClassName()}). {@link AsmDecompiler} caches stubs by
+ * URI, so an ASM-on resolve that later calls {@code loadClass} does not parse
+ * the same file twice.
+ *
+ * @since 6.0.0
+ */
+public final class ClassFiles {
+    private ClassFiles() {
+    }
+
+    /**
+     * Resource path of {@code binaryName}, e.g. {@code java.lang.String} to
+     * {@code java/lang/String.class}.
+     */
+    public static String resourcePath(final String binaryName) {
+        return binaryName.replace('.', '/') + ".class";
+    }
+
+    /**
+     * {@code loader.getResource} of {@link #resourcePath(String)}.
+     */
+    public static URL findResource(final ClassLoader loader, final String 
binaryName) {
+        return loader.getResource(resourcePath(binaryName));

Review Comment:
   ## CodeQL / Uncontrolled data used in path expression
   
   This path depends on a [user-provided value](1).
   
   [Show more 
details](https://github.com/apache/groovy/security/code-scanning/277)





> ClassNodeResolver: NoClassDefFoundError during class-loader lookup aborts 
> resolution
> ------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12303
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12303
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Daniel Sun
>            Priority: Major
>
> When class-loader lookup is used ({{{}asmResolving{}}} off, or the type 
> exists only in memory), {{ClassNodeResolver}} calls 
> {{{}GroovyClassLoader.loadClass{}}}. If the requested class *exists* but 
> cannot be linked (missing superclass or interface), the JVM throws 
> {{{}NoClassDefFoundError{}}}.
> That error used to escape resolution. Compilation aborted with an {{Error}} 
> that named the {*}missing dependency{*}, not the type being resolved. 
> {{resolveName}} could also cache the name as a miss ({{{}NO_CLASS{}}}), so a 
> later successful compile of the dependency would not be retried.
> A TODO in {{findByClassLoading}} has noted this since the 2012 split out of 
> {{{}ResolveVisitor{}}}.
> h3. Expected
>  * If bytecode for the requested name is still on the class path, decompile 
> it (ASM does not link) and continue.
>  * Else if a groovy source of the same name is available, add it to the 
> compilation queue.
>  * Else if a {{.class}} resource exists for that path but declares a 
> different binary name (JVM {{defineClass}} name check; also case-insensitive 
> filesystems), treat the lookup as a miss. Detect this from the bytecode name, 
> not from {{NoClassDefFoundError}} text (HotSpot's {{wrong name}} phrase is 
> English-only; OpenJ9 does not use it).
>  * Otherwise rethrow {{NoClassDefFoundError}} with the looked-up name in the 
> message, and do not cache {{{}NO_CLASS{}}}.
> h3. Actual
> {{NoClassDefFoundError}} propagated out of 
> {{{}ClassNodeResolver.findByClassLoading{}}}.
> h3. Reproducer
> Put {{HasDep.class}} (extends a type that is not loadable) on the class path, 
> disable ASM resolving, and compile:
> {code:groovy}
> HasDep x = null
> {code}
> This fails with {{NoClassDefFoundError}} for the missing super-type instead 
> of resolving {{{}HasDep{}}}.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to