fix: close streams in LoggerContextAdmin.setConfigLocationUri - #4218
fix: close streams in LoggerContextAdmin.setConfigLocationUri#4218SebTardif wants to merge 3 commits into
Conversation
ConfigurationSource(InputStream, File/URL) leaves stream ownership with the caller. Buffer configuration bytes into a Source-backed ConfigurationSource and close the FileInputStream/URL stream before ConfigurationFactory runs so failed or successful JMX reconfigure paths do not leak descriptors. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
ramanathan1504
left a comment
There was a problem hiding this comment.
@SebTardif thanks for this one, the missing close() is real, I could follow it in the code.
I pulled it down and ran it locally (./mvnw test -pl log4j-core,log4j-core-test -am -Dtest=LoggerContextAdminSetConfigLocationUriTest), two things came up:
-
I reverted
LoggerContextAdmin.javaback to2.xand kept your tests, all 3 still pass. They only check the config loads, not that anything is closed. Can you make at least one of them fail without the production change? -
The buffering looks like it changes more than the close.
ConfigurationSource.resetInputStream()returns early whendata != nulland gives back the same bytes, and that is the methodreconfigure()uses.getFile()is still not null soinitializeWatchersstill registers the file watcher, so a config set over JMX withmonitorIntervalwould keep seeing the file change but keep loading the old config. Same idea as your #4125 — can you keep the stream-backed source and just widen the try-with-resources around thegetConfigurationcall? Smaller diff and no behaviour change.
One more, XmlConfiguration, JsonConfiguration and PropertiesConfigurationFactory all close getInputStream() in a finally already, so which path is the one that actually leaks? Good to have it written down so the changelog says the right thing.
Let me know when it's updated and I will review it again.
Address review on apache#4218: - Drop full buffering so ConfigurationSource remains stream/file backed (monitorInterval / resetInputStream still re-read the file). - Close the caller-owned InputStream with try-with-resources around getConfiguration and start. - Add a regression test that installs a factory which never consumes the stream; red fails on open FD count without the try-with-resources, green closes cleanly. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
@ramanathan1504 thanks for the detailed review — updated.
Ready for another look. |
What Problem This Solves
LoggerContextAdmin.setConfigLocationUriopens aFileInputStreamor URL stream and buildsConfigurationSource(InputStream, File/URL). That constructor documents that the caller owns the stream.Built-in factories (
XmlConfiguration,JsonConfiguration,PropertiesConfigurationFactory) closegetInputStream()when they consume it. That is factory-side cleanup, not a substitute for the caller contract: if a factory path never reads the stream (or returns before consuming it), the descriptor can leak. Same ownership theme as #4127.Evidence
Leak path (why close is still needed)
Xml/JSON/properties factories close streams they consume. The remaining risk is caller ownership: open stream → hand to
ConfigurationSource→ factory that never callsgetInputStream()(or fails before consume) → stream stays open. Defensive fix is try-with-resources on the caller side while keeping a stream-backed source soresetInputStream()/monitorIntervalstill re-open the file (buffering intodatawould short-circuit that and keep stale config; thanks @ramanathan1504).Fix
Same pattern for the URL branch. Double-close after XmlConfiguration's finally is safe.
Red-green
Red (production try-with-resources removed, factory that never consumes stream):
Green (with try-with-resources): 4 tests, 0 failures.
Summary
ConfigurationSource(no full buffer)