4477b4d7101d4f71c89e32561e5c4f1b566c169b LOG4J2-1457 - fix class loader deadlock diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java index a152ea7..6acf3b8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java @@ -207,7 +207,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement for (final PluginType type : plugins.values()) { try { // Cause the class to be initialized if it isn't already. - Loader.initializeClass(type.getPluginClass().getName(), type.getPluginClass().getClassLoader()); + Loader.initializeClass(type.getPluginClass().getName(), true, type.getPluginClass().getClassLoader()); } catch (final Exception e) { LOGGER.error("Unable to initialize {} due to {}", type.getPluginClass().getName(), e.getClass() .getSimpleName(), e); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 28f8e56..6133d7a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -484,7 +484,7 @@ public class ThrowableProxy implements Serializable { Class clazz; if (lastLoader != null) { try { - clazz = Loader.initializeClass(className, lastLoader); + clazz = Loader.initializeClass(className, false, lastLoader); if (clazz != null) { return clazz; } @@ -504,7 +504,7 @@ public class ThrowableProxy implements Serializable { private Class initializeClass(final String className) { try { - return Loader.initializeClass(className, this.getClass().getClassLoader()); + return Loader.initializeClass(className, false, this.getClass().getClassLoader()); } catch (final ClassNotFoundException ignore) { return null; } catch (final NoClassDefFoundError ignore) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java index bb35752..6b4344c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java @@ -232,13 +232,14 @@ public final class Loader { * Loads and initializes a named Class using a given ClassLoader. * * @param className The class name. + * @param initialize Whether the class must be initialized * @param loader The class loader. * @return The class. * @throws ClassNotFoundException if the class could not be found. */ - public static Class initializeClass(final String className, final ClassLoader loader) + public static Class initializeClass(final String className, boolean initialize, final ClassLoader loader) throws ClassNotFoundException { - return Class.forName(className, true, loader); + return Class.forName(className, initialize, loader); } /** diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlock.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlock.java new file mode 100644 index 0000000..ea8318f --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlock.java @@ -0,0 +1,32 @@ +/* + * 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.logging.log4j.core.async; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +class AsyncLoggerClassLoadDeadlock { + static { + Logger log = LogManager.getLogger("com.foo.bar.deadlock"); + Exception e = new Exception(); + // the key to reproducing the problem is to fill up the ring buffer so that + // log.info call will block on ring buffer as well + for (int i = 0; i < AsyncLoggerClassLoadDeadockTest.RING_BUFFER_SIZE * 2; ++i) { + log.info("clinit", e); + } + } +} \ No newline at end of file diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadockTest.java new file mode 100644 index 0000000..3aa3c89 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadockTest.java @@ -0,0 +1,44 @@ +/* + * 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.logging.log4j.core.async; + +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test class loading deadlock condition from the LOG4J2-1457 + * + */ +public class AsyncLoggerClassLoadDeadockTest { + + static final int RING_BUFFER_SIZE = 128; + + @BeforeClass + public static void beforeClass() { + System.setProperty("Log4jContextSelector","org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); + System.setProperty("AsyncLogger.RingBufferSize", String.valueOf(RING_BUFFER_SIZE)); + System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, + "AsyncLoggerConsoleTest.xml"); + } + + @Test(timeout=30000) + public void testClassLoaderDeadlock() throws Exception { + //touch the class so static init will be called + AsyncLoggerClassLoadDeadlock temp = new AsyncLoggerClassLoadDeadlock(); + } +} diff --git a/log4j-core/src/test/resources/AsyncLoggerConsoleTest.xml b/log4j-core/src/test/resources/AsyncLoggerConsoleTest.xml new file mode 100644 index 0000000..61efd8c --- /dev/null +++ b/log4j-core/src/test/resources/AsyncLoggerConsoleTest.xml @@ -0,0 +1,16 @@ + + + + + + %xEx{0} + + + + + + + + + + \ No newline at end of file