From 511f23c98f3c992f4f97403433643f353bdc1623 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 26 Jul 2026 15:05:25 +0200 Subject: [PATCH 1/4] Fix potential bug IntelliJ warnings --- .../endive/build/time/compiler/Generator.java | 7 ++- .../java/run/endive/experimental/cli/Cli.java | 6 +-- .../endive/runtime/InterpreterMachine.java | 3 ++ .../endive/simd/SimdInterpreterMachine.java | 50 ++++--------------- .../src/main/java/run/endive/wasm/Parser.java | 2 +- 5 files changed, 20 insertions(+), 48 deletions(-) diff --git a/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java b/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java index 04f127bca..6dca03aa8 100644 --- a/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java +++ b/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java @@ -23,6 +23,7 @@ import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; import com.github.javaparser.utils.SourceRoot; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -168,7 +169,11 @@ public void generateModuleInterface(String moduleInterfaceName) throws IOExcepti public void generateMetaWasm(Set interpretedFunctions) throws IOException { byte[] wasmBytes = Files.readAllBytes(config.wasmFile()); - var module = Parser.builder().includeSectionId(SectionId.CODE).build().parse(wasmBytes); + var module = + Parser.builder() + .includeSectionId(SectionId.CODE) + .build() + .parse(() -> new ByteArrayInputStream(wasmBytes)); var writer = new WasmWriter(); Parser.parseWithoutDecoding( diff --git a/cli/src/main/java/run/endive/experimental/cli/Cli.java b/cli/src/main/java/run/endive/experimental/cli/Cli.java index fd80b33e9..eaa62b970 100644 --- a/cli/src/main/java/run/endive/experimental/cli/Cli.java +++ b/cli/src/main/java/run/endive/experimental/cli/Cli.java @@ -86,11 +86,7 @@ public void run() { var result = export.apply(params); if (result != null) { for (var r : result) { - if (result == null) { - System.out.println(0); - } else { - System.out.println(r); // Check floating point results - } + System.out.println(r); // Check floating point results } } } diff --git a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java index 78832ea4c..e516538fd 100644 --- a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java +++ b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java @@ -1507,6 +1507,9 @@ private static void I32_SHR_S(MStack stack) { private static void I32_SHL(MStack stack) { var c = (int) stack.pop(); var v = (int) stack.pop(); + // Intentionally get the result as 32 bit `int` (despite it being converted to `long` when + // pushed to the stack) + //noinspection IntegerMultiplicationImplicitCastToLong stack.push(v << c); } diff --git a/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java b/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java index d39edffe4..d51496ab1 100644 --- a/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java +++ b/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java @@ -1369,8 +1369,6 @@ private static byte addSatU(byte a, byte b) { int result = Byte.toUnsignedInt(a) + Byte.toUnsignedInt(b); if (result >= 0xFF) { return (byte) 0xFF; - } else if (result < 0) { - return 0; } else { return (byte) result; } @@ -1736,53 +1734,23 @@ private static void BINOP( } private static boolean lt(float a, float b) { - if (Float.isNaN(b)) { - return false; - } else if ((a == 0.0f && b == -0.0f) || (a == -0.0f && b == 0.0f)) { - return false; - } else { - return Float.compare(a, b) < 0; - } + return a <= b; } private static boolean le(float a, float b) { - if (Float.isNaN(b)) { - return false; - } else if ((a == 0.0f && b == -0.0f) || (a == -0.0f && b == 0.0f)) { - return true; - } else { - return Float.compare(a, b) <= 0; - } + return a <= b; } private static boolean gt(float a, float b) { - if (Float.isNaN(a)) { - return false; - } else if ((a == 0.0f && b == -0.0f) || (a == -0.0f && b == 0.0f)) { - return false; - } else { - return Float.compare(a, b) > 0; - } + return a > b; } private static boolean ge(float a, float b) { - if (Float.isNaN(a)) { - return false; - } else if ((a == 0.0f && b == -0.0f) || (a == -0.0f && b == 0.0f)) { - return true; - } else { - return Float.compare(a, b) >= 0; - } + return a >= b; } private static boolean equals(float a, float b) { - if (Float.isNaN(a) || Float.isNaN(b)) { - return false; - } else if ((a == 0.0f && b == -0.0f) || (a == -0.0f && b == 0.0f)) { - return true; - } else { - return Float.compare(a, b) == 0; - } + return a == b; } private static void F32x4(MStack stack, BiFunction fn) { @@ -1925,7 +1893,7 @@ private static void BITMASK(MStack stack, Function reduce) { var result = 0L; for (int i = 0; i < vals.length; i++) { if (vals[i] < 0) { - result |= 1 << i; + result |= 1L << i; } } @@ -2564,7 +2532,7 @@ private static void I64x2_EXTMUL_LOW_I32x4_S(MStack stack) { var res = new long[] { - v1[0] * v2[0], v1[1] * v2[1], + ((long) v1[0]) * v2[0], ((long) v1[1]) * v2[1], }; var result = Value.i64ToVec(res); System.arraycopy(result, 0, stack.array(), offset, 2); @@ -2587,7 +2555,7 @@ private static void I64x2_EXTMUL_HIGH_I32x4_S(MStack stack) { var res = new long[] { - v1[2] * v2[2], v1[3] * v2[3], + ((long) v1[2]) * v2[2], ((long) v1[3]) * v2[3], }; var result = Value.i64ToVec(res); System.arraycopy(result, 0, stack.array(), offset, 2); @@ -3007,7 +2975,7 @@ private static void I8x16_SWIZZLE(MStack stack) { if (id < 8) { base = (baseLow >> (id * 8)) & 0xFFL; } else if (id < 16) { - base = (baseHigh >> (id * 8)) & 0xFFL; + base = (baseHigh >> ((id - 8) * 8)) & 0xFFL; } else { base = 0x00L; } diff --git a/wasm/src/main/java/run/endive/wasm/Parser.java b/wasm/src/main/java/run/endive/wasm/Parser.java index 34b4182fa..294887327 100644 --- a/wasm/src/main/java/run/endive/wasm/Parser.java +++ b/wasm/src/main/java/run/endive/wasm/Parser.java @@ -1358,7 +1358,7 @@ private static Instruction parseInstruction(ByteBuffer buffer) { operands.add(n); for (var j = 0; j < n; j++) { var catchOp = readByte(buffer); - operands.add(0L | catchOp); + operands.add((long) catchOp); var catchOpcode = CatchOpCode.byOpCode(catchOp); switch (catchOpcode) { case CATCH: From a4d500e94f9316a2283edaee4a98784b03f6b928 Mon Sep 17 00:00:00 2001 From: andreatp Date: Mon, 27 Jul 2026 17:31:38 +0100 Subject: [PATCH 2/4] Fix Generator using wrong Parser.parse overload The previous commit changed parse(wasmBytes) to parse(() -> new ByteArrayInputStream(wasmBytes)), switching from the static method (which ignores builder config) to the instance method (which applies includeSectionId(CODE)). Parsing only the CODE section causes validation to fail with "function and code section have inconsistent lengths". Use the static Parser.parse(wasmBytes) directly since the builder config was never actually applied and the method needs multiple sections (CODE, FUNCTION, IMPORT). --- .../java/run/endive/build/time/compiler/Generator.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java b/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java index 6dca03aa8..f3f8e27f6 100644 --- a/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java +++ b/build-time-compiler/src/main/java/run/endive/build/time/compiler/Generator.java @@ -23,7 +23,6 @@ import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; import com.github.javaparser.utils.SourceRoot; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -169,11 +168,7 @@ public void generateModuleInterface(String moduleInterfaceName) throws IOExcepti public void generateMetaWasm(Set interpretedFunctions) throws IOException { byte[] wasmBytes = Files.readAllBytes(config.wasmFile()); - var module = - Parser.builder() - .includeSectionId(SectionId.CODE) - .build() - .parse(() -> new ByteArrayInputStream(wasmBytes)); + var module = Parser.parse(wasmBytes); var writer = new WasmWriter(); Parser.parseWithoutDecoding( From 700bcad718027ba690ad93a53a4c1f0614179797 Mon Sep 17 00:00:00 2001 From: andreatp Date: Mon, 27 Jul 2026 17:31:43 +0100 Subject: [PATCH 3/4] Fix SIMD float lt using <= instead of < The previous commit simplified lt(float, float) to "return a <= b" instead of "return a < b", making it identical to le (less-than-or-equal). --- simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java b/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java index d51496ab1..3e22253ef 100644 --- a/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java +++ b/simd/src/main/java/run/endive/simd/SimdInterpreterMachine.java @@ -1734,7 +1734,7 @@ private static void BINOP( } private static boolean lt(float a, float b) { - return a <= b; + return a < b; } private static boolean le(float a, float b) { From dd837cff4ae2a2f50091b1e743a32229e6c91bb4 Mon Sep 17 00:00:00 2001 From: andreatp Date: Tue, 15 Sep 2026 12:43:43 +0100 Subject: [PATCH 4/4] Fix interpreter I32_MUL leaking upper 32 bits --- .../run/endive/runtime/InterpreterMachine.java | 5 +++-- .../java/run/endive/runtime/WasmModuleTest.java | 16 ++++++++++++++++ .../compiled/i32_mul_overflow.wat.wasm | Bin 0 -> 93 bytes .../src/main/resources/wat/i32_mul_overflow.wat | 13 +++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 wasm-corpus/src/main/resources/compiled/i32_mul_overflow.wat.wasm create mode 100644 wasm-corpus/src/main/resources/wat/i32_mul_overflow.wat diff --git a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java index e516538fd..755ab16de 100644 --- a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java +++ b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java @@ -1307,7 +1307,8 @@ private static void I64_SUB(MStack stack) { private static void I32_MUL(MStack stack) { var a = stack.pop(); var b = stack.pop(); - stack.push(a * b); + int result = (int) (a * b); + stack.push(result); } private static void I64_MUL(MStack stack) { @@ -3242,7 +3243,7 @@ private static void TRY_TABLE( private static void IF( StackFrame frame, MStack stack, Instance instance, AnnotatedInstruction instruction) { - var predValue = stack.pop(); + var predValue = (int) stack.pop(); var paramsSize = numberOfParams(instance, instruction); var returnsSize = numberOfValuesToReturn(instance, instruction); frame.pushCtrl(instruction.opcode(), paramsSize, returnsSize, stack.size() - paramsSize); diff --git a/runtime/src/test/java/run/endive/runtime/WasmModuleTest.java b/runtime/src/test/java/run/endive/runtime/WasmModuleTest.java index b38908ab8..da2e202da 100644 --- a/runtime/src/test/java/run/endive/runtime/WasmModuleTest.java +++ b/runtime/src/test/java/run/endive/runtime/WasmModuleTest.java @@ -58,6 +58,22 @@ public void shouldRunABasicAdd() { assertEquals(11L, result); } + @Test + public void shouldWrapI32MulOverflow() { + var instance = Instance.builder(loadModule("compiled/i32_mul_overflow.wat.wasm")).build(); + var mul = instance.export("mul"); + var mulIf = instance.export("mul_if"); + + // 65536 * 65536 = 2^32, which wraps to 0 as an i32 + assertEquals(0L, mul.apply(65536L, 65536L)[0]); + assertEquals(0L, mulIf.apply(65536L, 65536L)[0]); + + assertEquals(6L, mul.apply(2L, 3L)[0]); + assertEquals(1L, mulIf.apply(2L, 3L)[0]); + assertEquals(-6L, mul.apply(-2L, 3L)[0]); + assertEquals(1L, mulIf.apply(-2L, 3L)[0]); + } + @Test public void shouldSupportBrTable() { var instance = Instance.builder(loadModule("compiled/br_table.wat.wasm")).build(); diff --git a/wasm-corpus/src/main/resources/compiled/i32_mul_overflow.wat.wasm b/wasm-corpus/src/main/resources/compiled/i32_mul_overflow.wat.wasm new file mode 100644 index 0000000000000000000000000000000000000000..61bf93c74d4a10b7cff77259386127b7cf8c6988 GIT binary patch literal 93 zcmXZNu?m176a~