From 5b1c6caf9f87ed74f6eecf49eafcf0a5e4af7f94 Mon Sep 17 00:00:00 2001 From: Yann Date: Thu, 9 Apr 2026 16:53:29 +0800 Subject: [PATCH] [client] Deep copy BinaryString in createDeepFieldGetter to fix use-after-free IndexedRow.getString() returns a zero-copy BinaryString view into the underlying MemorySegment. When DefaultCompletedFetch.drain() releases the backing Netty ByteBuf, these BinaryString views become dangling references, causing data corruption on platforms that eagerly reclaim freed memory (e.g., Linux CI). This fixes the flaky test RemoteLogScannerITCase#testScanFromRemoteAndProject by adding a STRING case to createDeepFieldGetter and createDeepElementGetter that calls BinaryString.copy() to materialize the string data into independent heap memory. Co-Authored-By: Claude Opus 4.6 --- .../src/main/java/org/apache/fluss/row/InternalArray.java | 3 +++ .../src/main/java/org/apache/fluss/row/InternalRow.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/fluss-common/src/main/java/org/apache/fluss/row/InternalArray.java b/fluss-common/src/main/java/org/apache/fluss/row/InternalArray.java index 6575de1b39..f1ed1ee676 100644 --- a/fluss-common/src/main/java/org/apache/fluss/row/InternalArray.java +++ b/fluss-common/src/main/java/org/apache/fluss/row/InternalArray.java @@ -175,6 +175,9 @@ static ElementGetter createElementGetter(DataType fieldType) { static ElementGetter createDeepElementGetter(DataType fieldType) { final ElementGetter elementGetter; switch (fieldType.getTypeRoot()) { + case STRING: + elementGetter = (array, pos) -> array.getString(pos).copy(); + break; case ARRAY: DataType nestedType = ((ArrayType) fieldType).getElementType(); ElementGetter nestedGetter = createDeepElementGetter(nestedType); diff --git a/fluss-common/src/main/java/org/apache/fluss/row/InternalRow.java b/fluss-common/src/main/java/org/apache/fluss/row/InternalRow.java index e19f42b2e0..7e0a608225 100644 --- a/fluss-common/src/main/java/org/apache/fluss/row/InternalRow.java +++ b/fluss-common/src/main/java/org/apache/fluss/row/InternalRow.java @@ -252,6 +252,9 @@ static FieldGetter createFieldGetter(DataType fieldType, int fieldPos) { static FieldGetter createDeepFieldGetter(DataType fieldType, int fieldPos) { final FieldGetter fieldGetter; switch (fieldType.getTypeRoot()) { + case STRING: + fieldGetter = row -> row.getString(fieldPos).copy(); + break; case ARRAY: DataType elementType = ((ArrayType) fieldType).getElementType(); InternalArray.ElementGetter nestedGetter = createDeepElementGetter(elementType);