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