Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import run.endive.runtime.CompiledModule;
import run.endive.runtime.Instance;
import run.endive.runtime.Machine;
import run.endive.wasm.MalformedException;
import run.endive.wasm.Parser;
import run.endive.wasm.WasmModule;
import run.endive.wasm.WasmWriter;
Expand Down Expand Up @@ -155,7 +156,9 @@ public void generateMetaWasm(Set<Integer> interpretedFunctions) throws IOExcepti
int count = module.codeSection().functionBodyCount();
writeVarUInt32(out, count);
var actual = readVarUInt32(source);
assert count == actual;
if (count != actual) {
throw new MalformedException("wrong number of function bodies");
}
for (int i = 0; i < count; i++) {
var funcId = importFuncs + i;
if (interpretedFunctions.contains(funcId)) {
Expand All @@ -177,7 +180,10 @@ public void generateMetaWasm(Set<Integer> interpretedFunctions) throws IOExcepti
var bodySize = (int) readVarUInt32(source);
source.position(source.position() + bodySize - 1);
var end_op = source.get();
assert end_op == OpCode.END.opcode();
if (end_op != OpCode.END.opcode()) {
throw new MalformedException(
"unexpected end opcode: " + end_op);
}

// Write an empty function body
writeVarUInt32(out, 3); // function size in bytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import run.endive.runtime.Instance;
import run.endive.runtime.OpCodeIdentifier;
import run.endive.runtime.WasmException;
import run.endive.wasm.WasmEngineException;
import run.endive.wasm.WasmModule;
import run.endive.wasm.types.FunctionType;
import run.endive.wasm.types.ValType;
Expand Down Expand Up @@ -104,13 +105,15 @@ public static ValType valType(long id, Context ctx) {
}

private static void assertTempSlotInRange(Context ctx, int slotsNeeded) {
assert ctx.tempSlot() + slotsNeeded <= ctx.trySaveBaseSlot()
: "temp slot overflow: need "
+ slotsNeeded
+ " slots at "
+ ctx.tempSlot()
+ " but try-save starts at "
+ ctx.trySaveBaseSlot();
if (ctx.tempSlot() + slotsNeeded > ctx.trySaveBaseSlot()) {
throw new WasmEngineException(
"temp slot overflow: need "
+ slotsNeeded
+ " slots at "
+ ctx.tempSlot()
+ " but try-save starts at "
+ ctx.trySaveBaseSlot());
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ public ValType getType() {
}

public void setValue(Value value) {
assert (value.type() == valType);
if (value.type() != valType) {
throw new IllegalArgumentException(
"Value has wrong type; expected " + valType + " got " + value.type());
}
this.valueLow = value.raw();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3215,7 +3215,7 @@ protected static StackFrame THROW_REF(
frame = callStack.peek(); // peek, don't pop - keep catcher on callStack
}
}
throw new RuntimeException("unreacheable");
throw new RuntimeException("unreachable");
}

private static void BLOCK(
Expand Down
9 changes: 6 additions & 3 deletions runtime/src/main/java/run/endive/runtime/OpcodeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -917,9 +917,12 @@ public static long unboxFromTable(int tableValue, Instance instance, ValType ele
impl = java.lang.invoke.VarHandle::fullFence;
} catch (NoSuchMethodError e) {
try {
// Suppress IntelliJ warning about module-info.java needing `requires jdk.unsupported` for
// `sun.misc.Unsafe`. This code here is only a fallback when `VarHandle::fullFence` is unavailable,
// which is only the case for Java < 9 (and therefore module-info.java is irrelevant).
// Suppress IntelliJ warning about module-info.java needing `requires
// jdk.unsupported` for
// `sun.misc.Unsafe`. This code here is only a fallback when `VarHandle::fullFence`
// is unavailable,
// which is only the case for Java < 9 (and therefore module-info.java is
// irrelevant).
@SuppressWarnings("Java9ReflectionClassVisibility")
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
var theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
Expand Down
4 changes: 3 additions & 1 deletion wasm/src/main/java/run/endive/wasm/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,9 @@ private static TableSection parseTableSection(ByteBuffer buffer, TypeSection typ
var firstByte = (int) readVarUInt32(buffer);
if (firstByte == 0x40) {
var secondByte = readVarUInt32(buffer);
assert secondByte == 0x00;
if (secondByte != 0x00) {
throw new MalformedException("incorrect second byte");
}
var tableType = readValueType(buffer, typeSection);
var limits = readTableLimits(buffer);
var init = parseExpression(buffer);
Expand Down
4 changes: 3 additions & 1 deletion wasm/src/main/java/run/endive/wasm/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,9 @@ void validateFunction(int funcIdx, FunctionBody body, FunctionType functionType)
}
var type = module.typeSection().getType(getTagType(tagNumber).typeIdx());
popVals(type.params());
assert (type.returns().size() == 0);
if (!type.returns().isEmpty()) {
throw new InvalidException("expected no returns");
}
unreachable();
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;

import run.endive.wasm.InvalidException;

/*
Expand Down Expand Up @@ -156,10 +155,14 @@ public AnnotatedInstruction build() {
case END:
case IF:
case TRY_TABLE:
assert (scope.isPresent());
if (scope.isEmpty()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the records: those were asserts in first place as they would detect bugs in the calculation/labelling of the Control Flow instructions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean all of the asserts? Because during fuzzing I encountered a case where assert (labelFalse.isEmpty()); failed. Here is the reproducer (unfortunately not minimal):

AnnotatedInstruction.class.getClassLoader().setDefaultAssertionStatus(true);
byte[] bytes = Base64.getDecoder().decode("AGFzbQEAAAABGAJgB39/f39/f38Bf2AIf39/f39/f38BfwMEAwAAAQcFAQFmAAAKSgMSACAAIAEgAiADIAQgBSAGEAELGwAgACABIAIgA0EfcUGAAXJBACAEUwUgBhICCxkAIAAgAWogApogA2ogBGogBWogBmogB2oL");
Parser.parse(bytes);

I guess the Wasm code is invalid, wasm2wat fails for it, but it should nonetheless not cause an AssertionError.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For that reproducer, maybe the problem is here:

case ELSE:
{
currentControlFlow
.instruction()
.withLabelFalse(instructions.size() + 1);
currentControlFlow.addCallback(instruction::withLabelTrue);
break;
}

It seems for ELSE it just assumes that the currentControlFlow is the corresponding IF (or are there other cases where ELSE is valid?) without actually checking it. But for the reproducer above currentControlFlow is actually LOCAL_GET (the first instruction).

throw new InvalidException("unknown scope");
}
break;
default:
assert (scope.isEmpty());
if (scope.isPresent()) {
throw new InvalidException("scope is not empty");
}
break;
}
switch (base.opcode()) {
Expand All @@ -180,8 +183,9 @@ public AnnotatedInstruction build() {
}
break;
default:
assert (labelTrue.isEmpty());
assert (labelFalse.isEmpty());
if (!(labelTrue.isEmpty() && labelFalse.isEmpty())) {
throw new InvalidException("labels are not empty");
}
break;
}
switch (base.opcode()) {
Expand All @@ -191,7 +195,9 @@ public AnnotatedInstruction build() {
}
break;
default:
assert (labelTable.isEmpty());
if (labelTable.isPresent()) {
throw new InvalidException("label table is not empty");
}
break;
}
switch (base.opcode()) {
Expand All @@ -201,7 +207,9 @@ public AnnotatedInstruction build() {
}
break;
default:
assert (catches.isEmpty());
if (catches.isPresent()) {
throw new InvalidException("catches is not empty");
}
break;
}

Expand Down
5 changes: 4 additions & 1 deletion wasm/src/main/java/run/endive/wasm/types/CatchOpCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import run.endive.wasm.WasmEngineException;

public enum CatchOpCode {
CATCH(0x00),
Expand Down Expand Up @@ -98,7 +99,9 @@ public static List<Catch> decode(long[] operands) {
}
}
}
assert (result.size() == length);
if (result.size() != length) {
throw new WasmEngineException("wrong result size");
}
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.List;
import java.util.Optional;
import java.util.function.ToIntFunction;
import run.endive.wasm.WasmEngineException;

/**
* The "name" custom section.
Expand Down Expand Up @@ -74,7 +75,9 @@ public static NameCustomSection parse(byte[] bytes) {
// todo: IDs 4 and 10 are reserved for the Host GC spec
switch (id) {
case 0:
assert (moduleName == null);
if (moduleName != null) {
throw new WasmEngineException("duplicate module name");
}
moduleName = readName(slice);
break;
case 1:
Expand Down
4 changes: 3 additions & 1 deletion wasm/src/main/java/run/endive/wasm/types/RecType.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ public boolean isLegacy() {
}

public FunctionType legacy() {
assert subTypes.length == 1;
if (!isLegacy()) {
throw new IllegalStateException("type is not legacy");
}
return subTypes[0].compType().funcType();
}

Expand Down
17 changes: 12 additions & 5 deletions wasm/src/main/java/run/endive/wasm/types/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,30 @@ public static Value fromFloat(float data) {
return Value.f32(floatToLong(data));
}

private void expectType(ValType expected) {
if (type != expected) {
throw new IllegalStateException(
"Expected value to have type " + expected + " but is " + type);
}
}

public int asInt() {
assert (type == ValType.I32);
expectType(ValType.I32);
return (int) data;
}

public long asLong() {
assert (type == ValType.I64);
expectType(ValType.I64);
return data;
}

public float asFloat() {
assert (type == ValType.F32);
expectType(ValType.F32);
return longToFloat(data);
}

public double asDouble() {
assert (type == ValType.F64);
expectType(ValType.F64);
return longToDouble(data);
}

Expand Down Expand Up @@ -332,7 +339,7 @@ public String toString() {
case ValType.ID.RefNull:
return "refnull[" + (int) data + "]";
default:
throw new AssertionError("Unhandled type: " + type);
return data + "@" + type;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void roundtrip() {
for (var vt : cases) {
long id = vt.id();
ValType roundTrip = ValType.builder().fromId(id).build();
assert vt.equals(roundTrip) : "Failed to roundtrip: " + vt;
assertEquals(vt, roundTrip);
}
}

Expand Down
Loading