You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ck...@apache.org on 2019/12/31 23:38:53 UTC

[logging-log4j2] branch master updated: LOG4J2-2754: LoaderUtil.getClassLoaders may discover additional loaders

This is an automated email from the ASF dual-hosted git repository.

ckozak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/master by this push:
     new 0db2bbb  LOG4J2-2754: LoaderUtil.getClassLoaders may discover additional loaders
0db2bbb is described below

commit 0db2bbb948dd7e13749efa2b47891678b71f25d3
Author: Carter Kozak <ck...@ckozak.net>
AuthorDate: Tue Dec 31 15:10:15 2019 -0500

    LOG4J2-2754: LoaderUtil.getClassLoaders may discover additional loaders
    
    The utility no longer erroneously returns a result with a null element in some
    environments.
    Also updated loadClass to avoid internally throwing and catching a null
    pointer exception when getThreadContextClassLoader returns null.
---
 .../org/apache/logging/log4j/util/LoaderUtil.java  | 50 +++++++++++-----------
 src/changes/changes.xml                            |  3 ++
 2 files changed, 29 insertions(+), 24 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
index 845b1e0..3eccabd 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
@@ -21,11 +21,9 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Objects;
 
 /**
@@ -149,26 +147,16 @@ public final class LoaderUtil {
     }
 
     public static ClassLoader[] getClassLoaders() {
-        List<ClassLoader> classLoaders = new ArrayList<>();
-        ClassLoader tcl = getThreadContextClassLoader();
-        classLoaders.add(tcl);
-        if (!isForceTccl()) {
-            // Some implementations may use null to represent the bootstrap class loader.
-            ClassLoader current = LoaderUtil.class.getClassLoader();
-            if (current != null && current != tcl) {
-                classLoaders.add(current);
-                ClassLoader parent = current.getParent();
-                while (parent != null && !classLoaders.contains(parent)) {
-                    classLoaders.add(parent);
-                }
-            }
-            ClassLoader parent = tcl == null ? null : tcl.getParent();
-            while (parent != null && !classLoaders.contains(parent)) {
-                classLoaders.add(parent);
-                parent = parent.getParent();
-            }
-            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-            if (!classLoaders.contains(systemClassLoader)) {
+        final Collection<ClassLoader> classLoaders = new LinkedHashSet<>();
+        final ClassLoader tcl = getThreadContextClassLoader();
+        if (tcl != null) {
+            classLoaders.add(tcl);
+        }
+	if (!isForceTccl()) {
+            accumulateClassLoaders(LoaderUtil.class.getClassLoader(), classLoaders);
+            accumulateClassLoaders(tcl == null ? null : tcl.getParent(), classLoaders);
+            final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+            if (systemClassLoader != null) {
                 classLoaders.add(systemClassLoader);
             }
         }
@@ -176,6 +164,17 @@ public final class LoaderUtil {
     }
 
     /**
+     * Adds the provided loader to the loaders collection, and traverses up the tree until either a null
+     * value or a classloader which has already been added is encountered.
+     */
+    private static void accumulateClassLoaders(ClassLoader loader, Collection<ClassLoader> loaders) {
+        // Some implementations may use null to represent the bootstrap class loader.
+        if (loader != null && loaders.add(loader)) {
+            accumulateClassLoaders(loader.getParent(), loaders);
+        }
+    }
+
+    /**
      * Determines if a named Class can be loaded or not.
      *
      * @param className The class name.
@@ -208,10 +207,13 @@ public final class LoaderUtil {
             return Class.forName(className);
         }
         try {
-            return getThreadContextClassLoader().loadClass(className);
+            ClassLoader tccl = getThreadContextClassLoader();
+            if (tccl != null) {
+                return tccl.loadClass(className);
+            }
         } catch (final Throwable ignored) {
-            return Class.forName(className);
         }
+        return Class.forName(className);
     }
 
     /**
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3bc396f..d1175e1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -196,6 +196,9 @@
       <action issue="LOG4J2-2752" dev="ckozak" type="fix">
         MutableLogEvent and RingBufferLogEvent avoid StringBuffer and parameter array allocation unless reusable messages are used.
       </action>
+      <action issue="LOG4J2-2754" dev="ckozak" type="fix">
+        LoaderUtil.getClassLoaders may discover additional loaders and no longer erroneously returns a result with a null element in some environments.
+      </action>
     </release>
     <release version="2.13.0" date="2019-12-11" description="GA Release 2.13.0">
       <action issue="LOG4J2-2058" dev="rgoers" type="fix">