Thanks so much for the report and the diligent analysis, Stephan! Much appreciated! 🙏
I think your analysis is correct. Would you mind creating a GitHub Issue, please? I will push a fix some time tonight (CET). I skimmed through JSON Template Layout's `InstantFormatter`, and it is looking fine. I want to investigate further if there are other places/layouts where the issue manifests itself. I wish I would have time to strap some jcstress harness around certain parts of Log4j. For the records, it always makes me wonder shouldn't those `if (currentTime != cachedTime)` checks around the compare-and-swap be replaced with `if (currentTime > cachedTime)`. 🤔 @Piotr, @Christian, yet another supporting case for my "Unified date-time formatting" venture. On Sun, May 21, 2023 at 4:22 PM Stephan Markwalder < stephan.markwal...@fnz.com> wrote: > Hi, > > I'm not 100% sure if my analysis is correct. I therefore write to you > before opening an issue on GitHub. > > If two threads are calling the method > DatePatternConverter.formatWithoutThreadLocals(Instant,StringBuilder) at > the same time, one of the threads may incorrectly use the formatted date of > the other thread in the output. In other words, the event of one thread > could be written to a log file with the date of the other thread's event. > > The following sequence shows how this could happen. All line numbers are > based on this source code: > > https://github.com/apache/logging-log4j2/blob/98c3ceb655d485b0adb48e05d84c8269716f59e8/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java#L327-L338 > > 0. cachedTime contains time t0. > > Thread 1: > 1. Line 327: Calls the method formatWithoutThreadLocals(instant,output) > with instant = t1, where t1 > t0. > 2. Line 328: Reads t0 from cachedTime into local variable cached. > 3. Line 329: if condition evaluates to true (t1 != t0). > 4. Line 330: Creates a new CachedTime(t1) and stores it in local variable > newTime. > > Thread 2: > 5. Line 327: Calls the method formatWithoutThreadLocals(instant,output) > with instant = t2, where t2 > t1. > 6. Line 328: Reads t0 from cachedTime into local variable cached. > 7. Line 329: if condition evaluates to true (t2 != t0). > 8. Line 330: Creates a new CachedTime(t2) and stores it in local variable > newTime. > > Thread 1: > 9. Line 331: Calls cachedTime.compareAndSet(cached, newTime): This will > set the shared cachedTime to thread 1's newTime t1 and return true > (t0.compareAndSet(t0,t1) == true). > 10. Line 332: Sets local variable cached = newTime (t1). > 11. Line 337: Appends cached.formatted (t1) to output. > > Thread 2: > 12. Line 331: Calls cachedTime.compareAndSet(cached, newTime): This will > NOT change the shared cachedTime and return false (t1.compareAndSet(t0,t2) > == false). > 13. Line 334: Sets local variable cached = cachedTime.get(). <-- This will > read t1 into local variable cached! > 14. Line 337: Appends cached.formatted (t1!) to output. > > Result: The event recorded by thread 2 at time t2 will be logged with a > formatted date based on t1, the time when thread 1 has recorded its own > event. In other words, both events would be written to the log file with > the same date and time, and the time of event 2 is completely lost. Also, > in the presence of multiple appenders, the same event can be written to > different log files with a different date and time. > > I think the problem is found at line 334 where thread 2 is reading the > time that was previously written to cachedTime by thread 1. In order to use > the correct time, thread 2 should instead set cached = newTime. This means > that the if block (line 330) and else block (line 332) would be identical. > So the return value of cachedTime.compareAndSet(cached, newTime) would not > be needed, and the code could be simplified a lot. > > Is my analysis correct, or am I missing something? > > Best regards, > Stephan > > PS 1: This issue has been found when using Log4j in a web application. > This means that the use of thread-locals for "gc-free logging" is disabled > by default. > PS 2: The web application currently uses only synchronous loggers and > appenders. > Email Disclaimer > FNZ (UK) Ltd registered in England and Wales (05435760) 10th Floor, 135 > Bishopsgate, London EC2M 3TP, FNZ (UK) Ltd is authorised and regulated by > the Financial Conduct Authority (438687); FNZ TA Services Ltd registered in > England and Wales (09571767) 10th Floor, 135 Bishopsgate, London EC2M 3TP, > FNZ TA Services Ltd is authorised and regulated by the Financial Conduct > Authority (932253); FNZ Securities Ltd registered in England and Wales > (09486463) 10th Floor, 135 Bishopsgate, London EC2M 3TP, FNZ Securities > Ltd, is authorised and regulated by the Financial Conduct Authority > (733400); JHC Systems Limited registered in England and Wales (08729370) > Temple Point 6th Floor, 1 Temple Row, Birmingham, West Midlands, B2 5LG; > FNZ (Europe) DAC registered in Ireland (657886) Block C, Irish Life > Centre, Lower Abbey Street, Dublin 1, D01V9F5, Ireland; FNZ SA (Pty) Ltd > registered under the laws of South Africa (2018/547997/07), 1st floor, > Newport House, Prestwich Street, Greenpoint, western Cape, 8001; FNZ > Limited registered in New Zealand (1797706) FNZ House, Level 3, 29A Brandon > Street, Wellington, 6011 New Zealand; FNZ (Australia) Pty Ltd registered in > Australia (138 819 119) Level 1, 99 Elizabeth St, Sydney 2000; FNZ (Hong > Kong) Limited registered in Hong Kong (1305362) 6A-1, Koshun House, 331 > Nathan Road, Hong Kong; FNZ (Singapore) Services Pte. Ltd. registered in > Singapore (201307199R) 61 Robinson Road, #13-03A, Robinson Centre, > Singapore (068893); and FNZ (China) Ltd registered in China > (91310115MA1K3G4K6T) [中国(上海)自由贸易试验区世纪大道1196 号二 座20 层. > This message is intended solely for the addressee and may contain > confidential information. If you have received this message in error, > please send it back to us, and immediately and permanently delete it. Do > not use, copy or disclose the information contained in this message or in > any attachment. > Emails sent to and from FNZ may be monitored and read for legitimate > business purposes. Emails cannot be guaranteed to be secure or error-free, > and you should protect your systems. FNZ does not accept any liability > arising from interception, corruption, loss or destruction of this email, > or if it arrives late or incomplete or with errors or viruses. > For more information about the FNZ group please visit our website here > where you can also find links to our policies including our Privacy policy > which provides information about what we do with your personal data. > >