This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new c819020bc2a IGNITE-28413 Java client: fix race condition in message
decoder (#7926)
c819020bc2a is described below
commit c819020bc2a6a82a3187f3c998714caf4077e6db
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Tue Apr 7 11:28:20 2026 +0300
IGNITE-28413 Java client: fix race condition in message decoder (#7926)
Disable automatic `discardReadBytes` in Netty to fix a race condition and
data corruption caused by concurrent buffer modification:
* Netty calls `discardSomeReadBytes` on IO thread, which changes
`readerIndex`
* `TcpClientChannel.asyncContinuationExecutor` decodes the response on
another thread, which also uses and changes `readerIndex`
---
.../ignite/internal/client/proto/ClientMessageDecoder.java | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageDecoder.java
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageDecoder.java
index 0c3bda74a33..4d83baf6e42 100644
---
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageDecoder.java
+++
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageDecoder.java
@@ -27,11 +27,12 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.CharsetUtil;
import java.util.Arrays;
import org.apache.ignite.lang.IgniteException;
+import org.jetbrains.annotations.Nullable;
/**
* Decodes full client messages: 1. MAGIC for first message. 2. Payload length
(4 bytes). 3. Payload (N bytes).
*/
-public class ClientMessageDecoder extends LengthFieldBasedFrameDecoder {
+public final class ClientMessageDecoder extends LengthFieldBasedFrameDecoder {
/** Magic decoded flag. */
private boolean magicDecoded;
@@ -43,13 +44,19 @@ public class ClientMessageDecoder extends
LengthFieldBasedFrameDecoder {
*/
public ClientMessageDecoder() {
super(Integer.MAX_VALUE - HEADER_SIZE, 0, HEADER_SIZE, 0, HEADER_SIZE,
true);
+
+ // Effectively disable automatic calls to discardReadBytes /
discardSomeReadBytes:
+ // We pass the buffers to other threads, and discardReadBytes modifies
the buffer concurrently,
+ // leading to race conditions and corrupted offsets.
+ // Moreover, discardReadBytes is not very beneficial with our access
patterns:
+ // Read small header => pass to another thread => read fully =>
discard.
+ setDiscardAfterReads(Integer.MAX_VALUE);
}
/** {@inheritDoc} */
@Override
- protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws
Exception {
+ protected @Nullable Object decode(ChannelHandlerContext ctx, ByteBuf in)
throws Exception {
if (!readMagic(in)) {
- //noinspection ReturnOfNull
return null;
}