This is an automated email from the ASF dual-hosted git repository.

jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new c83ab1f8c3 optimize: zstd decompression is changed from jni to 
ZstdInputStream (#7578)
c83ab1f8c3 is described below

commit c83ab1f8c32d68fd54d266d426981590eb5bc18b
Author: funkye <jian...@apache.org>
AuthorDate: Sat Aug 9 16:44:06 2025 +0800

    optimize: zstd decompression is changed from jni to ZstdInputStream (#7578)
---
 changes/en-us/2.x.md                               |  1 +
 changes/zh-cn/2.x.md                               |  2 ++
 .../org/apache/seata/compressor/zstd/ZstdUtil.java | 22 +++++++++++++---
 .../apache/seata/compressor/zstd/ZstdUtilTest.java | 30 ++++++++++++++++++++--
 4 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 27aa56d535..7f1add0791 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -39,6 +39,7 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#7478](https://github.com/apache/incubator-seata/pull/7484)] optimize: 
remove client id metric
 - [[#7557](https://github.com/seata/seata/pull/7557)] upgrade some npmjs 
dependencies
 - [[#7577](https://github.com/seata/seata/pull/7577)]  remove the 4MB size 
limit when decompressing with zstd
+- [[#7578](https://github.com/seata/seata/pull/7578)]  zstd decompression is 
changed from jni to ZstdInputStream
 
 ### security:
 
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 2b0947bdb0..70abe17143 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -48,6 +48,8 @@
 
 - [[#7541](https://github.com/seata/seata/pull/7541)] 修复 jakarta 依赖在 jdk17+ 
单测失败问题
 - [[#7540](https://github.com/seata/seata/pull/7540)] 修复mock server端口冲突问题
+- [[#7578](https://github.com/seata/seata/pull/7578)]  
zstd解压由jni改为ZstdInputStream
+
 
 ### refactor:
 
diff --git 
a/compressor/seata-compressor-zstd/src/main/java/org/apache/seata/compressor/zstd/ZstdUtil.java
 
b/compressor/seata-compressor-zstd/src/main/java/org/apache/seata/compressor/zstd/ZstdUtil.java
index 6dcc2c7885..b9c92b6238 100644
--- 
a/compressor/seata-compressor-zstd/src/main/java/org/apache/seata/compressor/zstd/ZstdUtil.java
+++ 
b/compressor/seata-compressor-zstd/src/main/java/org/apache/seata/compressor/zstd/ZstdUtil.java
@@ -17,6 +17,11 @@
 package org.apache.seata.compressor.zstd;
 
 import com.github.luben.zstd.Zstd;
+import com.github.luben.zstd.ZstdInputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 
 /**
  * the Zstd Util
@@ -28,6 +33,7 @@ public class ZstdUtil {
         if (bytes == null) {
             throw new NullPointerException("bytes is null");
         }
+
         return Zstd.compress(bytes);
     }
 
@@ -35,9 +41,17 @@ public class ZstdUtil {
         if (bytes == null) {
             throw new NullPointerException("bytes is null");
         }
-        long size = Zstd.decompressedSize(bytes);
-        byte[] decompressBytes = new byte[(int) size];
-        Zstd.decompress(decompressBytes, bytes);
-        return decompressBytes;
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ZstdInputStream zis = new ZstdInputStream(bais);
+                ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            byte[] buffer = new byte[8192];
+            int len;
+            while ((len = zis.read(buffer)) > 0) {
+                baos.write(buffer, 0, len);
+            }
+            return baos.toByteArray();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Failed to decompress zstd 
data", e);
+        }
     }
 }
diff --git 
a/compressor/seata-compressor-zstd/src/test/java/org/apache/seata/compressor/zstd/ZstdUtilTest.java
 
b/compressor/seata-compressor-zstd/src/test/java/org/apache/seata/compressor/zstd/ZstdUtilTest.java
index 4bc94f9617..d46bd48bfb 100644
--- 
a/compressor/seata-compressor-zstd/src/test/java/org/apache/seata/compressor/zstd/ZstdUtilTest.java
+++ 
b/compressor/seata-compressor-zstd/src/test/java/org/apache/seata/compressor/zstd/ZstdUtilTest.java
@@ -17,7 +17,6 @@
 package org.apache.seata.compressor.zstd;
 
 import com.github.luben.zstd.Zstd;
-import com.github.luben.zstd.ZstdException;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -47,7 +46,7 @@ public class ZstdUtilTest {
 
     @Test
     public void test_decompress_with_len_illegal() {
-        Assertions.assertThrows(ZstdException.class, () -> {
+        Assertions.assertThrows(IllegalArgumentException.class, () -> {
             // 
https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#zstandard-frames
             List<Byte> bytes = new ArrayList<>();
             byte[] magic = new byte[] {(byte) 0x28, (byte) 0xB5, (byte) 0x2F, 
(byte) 0xFD};
@@ -82,4 +81,31 @@ public class ZstdUtilTest {
         byte[] decompressedData = ZstdUtil.decompress(compressedData);
         Assertions.assertEquals(len, decompressedData.length);
     }
+
+    @Test
+    public void test_decompress_with_fake_frame_content_size_oom() {
+        // Construct a fake zstd header with the frame content size set to 
1GB, while the actual content is only 4MB.
+        byte[] magic = new byte[] {(byte) 0x28, (byte) 0xB5, (byte) 0x2F, 
(byte) 0xFD};
+        byte[] frameHeaderDescriptor = new byte[magic.length + 1];
+        System.arraycopy(magic, 0, frameHeaderDescriptor, 0, magic.length);
+        frameHeaderDescriptor[magic.length] = (byte) 0xA0;
+        // frame content size: 1GB = 0x40000000
+        byte[] frameContentSize = new byte[] {(byte) 0x00, (byte) 0x00, (byte) 
0x00, (byte) 0x40};
+        // The actual content is only 4MB.
+        byte[] fakeContent = new byte[4 * 1024 * 1024];
+        for (int i = 0; i < fakeContent.length; i++) {
+            fakeContent[i] = (byte) ('A' + i % 26);
+        }
+        byte[] frameContent = new byte[frameHeaderDescriptor.length + 
frameContentSize.length + fakeContent.length];
+        System.arraycopy(frameHeaderDescriptor, 0, frameContent, 0, 
frameHeaderDescriptor.length);
+        System.arraycopy(frameContentSize, 0, frameContent, 
frameHeaderDescriptor.length, frameContentSize.length);
+        System.arraycopy(
+                fakeContent,
+                0,
+                frameContent,
+                frameHeaderDescriptor.length + frameContentSize.length,
+                fakeContent.length);
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
ZstdUtil.decompress(frameContent));
+        Assertions.assertTrue(Zstd.decompressedSize(frameContent) > 
MAX_COMPRESSED_SIZE);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org
For additional commands, e-mail: notifications-h...@seata.apache.org

Reply via email to