[ 
https://issues.apache.org/jira/browse/WW-5647?focusedWorklogId=1030899&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1030899
 ]

ASF GitHub Bot logged work on WW-5647:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 17/Jul/26 10:36
            Start Date: 17/Jul/26 10:36
    Worklog Time Spent: 10m 
      Work Description: lukaszlenart commented on PR #1781:
URL: https://github.com/apache/struts/pull/1781#issuecomment-5002231569

   ## Code Review
   
   ### Overview
   Fixes a data race in `XSLTResult.getTemplates()`. The static templates cache 
was a plain `HashMap` read via an unsynchronized `get()` while writes happened 
inside a `synchronized` block. The PR swaps `HashMap` → `ConcurrentHashMap`, 
adds a double-checked read inside the `synchronized` block, and inlines the 
field initializer (dropping the `static {}` block).
   
   The diagnosis is correct and the fix is sound. Concurrent read/write on a 
plain `HashMap` is a genuine bug (data corruption, and CPU-spinning infinite 
loops on older JDKs) — a legitimate correctness/hardening fix.
   
   ### Correctness ✅
   Traced the `noCache` interaction, the part most likely to break:
   
   - **`noCache == false`, concurrent miss**: outer `get()` null → both threads 
enter `synchronized` sequentially → the double-check `get()` lets the second 
thread see the first thread's `put()` and skip recompilation. Exactly the 
redundant-compilation fix, and correct.
   - **`noCache == true`**: the inner guard preserves `noCache || (...)`, so it 
still recompiles every call. Behavior unchanged.
   - **Return value**: `templates` is correctly reassigned on every path (cache 
hit, double-check hit, fresh compile), so the returned reference is always 
valid.
   
   No regression in observable behavior; the only new effect is avoiding 
duplicate compilation on concurrent misses, which is the stated goal.
   
   ### Style / Conventions ✅
   - Inlining the initializer and removing the `static {}` block is a clean 
simplification.
   - The re-check comment is helpful and matches surrounding style.
   
   ### Suggestions / Minor Notes
   - **Pre-existing, not introduced here:** with `noCache == true` the code 
still executes `templatesCache.put(path, templates)`, polluting the shared 
static cache from a "no-cache" instance. Out of scope here, but worth a 
follow-up — arguably a `noCache` result should never populate the shared cache.
   - **`synchronized (templatesCache)` as a map lock is now redundant** (the 
map is thread-safe), but it's still needed to serialize *compilation* and dedup 
work — keeping it is right. A `computeIfAbsent` alternative would hold a bin 
lock across the slow `newTemplates()` call, so the current approach is 
preferable. No change needed.
   - **Test coverage:** `XSLTResultTest.java` exists but the PR adds no test. 
Concurrency is hard to test deterministically, but the double-check dedup 
behavior is testable — e.g. a subclass counting `newTemplates` invocations to 
assert a single path is compiled once. Optional but would lock in the intent.
   
   ### Security
   The underlying `HashMap` race could theoretically spin CPU under concurrent 
access, but this is defensive concurrency hardening on an internal template 
cache, not a classic Struts attack surface (OGNL/params/upload). Reasonable as 
a public PR.
   
   ### Verdict
   **Approve.** Small, correct, well-reasoned fix. The 
`noCache`-populates-cache observation and a dedup unit test are the only 
follow-ups worth considering, both optional.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   




Issue Time Tracking
-------------------

            Worklog Id:     (was: 1030899)
    Remaining Estimate: 0h
            Time Spent: 10m

> Use ConcurrentHashMap for XSLT template cache
> ---------------------------------------------
>
>                 Key: WW-5647
>                 URL: https://issues.apache.org/jira/browse/WW-5647
>             Project: Struts 2
>          Issue Type: Improvement
>          Components: Plugin - XSLT
>    Affects Versions: 7.2.1
>            Reporter: Arun Manni
>            Priority: Minor
>             Fix For: 7.3.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> The XSLT template cache in XSLTResult uses a plain HashMap with an 
> unsynchronized get() outside the synchronized block. Under concurrent 
> access this can produce stale reads or exceptions from internal 
> HashMap corruption.
> This patch replaces HashMap with ConcurrentHashMap for thread-safe 
> reads, adds a double-check inside the synchronized block to avoid 
> redundant template compilation, and removes the static initializer 
> in favour of inline initialization.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to