This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 1a16d2e7b25d9f44f1cb68bfc13b4aad50d0cae4 Author: opencode <[email protected]> AuthorDate: Fri Oct 9 16:09:00 2026 +0200 Detach the unique id when shallow cloning a channel message The shallow clone shared the unique id byte array with the original message. TwoPhaseCommitInterceptor builds its confirmation message with this clone when deepclone is disabled and then generates a new id into the confirmation's id array in place, which overwrote the id of the caller's message. The wire data was already serialized at that point, but the in-memory id returned to the application by Channel.send afterwards identified the confirmation rather than the message that was sent. The clone now copies the id array, so a derived message can be given its own id without affecting the original. Fragment members still share the id of their original message by value, which is all the interceptors and the receiver side keying ever relied on. --- .../org/apache/catalina/tribes/io/ChannelData.java | 7 +++++- .../TestTwoPhaseCommitInterceptor.java | 25 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/java/org/apache/catalina/tribes/io/ChannelData.java b/java/org/apache/catalina/tribes/io/ChannelData.java index 2792338879..a04d9aef37 100644 --- a/java/org/apache/catalina/tribes/io/ChannelData.java +++ b/java/org/apache/catalina/tribes/io/ChannelData.java @@ -308,7 +308,9 @@ public class ChannelData implements ChannelMessage { } /** - * Create a shallow clone, only the data gets recreated + * Create a shallow clone, the message data and the unique id are recreated so that the + * clone, for example a confirmation message derived from the original, can be given a new + * id without modifying the original message in place. * * @return ChannelData clone */ @@ -321,6 +323,9 @@ public class ChannelData implements ChannelMessage { // Cannot happen throw new AssertionError(); } + if (this.uniqueId != null) { + clone.uniqueId = this.uniqueId.clone(); + } if (this.message != null) { clone.message = new XByteBuffer(this.message.getBytesDirect(), false); clone.message.setLength(this.message.getLength()); diff --git a/test/org/apache/catalina/tribes/group/interceptors/TestTwoPhaseCommitInterceptor.java b/test/org/apache/catalina/tribes/group/interceptors/TestTwoPhaseCommitInterceptor.java index 7f33f2ce2d..b5ecc22a29 100644 --- a/test/org/apache/catalina/tribes/group/interceptors/TestTwoPhaseCommitInterceptor.java +++ b/test/org/apache/catalina/tribes/group/interceptors/TestTwoPhaseCommitInterceptor.java @@ -121,6 +121,31 @@ public class TestTwoPhaseCommitInterceptor { Assert.assertNull(chain.payloads.get(1)); } + @Test + public void testShallowCloneKeepsOriginalUniqueIdIntact() throws Exception { + TwoPhaseCommitInterceptor interceptor = new TwoPhaseCommitInterceptor(); + interceptor.setDeepclone(false); + RecordingSendChain chain = new RecordingSendChain(); + GroupChannel channel = new GroupChannel(); + interceptor.setChannel(channel); + interceptor.setNext(chain); + + MemberImpl member = new MemberImpl("localhost", 4000, -1); + ChannelData msg = createMessage(member); + byte[] originalId = msg.getUniqueId(); + byte[] savedId = originalId.clone(); + + interceptor.sendMessage(new Member[] { member }, msg, null); + + Assert.assertEquals(2, chain.messages.size()); + Assert.assertArrayEquals("Building the confirmation must not modify the original id in place", + savedId, msg.getUniqueId()); + Assert.assertNotSame("The clone must not share the id array with the original", + originalId, chain.messages.get(1).getUniqueId()); + Assert.assertFalse("The confirmation must carry a different id", + Arrays.equals(savedId, chain.messages.get(1).getUniqueId())); + } + @Test public void testOriginalSendFailureSkipsConfirmation() throws Exception { TwoPhaseCommitInterceptor interceptor = new TwoPhaseCommitInterceptor(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
