Skip to content

Conversation

@pradeep85841
Copy link
Contributor

Updated VMTransport.java doDispatch() to create a defensive copy of ActiveMQMessage to prevent shared message mutation.

Verified locally with a helper: original message body remains unchanged and copy is correctly dispatched.

No new files added; only VMTransport.java modified.

Pradeep Kunchala added 6 commits January 26, 2026 18:14
- HEALTHCHECK uses Jolokia search on Broker MBean
- Ensures broker is running and accessible
- Auth and Origin headers included for Jolokia security
- Docker CI-ready and deterministic
- Create a dedicated 'activemq' user and group
- Ensure ActiveMQ home directory is owned by this user
- Drop root privileges before starting the broker

This improves container security by avoiding running the process as root,
aligning with Docker best practices.
- Messages are now copied via OpenWireFormat marshal/unmarshal
- Prevents consumers from mutating original message
- Includes fallback if marshal/unmarshal fails
- Verified with unit tests: original message remains intact
@jbonofre jbonofre self-requested a review February 8, 2026 15:55
@mattrpav
Copy link
Contributor

mattrpav commented Feb 8, 2026

Have you observed a bug or problem with message mutation? If so, please provide the scenario and reproducible test case.

ActiveMQConnectionFactory already has copyMessageOnSend enabled by default.

I need help understanding why (in effect) 2 copies are needed.

@jbonofre
Copy link
Member

jbonofre commented Feb 8, 2026

@pradeep85841 can you please provide some details here ? Do you have an issue/test case ? It's not obvious to me if it's cosmetic or actual issue.

@pradeep85841
Copy link
Contributor Author

This is based on issue with vm:// and topics (AMQ-9855).

With VMTransport the same ActiveMQMessage instance is dispatched to multiple consumers. If one consumer reads or mutates the body (Camel split/processor does this), other consumers can see an empty body. This does not happen over tcp:// because marshal/unmarshal creates a copy.

copyMessageOnSend only applies at the producer and broker boundary. The problem here happens inside the broker during dispatch, so that setting does not help.

The change makes VM transport behave consistently with TCP transport and avoids shared mutable state

Happy to add a test if needed.

@jbonofre
Copy link
Member

jbonofre commented Feb 8, 2026

OK, let me take a new look. I'm adding the Jira id in the title of the PR to avoid confusion. Thanks.

@jbonofre jbonofre changed the title VMTransport: Defensive copy of messages to prevent mutation AMQ-9855: VMTransport, Defensive copy of messages to prevent mutation Feb 8, 2026
@mattrpav
Copy link
Contributor

mattrpav commented Feb 8, 2026

This probably needs a config flag that is a corollary to the copyMessageOnSend

ie. copyMessageOnDispatch

@pradeep85841
Copy link
Contributor Author

Sounds good, thanks.
Happy to make this configurable and I’ll wait for next steps.

- Updated VMTransport to create defensive copy of ActiveMQMessage during dispatch.
  This prevents shared mutable state across consumers in VM transport.
- Added VMTransportDefensiveCopyTest to reproduce AMQ-9855 scenario and verify fix.
- Test ensures that message body remains intact across multiple consumers.
- Patch aligns VM transport behavior with TCP transport and avoids Camel route failures.
@pradeep85841
Copy link
Contributor Author

Applied a defensive copy in VMTransport.java to ensure each consumer on vm:// topics receives an independent message.

Added VMTransportDefensiveCopyTest.java to reproduce the issue and verify the fix.

Confirms that message bodies are not shared/mutated between consumers.

Addresses the intermittent null/empty body problem reported in AMQ-9855.

@mattrpav
Copy link
Contributor

mattrpav commented Feb 10, 2026

Should this be enabled on the client connection factory? JMS messages are supposed to be immutable. If someone is modifying it post recv, seems like that is on the app-side to ensure the spec is not violated when using vm transport.

@mattrpav mattrpav requested review from mattrpav and removed request for jbonofre February 10, 2026 23:19
@pradeep85841
Copy link
Contributor Author

Thanks for the suggestion.

The issue in AMQ-9855 happens inside the vm:// transport dispatch path. The same ActiveMQMessage instance is delivered to multiple consumers in-memory. With tcp://, marshal/unmarshal creates separate instances, so this does not occur.

So this is not about client code mutating a received JMS message, it’s about vm:// sharing the same object reference across consumers, which makes its behaviour inconsistent with other transports.

@mattrpav
Copy link
Contributor

The consumer-side may perform the copy, no?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants