[ 
https://issues.apache.org/jira/browse/CAMEL-24104?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen resolved CAMEL-24104.
---------------------------------
    Resolution: Fixed

> camel-bean: racy lazy Processor-adapter lookup in AbstractBeanProcessor 
> (non-volatile fields, no retry on conversion failure)
> -----------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24104
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24104
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-bean
>    Affects Versions: 4.21.0
>            Reporter: Federico Mariani
>            Assignee: Claus Ibsen
>            Priority: Minor
>             Fix For: 4.22.0
>
>
> {{AbstractBeanProcessor.getCustomAdapter()}} lazily resolves a custom 
> {{Processor}} adapter for the bean via type conversion, guarded by:
> {code:java}
> private transient Processor processor;
> private transient boolean lookupProcessorDone;
> ...
> Processor target = getProcessor();            // plain read, no lock
> if (target == null) {
>     if (allowCache) {
>         if (!lookupProcessorDone) {           // plain read, no lock
>             lock.lock();
>             try {
>                 lookupProcessorDone = true;   // set BEFORE conversion
>                 target = ...tryConvertTo(Processor.class, exchange, beanTmp);
>                 processor = target;
>             } finally { lock.unlock(); }
>         }
>     }
> {code}
> Two issues:
> # {{lookupProcessorDone}} and {{processor}} are *non-volatile* and read 
> outside the lock. A racing thread can observe {{lookupProcessorDone == true}} 
> while still reading a stale {{null}} {{processor}} → that exchange silently 
> falls back to bean-binding method invocation instead of the custom 
> {{Processor}} adapter (different invocation semantics for that message). 
> There is also no double-check of {{lookupProcessorDone}} after acquiring the 
> lock, so two threads racing before the flag is visible both perform the 
> conversion (benign, but shows the guard is not doing its job).
> # {{lookupProcessorDone = true}} is set *before* {{tryConvertTo}}; if the 
> conversion throws, the adapter lookup is permanently disabled without retry.
> Suggested fix: make both fields {{volatile}} (or do the whole 
> check-and-populate under the lock with a re-check), and set the flag after 
> the conversion succeeds.
> No test attached — the visibility race is not deterministically reproducible 
> in a unit test; the defect is evident from the field declarations and access 
> pattern in {{AbstractBeanProcessor.java}}.
> _This issue was found by an AI-assisted code review. Reported by Claude Code 
> on behalf of [~fmariani] (GitHub: Croway)._



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

Reply via email to