diff --git a/native/compile-osx.sh b/native/compile-osx.sh index b1404339e..3cdbeafd3 100755 --- a/native/compile-osx.sh +++ b/native/compile-osx.sh @@ -6,7 +6,7 @@ export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Hom CFLAGS="-O3 -I$JAVA_HOME/include/ -I$JAVA_HOME/include/darwin/ -fPIC -shared" clang $CFLAGS -lz src/main/c/jni_util.c src/main/c/jni_zlib_deflate.c src/main/c/jni_zlib_inflate.c \ - -o src/main/resources/macosx/velocity-compress.dylib + src/main/c/jni_zlib_common.c -o src/main/resources/macosx/velocity-compress.dylib clang $CFLAGS -I $MBEDTLS_ROOT/include -shared $MBEDTLS_ROOT/library/aes.c $MBEDTLS_ROOT/library/aesni.c \ $MBEDTLS_ROOT/library/platform.c $MBEDTLS_ROOT/library/platform_util.c src/main/c/jni_util.c src/main/c/jni_cipher.c \ -o src/main/resources/macosx/velocity-cipher.dylib \ No newline at end of file diff --git a/native/src/main/c/jni_util.c b/native/src/main/c/jni_util.c index e5356c93f..1e2b6bd8c 100644 --- a/native/src/main/c/jni_util.c +++ b/native/src/main/c/jni_util.c @@ -1,7 +1,7 @@ #include #include "jni_util.h" -JNIEXPORT void JNICALL +void JNICALL throwException(JNIEnv *env, const char *type, const char *msg) { jclass klazz = (*env)->FindClass(env, type); diff --git a/native/src/main/c/jni_zlib_common.c b/native/src/main/c/jni_zlib_common.c new file mode 100644 index 000000000..20d320311 --- /dev/null +++ b/native/src/main/c/jni_zlib_common.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include "jni_util.h" + +void JNICALL +check_zlib_free(JNIEnv *env, z_stream *stream, bool deflate) +{ + int ret = deflate ? deflateEnd(stream) : inflateEnd(stream); + char *msg = stream->msg; + free((void*) stream); + + switch (ret) { + case Z_OK: + break; + case Z_STREAM_ERROR: + if (msg == NULL) { + msg = "stream state inconsistent"; + } + // fall-through + case Z_DATA_ERROR: + if (msg == NULL) { + msg = "data was discarded"; + } + throwException(env, "java/lang/IllegalArgumentException", msg); + break; + } +} \ No newline at end of file diff --git a/native/src/main/c/jni_zlib_common.h b/native/src/main/c/jni_zlib_common.h new file mode 100644 index 000000000..ff4bc9a80 --- /dev/null +++ b/native/src/main/c/jni_zlib_common.h @@ -0,0 +1,6 @@ +#include +#include +#include + +void JNICALL +check_zlib_free(JNIEnv *env, z_stream *stream, bool deflate); \ No newline at end of file diff --git a/native/src/main/c/jni_zlib_deflate.c b/native/src/main/c/jni_zlib_deflate.c index c0195ff38..e76ba3053 100644 --- a/native/src/main/c/jni_zlib_deflate.c +++ b/native/src/main/c/jni_zlib_deflate.c @@ -1,8 +1,10 @@ #include #include +#include #include #include #include "jni_util.h" +#include "jni_zlib_common.h" static jfieldID finishedID; static jfieldID consumedID; @@ -27,27 +29,28 @@ Java_com_velocitypowered_natives_compression_NativeZlibDeflate_init(JNIEnv *env, return 0; } - char *msg; int ret = deflateInit(stream, level); - - switch (ret) { - case Z_OK: - return (jlong) stream; - case Z_MEM_ERROR: - free(stream); - throwException(env, "java/lang/OutOfMemoryError", "zlib init"); - return 0; - case Z_STREAM_ERROR: - free(stream); - char message[32]; - snprintf(message, 32, "invalid level %d", level); - throwException(env, "java/lang/IllegalArgumentException", message); - return 0; - default: - msg = stream->msg; - free(stream); - throwException(env, "java/util/zip/DataFormatException", msg); - return 0; + if (ret == Z_OK) { + return (jlong) stream; + } else { + char *zlib_msg = stream->msg; + free(stream); + switch (ret) { + case Z_MEM_ERROR: + throwException(env, "java/lang/OutOfMemoryError", "zlib init"); + break; + case Z_STREAM_ERROR: { + // Thanks Ken and Ritchie! + char message[32]; + snprintf(message, 32, "invalid level %d", level); + throwException(env, "java/lang/IllegalArgumentException", message); + break; + } + default: + throwException(env, "java/util/zip/DataFormatException", zlib_msg); + break; + } + return 0; } } @@ -57,24 +60,7 @@ Java_com_velocitypowered_natives_compression_NativeZlibDeflate_free(JNIEnv *env, jlong ctx) { z_stream* stream = (z_stream*) ctx; - int ret = deflateEnd(stream); - char *msg = stream->msg; - free((void*) ctx); - - switch (ret) { - case Z_OK: - break; - case Z_STREAM_ERROR: - if (msg == NULL) { - msg = "stream state inconsistent"; - } - case Z_DATA_ERROR: - if (msg == NULL) { - msg = "data was discarded"; - } - throwException(env, "java/lang/IllegalArgumentException", msg); - break; - } + check_zlib_free(env, stream, true); } JNIEXPORT int JNICALL diff --git a/native/src/main/c/jni_zlib_inflate.c b/native/src/main/c/jni_zlib_inflate.c index 0695e4c91..816670e43 100644 --- a/native/src/main/c/jni_zlib_inflate.c +++ b/native/src/main/c/jni_zlib_inflate.c @@ -1,8 +1,10 @@ #include #include +#include #include #include #include "jni_util.h" +#include "jni_zlib_common.h" static jfieldID finishedID; static jfieldID consumedID; @@ -26,25 +28,23 @@ Java_com_velocitypowered_natives_compression_NativeZlibInflate_init(JNIEnv *env, return 0; } - char *msg; int ret = inflateInit(stream); - - switch (ret) { - case Z_OK: - return (jlong) stream; - case Z_MEM_ERROR: - free(stream); - throwException(env, "java/lang/OutOfMemoryError", "zlib init"); - return 0; - case Z_STREAM_ERROR: - free(stream); - throwException(env, "java/lang/IllegalArgumentException", "stream clobbered?"); - return 0; - default: - msg = stream->msg; - free(stream); - throwException(env, "java/util/zip/DataFormatException", msg); - return 0; + if (ret == Z_OK) { + return (jlong) stream; + } else { + char *zlib_msg = stream->msg; + free(stream); + switch (ret) { + case Z_MEM_ERROR: + throwException(env, "java/lang/OutOfMemoryError", "zlib init"); + return 0; + case Z_STREAM_ERROR: + throwException(env, "java/lang/IllegalArgumentException", "stream clobbered?"); + return 0; + default: + throwException(env, "java/util/zip/DataFormatException", zlib_msg); + return 0; + } } } @@ -54,24 +54,7 @@ Java_com_velocitypowered_natives_compression_NativeZlibInflate_free(JNIEnv *env, jlong ctx) { z_stream* stream = (z_stream*) ctx; - int ret = inflateEnd(stream); - char *msg = stream->msg; - free((void*) ctx); - - switch (ret) { - case Z_OK: - break; - case Z_STREAM_ERROR: - if (msg == NULL) { - msg = "stream state inconsistent"; - } - case Z_DATA_ERROR: - if (msg == NULL) { - msg = "data was discarded"; - } - throwException(env, "java/lang/IllegalArgumentException", msg); - break; - } + check_zlib_free(env, stream, false); } JNIEXPORT int JNICALL diff --git a/native/src/main/resources/linux_x64/velocity-compress.so b/native/src/main/resources/linux_x64/velocity-compress.so index e9655d774..53a2d8597 100755 Binary files a/native/src/main/resources/linux_x64/velocity-compress.so and b/native/src/main/resources/linux_x64/velocity-compress.so differ diff --git a/native/src/main/resources/macosx/velocity-compress.dylib b/native/src/main/resources/macosx/velocity-compress.dylib index b3dbcce49..afe4075d7 100755 Binary files a/native/src/main/resources/macosx/velocity-compress.dylib and b/native/src/main/resources/macosx/velocity-compress.dylib differ diff --git a/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java b/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java index 506228c07..0d37f8f67 100644 --- a/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java +++ b/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java @@ -1,5 +1,6 @@ package com.velocitypowered.natives.compression; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.condition.OS.LINUX; @@ -28,6 +29,12 @@ class VelocityCompressorTest { new Random(1).nextBytes(TEST_DATA); } + @Test + @EnabledOnOs({MAC, LINUX}) + void sanityCheckNative() { + assertThrows(IllegalArgumentException.class, () -> Natives.compress.get().create(-42)); + } + @Test @EnabledOnOs({MAC, LINUX}) void nativeIntegrityCheck() throws DataFormatException {