apache / apache/logging-log4j2
AbstractConfiguration - Potential NPE on AsyncLoggerConfigDisruptor
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 1.7k
- Avg merge
- 21h 30m
- Merged PRs (30d)
- 27
Description
AbstractConfiguration (Log4j 2.24.1)
In `AbstractConfiguration` the field `asyncLoggerConfigDisruptor`is lazily initialized.
```
private AsyncLoggerConfigDisruptor asyncLoggerConfigDisruptor;
public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() {
// lazily instantiate only when requested by AsyncLoggers:
// loading AsyncLoggerConfigDisruptor requires LMAX Disruptor jar on classpath
if (asyncLoggerConfigDisruptor == null) {
asyncLoggerConfigDisruptor = new AsyncLoggerConfigDisruptor(asyncWaitStrategyFactory);
}
return asyncLoggerConfigDisruptor;
}
```
The method `getAsyncLoggerConfigDelegate()` would normally be called in the constructor of `AsyncLoggerConfig(...)`:
```
protected AsyncLoggerConfig(
final String name,
final List appenders,
final Filter filter,
final Level level,
final boolean additive,
final Property[] properties,
final Configuration config,
final boolean includeLocation) {
super(name, appenders, filter, level, additive, properties, config, includeLocation);
delegate = config.getAsyncLoggerConfigDelegate();
delegate.setLogEventFactory(getLogEventFactory());
}
```
Here an assumption is being made that `Configuration#getAsyncLoggerConfigDelegate()` will not return `null` and properly initialiize the field, but since `Configuration` is an interface that can be implemented by anyone, anything is possible. :) It also assumes that the `AsyncLoggerConfig` has been created with *this* `AbstractConfiguration` which may not be a given if created somewhere else and just added with `Configuration#addLogger(String, LoggerConfig)`.
This also implies that the `AbstractConfiguration` has a certain "knowledge" of the inner workings of the `AsyncLoggerConfig` which I believe violates some principle of encapsulation. :)
The potential NPE comes up in the `AbstractConfiguration#start()` and `AbstractConfiguration#stop()` methods where it is assumed that the `asyncLoggerConfigDisruptor` has already been lazily initialized to a non-`null` value.
`start()`
```
if (hasAsyncLoggers()) {
asyncLoggerConfigDisruptor.start();
}
```
`stop()`
```
if (hasAsyncLoggers()) {
LOGGER.trace("{} stopping AsyncLoggerConfigDisruptor.", cls);
asyncLoggerConfigDisruptor.stop(timeout, timeUnit);
}
```
A potential fix is *either* doing a simple null-check or maybe adding a protected API (since you can't call `start()` on the `AsyncLoggerConfigDelegate`:
```
@Override
public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() {
return getAsyncLoggerConfigDisruptor();
}
protected AsyncLoggerConfigDisruptor getAsyncLoggerConfigDisruptor() {
// lazily instantiate only when requested by AsyncLoggers:
// loading AsyncLoggerConfigDisruptor requires LMAX Disruptor jar on classpath
if (asyncLoggerConfigDisruptor == null) {
asyncLoggerConfigDisruptor = new AsyncLoggerConfigDisruptor(asyncWaitStrategyFactory);
}
return asyncLoggerConfigDisruptor;
}
public void start() {
...
if (hasAsyncLoggers()) {
getAsyncLoggerConfigDisruptor().start();
}
...
}
public void stop() {
...
if (hasAsyncLoggers()) {
getAsyncLoggerConfigDisruptor().stop(timeout, timeUnit);
}
...
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.