apache / apache/logging-log4j2

AbstractConfiguration - Potential NPE on AsyncLoggerConfigDisruptor

Open
#3,156 1 comment 0 reactions 0 assignees View on GitHub
waiting-for-maintainer
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.