diff --git a/Java/src/main/java/org/ciyam/at/FunctionCode.java b/Java/src/main/java/org/ciyam/at/FunctionCode.java index 307f9a9..c0bdac9 100644 --- a/Java/src/main/java/org/ciyam/at/FunctionCode.java +++ b/Java/src/main/java/org/ciyam/at/FunctionCode.java @@ -121,10 +121,9 @@ public enum FunctionCode { @Override protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException { // Validate data offset in arg1 - if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3) - throw new ExecutionException(this.name() + " data start address out of bounds"); + checkDataAddress(state, functionData.value1, 4); - int dataIndex = (int) (functionData.value1 & 0x7fffffffL); + int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE); state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.a1); state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.a2); @@ -140,10 +139,9 @@ public enum FunctionCode { @Override protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException { // Validate data offset in arg1 - if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3) - throw new ExecutionException(this.name() + " data start address out of bounds"); + checkDataAddress(state, functionData.value1, 4); - int dataIndex = (int) (functionData.value1 & 0x7fffffffL); + int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE); state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.b1); state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.b2); @@ -283,10 +281,9 @@ public enum FunctionCode { @Override protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException { // Validate data offset in arg1 - if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3) - throw new ExecutionException(this.name() + " data start address out of bounds"); + checkDataAddress(state, functionData.value1, 4); - int dataIndex = (int) (functionData.value1 & 0x7fffffffL); + int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE); state.a1 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE); state.a2 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE); @@ -302,10 +299,9 @@ public enum FunctionCode { @Override protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException { // Validate data offset in arg1 - if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3) - throw new ExecutionException(this.name() + " data start address out of bounds"); + checkDataAddress(state, functionData.value1, 4); - int dataIndex = (int) (functionData.value1 & 0x7fffffffL); + int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE); state.b1 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE); state.b2 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE); @@ -1081,15 +1077,14 @@ public enum FunctionCode { protected byte[] getHashData(FunctionData functionData, MachineState state) throws ExecutionException { // Validate data offset in arg1 - if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages) - throw new ExecutionException(this.name() + " data start address out of bounds"); + checkDataAddress(state, functionData.value1, 1); // Validate data length in arg2 - if (functionData.value2 < 0L || functionData.value2 > Integer.MAX_VALUE || functionData.value1 + byteLengthToDataLength(functionData.value2) > state.numDataPages) + if (functionData.value2 < 0L || functionData.value2 > state.numDataPages || functionData.value1 + byteLengthToDataLength(functionData.value2) > state.numDataPages) throw new ExecutionException(this.name() + " data length invalid"); - final int dataStart = (int) (functionData.value1 & 0x7fffffffL); - final int dataLength = (int) (functionData.value2 & 0x7fffffffL); + final int dataStart = (int) (functionData.value1 & Integer.MAX_VALUE); + final int dataLength = (int) (functionData.value2 & Integer.MAX_VALUE); byte[] message = new byte[dataLength]; @@ -1104,7 +1099,15 @@ public enum FunctionCode { /** Returns the number of data-page values to contain specific length of bytes. */ protected int byteLengthToDataLength(long byteLength) { - return (MachineState.VALUE_SIZE - 1 + (int) (byteLength & 0x7fffffffL)) / MachineState.VALUE_SIZE; + return (MachineState.VALUE_SIZE - 1 + (int) (byteLength & Integer.MAX_VALUE)) / MachineState.VALUE_SIZE; + } + + /** Check that data segment address (+ subsequent locations) are within data segment bounds. */ + protected void checkDataAddress(MachineState state, long address, int count) throws ExecutionException { + final int maxAddress = state.numDataPages - count; + + if (address < 0L || address > maxAddress) + throw new ExecutionException(String.format("%s data address %d out of bounds: 0 to %d", this.name(), address, maxAddress)); } } diff --git a/Java/src/main/java/org/ciyam/at/OpCode.java b/Java/src/main/java/org/ciyam/at/OpCode.java index 935201e..574728f 100644 --- a/Java/src/main/java/org/ciyam/at/OpCode.java +++ b/Java/src/main/java/org/ciyam/at/OpCode.java @@ -39,7 +39,7 @@ public enum OpCode { */ NOP(0x7f) { @Override - public void executeWithParams(MachineState state, Object... args) { + protected void executeWithParams(MachineState state, Object... args) { // Do nothing } }, @@ -50,7 +50,7 @@ public enum OpCode { */ SET_VAL(0x01, OpCodeParam.DEST_ADDR, OpCodeParam.VALUE) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = (long) args[1]; @@ -64,7 +64,7 @@ public enum OpCode { */ SET_DAT(0x02, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; @@ -79,7 +79,7 @@ public enum OpCode { */ CLR_DAT(0x03, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; state.dataByteBuffer.putLong(address, 0L); @@ -92,7 +92,7 @@ public enum OpCode { */ INC_DAT(0x04, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -106,7 +106,7 @@ public enum OpCode { */ DEC_DAT(0x05, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -120,7 +120,7 @@ public enum OpCode { */ ADD_DAT(0x06, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a + b, args); } }, @@ -131,7 +131,7 @@ public enum OpCode { */ SUB_DAT(0x07, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a - b, args); } }, @@ -142,7 +142,7 @@ public enum OpCode { */ MUL_DAT(0x08, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a * b, args); } }, @@ -154,7 +154,7 @@ public enum OpCode { */ DIV_DAT(0x09, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { try { executeDataOperation(state, (a, b) -> a / b, args); } catch (ArithmeticException e) { @@ -169,7 +169,7 @@ public enum OpCode { */ BOR_DAT(0x0a, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a | b, args); } }, @@ -180,7 +180,7 @@ public enum OpCode { */ AND_DAT(0x0b, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a & b, args); } }, @@ -191,7 +191,7 @@ public enum OpCode { */ XOR_DAT(0x0c, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeDataOperation(state, (a, b) -> a ^ b, args); } }, @@ -202,7 +202,7 @@ public enum OpCode { */ NOT_DAT(0x0d, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -216,7 +216,7 @@ public enum OpCode { */ SET_IND(0x0e, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; @@ -236,7 +236,7 @@ public enum OpCode { */ SET_IDX(0x0f, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR_WITH_INDEX, OpCodeParam.INDEX) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; int address3 = (int) args[2]; @@ -261,7 +261,7 @@ public enum OpCode { */ PSH_DAT(0x10, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -284,7 +284,7 @@ public enum OpCode { */ POP_DAT(0x11, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; try { @@ -308,7 +308,7 @@ public enum OpCode { */ JMP_SUB(0x12, OpCodeParam.CODE_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; try { @@ -331,7 +331,7 @@ public enum OpCode { */ RET_SUB(0x13) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { try { int returnAddress = state.callStackByteBuffer.getInt(); @@ -351,7 +351,7 @@ public enum OpCode { */ IND_DAT(0x14, OpCodeParam.INDIRECT_DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; @@ -371,7 +371,7 @@ public enum OpCode { */ IDX_DAT(0x15, OpCodeParam.INDIRECT_DEST_ADDR_WITH_INDEX, OpCodeParam.INDEX, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; int address3 = (int) args[2]; @@ -395,7 +395,7 @@ public enum OpCode { */ MOD_DAT(0x16, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { try { executeDataOperation(state, (a, b) -> a % b, args); } catch (ArithmeticException e) { @@ -412,7 +412,7 @@ public enum OpCode { private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8L; @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { // If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a << b, args); } @@ -427,7 +427,7 @@ public enum OpCode { private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8L; @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { // If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a >>> b, args); } @@ -439,7 +439,7 @@ public enum OpCode { */ JMP_ADR(0x1a, OpCodeParam.CODE_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; state.codeByteBuffer.position(address); @@ -453,7 +453,7 @@ public enum OpCode { */ BZR_DAT(0x1b, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; byte offset = (byte) args[1]; @@ -476,7 +476,7 @@ public enum OpCode { */ BNZ_DAT(0x1e, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; byte offset = (byte) args[1]; @@ -499,7 +499,7 @@ public enum OpCode { */ BGT_DAT(0x1f, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a > b, args); } }, @@ -511,7 +511,7 @@ public enum OpCode { */ BLT_DAT(0x20, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a < b, args); } }, @@ -523,7 +523,7 @@ public enum OpCode { */ BGE_DAT(0x21, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a >= b, args); } }, @@ -535,7 +535,7 @@ public enum OpCode { */ BLE_DAT(0x22, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a <= b, args); } }, @@ -547,7 +547,7 @@ public enum OpCode { */ BEQ_DAT(0x23, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a == b, args); } }, @@ -559,7 +559,7 @@ public enum OpCode { */ BNE_DAT(0x24, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { executeBranchConditional(state, (a, b) -> a != b, args); } }, @@ -571,7 +571,7 @@ public enum OpCode { */ SLP_DAT(0x25, OpCodeParam.BLOCK_HEIGHT) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.codeByteBuffer.getLong(address); @@ -587,7 +587,7 @@ public enum OpCode { */ FIZ_DAT(0x26, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -603,7 +603,7 @@ public enum OpCode { */ STZ_DAT(0x27, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; long value = state.dataByteBuffer.getLong(address); @@ -621,7 +621,7 @@ public enum OpCode { */ FIN_IMD(0x28) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { state.setIsFinished(true); } }, @@ -632,7 +632,7 @@ public enum OpCode { */ STP_IMD(0x29) { @Override - public void executeWithParams(MachineState state, Object... args) { + protected void executeWithParams(MachineState state, Object... args) { state.setIsStopped(true); } }, @@ -643,7 +643,7 @@ public enum OpCode { */ SLP_IMD(0x2a) { @Override - public void executeWithParams(MachineState state, Object... args) { + protected void executeWithParams(MachineState state, Object... args) { state.setSleepUntilHeight(state.getCurrentBlockHeight() + 1); state.setIsSleeping(true); } @@ -655,7 +655,7 @@ public enum OpCode { */ ERR_ADR(0x2b, OpCodeParam.CODE_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { int address = (int) args[0]; state.setOnErrorAddress(address); @@ -669,7 +669,7 @@ public enum OpCode { */ SET_PCS(0x30) { @Override - public void executeWithParams(MachineState state, Object... args) { + protected void executeWithParams(MachineState state, Object... args) { state.setOnStopAddress(state.codeByteBuffer.position()); } }, @@ -680,7 +680,7 @@ public enum OpCode { */ EXT_FUN(0x32, OpCodeParam.FUNC) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode); @@ -702,7 +702,7 @@ public enum OpCode { */ EXT_FUN_DAT(0x33, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; int address = (int) args[1]; @@ -727,7 +727,7 @@ public enum OpCode { */ EXT_FUN_DAT_2(0x34, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; int address1 = (int) args[1]; int address2 = (int) args[2]; @@ -754,7 +754,7 @@ public enum OpCode { */ EXT_FUN_RET(0x35, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; int address = (int) args[1]; @@ -782,7 +782,7 @@ public enum OpCode { */ EXT_FUN_RET_DAT(0x36, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; int address1 = (int) args[1]; int address2 = (int) args[2]; @@ -813,7 +813,7 @@ public enum OpCode { */ EXT_FUN_RET_DAT_2(0x37, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) { @Override - public void executeWithParams(MachineState state, Object... args) throws ExecutionException { + protected void executeWithParams(MachineState state, Object... args) throws ExecutionException { short rawFunctionCode = (short) args[0]; int address1 = (int) args[1]; int address2 = (int) args[2]; @@ -842,7 +842,7 @@ public enum OpCode { }; public final byte value; - public final OpCodeParam[] params; + private final OpCodeParam[] params; // Create a map of opcode values to OpCode private static final Map map = Arrays.stream(OpCode.values()).collect(Collectors.toMap(opcode -> opcode.value, opcode -> opcode)); @@ -873,7 +873,7 @@ public enum OpCode { * * @throws ExecutionException */ - public abstract void executeWithParams(MachineState state, Object... args) throws ExecutionException; + protected abstract void executeWithParams(MachineState state, Object... args) throws ExecutionException; public void execute(MachineState state) throws ExecutionException { List args = new ArrayList<>(); @@ -914,7 +914,7 @@ public enum OpCode { * - typically a lambda operating on two long params, e.g. (a, b) -> a + b * @throws ExecutionException */ - private static void executeDataOperation(MachineState state, TwoValueOperator operator, Object... args) throws ExecutionException { + protected void executeDataOperation(MachineState state, TwoValueOperator operator, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; @@ -936,13 +936,16 @@ public enum OpCode { * - typically a lambda comparing two long params, e.g. (a, b) -> a == b * @throws ExecutionException */ - private static void executeBranchConditional(MachineState state, TwoValueComparator comparator, Object... args) throws ExecutionException { + protected void executeBranchConditional(MachineState state, TwoValueComparator comparator, Object... args) throws ExecutionException { int address1 = (int) args[0]; int address2 = (int) args[1]; byte offset = (byte) args[2]; int branchTarget = state.getProgramCounter() + offset; + if (branchTarget < 0 || branchTarget >= state.codeByteBuffer.limit()) + throw new InvalidAddressException("branch target out of bounds"); + long value1 = state.dataByteBuffer.getLong(address1); long value2 = state.dataByteBuffer.getLong(address2); diff --git a/Java/src/main/java/org/ciyam/at/Utils.java b/Java/src/main/java/org/ciyam/at/Utils.java index 42e3dba..6b965e4 100644 --- a/Java/src/main/java/org/ciyam/at/Utils.java +++ b/Java/src/main/java/org/ciyam/at/Utils.java @@ -94,10 +94,12 @@ public class Utils { */ public static byte getCodeOffset(ByteBuffer codeByteBuffer) throws CodeSegmentException, InvalidAddressException { try { - byte offset = codeByteBuffer.get(); + final byte offset = codeByteBuffer.get(); + final int target = codeByteBuffer.position() + offset; - if (codeByteBuffer.position() + offset < 0 || codeByteBuffer.position() + offset >= codeByteBuffer.limit()) - throw new InvalidAddressException("Code offset out of bounds"); + if (target < 0 || target >= codeByteBuffer.limit() - 1) + throw new InvalidAddressException(String.format("Code target PC+%02x=[%04x] out of bounds: 0x0000 to 0x%04x", + codeByteBuffer.position() - 1, offset, target, codeByteBuffer.limit() - 1 -1)); return offset; } catch (BufferUnderflowException e) { diff --git a/Java/src/test/java/BlockchainFunctionCodeTests.java b/Java/src/test/java/org/ciyam/at/BlockchainFunctionCodeTests.java similarity index 97% rename from Java/src/test/java/BlockchainFunctionCodeTests.java rename to Java/src/test/java/org/ciyam/at/BlockchainFunctionCodeTests.java index f340d64..95ef767 100644 --- a/Java/src/test/java/BlockchainFunctionCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/BlockchainFunctionCodeTests.java @@ -1,3 +1,5 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import java.util.Arrays; @@ -9,38 +11,15 @@ import org.ciyam.at.FunctionCode; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; import org.ciyam.at.Timestamp; +import org.ciyam.at.test.ExecutableTest; +import org.ciyam.at.test.TestAPI; +import org.ciyam.at.test.TestAPI.TestAccount; +import org.ciyam.at.test.TestAPI.TestBlock; +import org.ciyam.at.test.TestAPI.TestTransaction; import org.junit.Test; -import common.ExecutableTest; -import common.TestAPI; -import common.TestAPI.TestAccount; -import common.TestAPI.TestBlock; -import common.TestAPI.TestTransaction; - public class BlockchainFunctionCodeTests extends ExecutableTest { - /** - * GET_BLOCK_TIMESTAMP - * GET_CREATION_TIMESTAMP - * GET_PREVIOUS_BLOCK_TIMESTAMP - * PUT_PREVIOUS_BLOCK_HASH_INTO_A - * PUT_TX_AFTER_TIMESTAMP_INTO_A - * GET_TYPE_FROM_TX_IN_A - * GET_AMOUNT_FROM_TX_IN_A - * GET_TIMESTAMP_FROM_TX_IN_A - * GENERATE_RANDOM_USING_TX_IN_A - * PUT_MESSAGE_FROM_TX_IN_A_INTO_B - * PUT_ADDRESS_FROM_TX_IN_A_INTO_B - * PUT_CREATOR_INTO_B - * GET_CURRENT_BALANCE - * GET_PREVIOUS_BALANCE - * PAY_TO_ADDRESS_IN_B - * PAY_ALL_TO_ADDRESS_IN_B - * PAY_PREVIOUS_TO_ADDRESS_IN_B - * MESSAGE_A_TO_ADDRESS_IN_B - * ADD_MINUTES_TO_TIMESTAMP - */ - @Test public void testGetBlockTimestamp() throws ExecutionException { // Grab block 'timestamp' and save into address 0 diff --git a/Java/src/test/java/BranchingOpCodeTests.java b/Java/src/test/java/org/ciyam/at/BranchingOpCodeTests.java similarity index 93% rename from Java/src/test/java/BranchingOpCodeTests.java rename to Java/src/test/java/org/ciyam/at/BranchingOpCodeTests.java index 063c7c5..828c040 100644 --- a/Java/src/test/java/BranchingOpCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/BranchingOpCodeTests.java @@ -1,11 +1,12 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class BranchingOpCodeTests extends ExecutableTest { @Test @@ -35,6 +36,36 @@ public class BranchingOpCodeTests extends ExecutableTest { assertEquals("Data does not match", 2L, getData(1)); } + @Test + public void testOutOfBoundsForwardsBranch() throws ExecutionException { + int forwardAddr = codeByteBuffer.limit() - 60; // enough room for post-jump code + + codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(forwardAddr); + + codeByteBuffer.position(forwardAddr); + + codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L); + codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(0).put((byte) 80); // way after end + codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(1L); + codeByteBuffer.put(OpCode.FIN_IMD.value); + + execute(true); + + assertTrue(state.getHadFatalError()); + } + + @Test + public void testOutOfBoundsBackwardsBranch() throws ExecutionException { + codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L); + codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(0).put((byte) -80); // way before start + codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(1L); + codeByteBuffer.put(OpCode.FIN_IMD.value); + + execute(true); + + assertTrue(state.getHadFatalError()); + } + @Test public void testBZR_DATtrue() throws ExecutionException { int targetAddr = 0x21; diff --git a/Java/src/test/java/CallStackOpCodeTests.java b/Java/src/test/java/org/ciyam/at/CallStackOpCodeTests.java similarity index 98% rename from Java/src/test/java/CallStackOpCodeTests.java rename to Java/src/test/java/org/ciyam/at/CallStackOpCodeTests.java index b08ba9d..44d94d5 100644 --- a/Java/src/test/java/CallStackOpCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/CallStackOpCodeTests.java @@ -1,12 +1,13 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class CallStackOpCodeTests extends ExecutableTest { @Test diff --git a/Java/src/test/java/DataOpCodeTests.java b/Java/src/test/java/org/ciyam/at/DataOpCodeTests.java similarity index 99% rename from Java/src/test/java/DataOpCodeTests.java rename to Java/src/test/java/org/ciyam/at/DataOpCodeTests.java index a525722..32452e2 100644 --- a/Java/src/test/java/DataOpCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/DataOpCodeTests.java @@ -1,11 +1,12 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class DataOpCodeTests extends ExecutableTest { @Test diff --git a/Java/src/test/java/DisassemblyTests.java b/Java/src/test/java/org/ciyam/at/DisassemblyTests.java similarity index 72% rename from Java/src/test/java/DisassemblyTests.java rename to Java/src/test/java/org/ciyam/at/DisassemblyTests.java index 315dc80..f1b6978 100644 --- a/Java/src/test/java/DisassemblyTests.java +++ b/Java/src/test/java/org/ciyam/at/DisassemblyTests.java @@ -1,16 +1,19 @@ -import static common.TestUtils.hexToBytes; +package org.ciyam.at; + +import static org.ciyam.at.test.TestUtils.hexToBytes; +import static org.junit.Assert.fail; import java.nio.charset.StandardCharsets; +import java.util.Random; import org.ciyam.at.ExecutionException; import org.ciyam.at.FunctionCode; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; +import org.ciyam.at.test.TestUtils; import org.junit.Test; -import common.ExecutableTest; -import common.TestUtils; - public class DisassemblyTests extends ExecutableTest { private static final String message = "The quick, brown fox jumped over the lazy dog."; @@ -55,4 +58,28 @@ public class DisassemblyTests extends ExecutableTest { System.out.println(state.disassemble()); } + @Test + public void testFuzzyDisassembly() { + Random random = new Random(); + + byte[] randomCode = new byte[200]; + random.nextBytes(randomCode); + codeByteBuffer.put(randomCode); + + byte[] headerBytes = TestUtils.HEADER_BYTES; + byte[] codeBytes = codeByteBuffer.array(); + byte[] dataBytes = dataByteBuffer.array(); + + state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes); + + try { + System.out.println(state.disassemble()); + } catch (ExecutionException e) { + // we expect this to fail + return; + } + + fail("Random code should cause disassembly failure"); + } + } diff --git a/Java/src/test/java/FunctionCodeTests.java b/Java/src/test/java/org/ciyam/at/FunctionCodeTests.java similarity index 97% rename from Java/src/test/java/FunctionCodeTests.java rename to Java/src/test/java/org/ciyam/at/FunctionCodeTests.java index 12d979b..be4313b 100644 --- a/Java/src/test/java/FunctionCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/FunctionCodeTests.java @@ -1,3 +1,5 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import java.util.Arrays; @@ -7,10 +9,9 @@ import org.ciyam.at.FunctionCode; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; import org.ciyam.at.Timestamp; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class FunctionCodeTests extends ExecutableTest { private static final byte[] TEST_BYTES = "This string is exactly 32 bytes!".getBytes(); diff --git a/Java/src/test/java/HashingFunctionCodeTests.java b/Java/src/test/java/org/ciyam/at/HashingFunctionCodeTests.java similarity index 97% rename from Java/src/test/java/HashingFunctionCodeTests.java rename to Java/src/test/java/org/ciyam/at/HashingFunctionCodeTests.java index ca5feb9..7d8937a 100644 --- a/Java/src/test/java/HashingFunctionCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/HashingFunctionCodeTests.java @@ -1,4 +1,6 @@ -import static common.TestUtils.hexToBytes; +package org.ciyam.at; + +import static org.ciyam.at.test.TestUtils.hexToBytes; import static org.junit.Assert.*; import java.nio.charset.StandardCharsets; @@ -6,10 +8,9 @@ import java.nio.charset.StandardCharsets; import org.ciyam.at.ExecutionException; import org.ciyam.at.FunctionCode; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class HashingFunctionCodeTests extends ExecutableTest { private static final String message = "The quick, brown fox jumped over the lazy dog."; diff --git a/Java/src/test/java/MiscTests.java b/Java/src/test/java/org/ciyam/at/MiscTests.java similarity index 93% rename from Java/src/test/java/MiscTests.java rename to Java/src/test/java/org/ciyam/at/MiscTests.java index d2fed94..5d41433 100644 --- a/Java/src/test/java/MiscTests.java +++ b/Java/src/test/java/org/ciyam/at/MiscTests.java @@ -1,15 +1,16 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.FunctionCode; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; +import org.ciyam.at.test.TestAPI; +import org.ciyam.at.test.TestUtils; import org.junit.Test; -import common.ExecutableTest; -import common.TestAPI; -import common.TestUtils; - public class MiscTests extends ExecutableTest { @Test diff --git a/Java/src/test/java/OpCodeTests.java b/Java/src/test/java/org/ciyam/at/OpCodeTests.java similarity index 98% rename from Java/src/test/java/OpCodeTests.java rename to Java/src/test/java/org/ciyam/at/OpCodeTests.java index 61ca070..a147b4b 100644 --- a/Java/src/test/java/OpCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/OpCodeTests.java @@ -1,12 +1,13 @@ -import static common.TestUtils.hexToBytes; +package org.ciyam.at; + +import static org.ciyam.at.test.TestUtils.hexToBytes; import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class OpCodeTests extends ExecutableTest { @Test diff --git a/Java/src/test/java/SerializationTests.java b/Java/src/test/java/org/ciyam/at/SerializationTests.java similarity index 96% rename from Java/src/test/java/SerializationTests.java rename to Java/src/test/java/org/ciyam/at/SerializationTests.java index 174c6d5..81d5756 100644 --- a/Java/src/test/java/SerializationTests.java +++ b/Java/src/test/java/org/ciyam/at/SerializationTests.java @@ -1,4 +1,6 @@ -import static common.TestUtils.hexToBytes; +package org.ciyam.at; + +import static org.ciyam.at.test.TestUtils.hexToBytes; import static org.junit.Assert.*; import java.util.Arrays; @@ -7,11 +9,10 @@ import org.ciyam.at.ExecutionException; import org.ciyam.at.FunctionCode; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; +import org.ciyam.at.test.TestUtils; import org.junit.Test; -import common.ExecutableTest; -import common.TestUtils; - public class SerializationTests extends ExecutableTest { private byte[] simulate() { diff --git a/Java/src/test/java/ToolchainTests.java b/Java/src/test/java/org/ciyam/at/ToolchainTests.java similarity index 86% rename from Java/src/test/java/ToolchainTests.java rename to Java/src/test/java/org/ciyam/at/ToolchainTests.java index 64ec535..e66c918 100644 --- a/Java/src/test/java/ToolchainTests.java +++ b/Java/src/test/java/org/ciyam/at/ToolchainTests.java @@ -1,4 +1,6 @@ -import static common.TestUtils.hexToBytes; +package org.ciyam.at; + +import static org.ciyam.at.test.TestUtils.hexToBytes; import static org.junit.Assert.assertTrue; import java.util.Arrays; diff --git a/Java/src/test/java/UserStackOpCodeTests.java b/Java/src/test/java/org/ciyam/at/UserStackOpCodeTests.java similarity index 98% rename from Java/src/test/java/UserStackOpCodeTests.java rename to Java/src/test/java/org/ciyam/at/UserStackOpCodeTests.java index db49724..72a250d 100644 --- a/Java/src/test/java/UserStackOpCodeTests.java +++ b/Java/src/test/java/org/ciyam/at/UserStackOpCodeTests.java @@ -1,12 +1,13 @@ +package org.ciyam.at; + import static org.junit.Assert.*; import org.ciyam.at.ExecutionException; import org.ciyam.at.MachineState; import org.ciyam.at.OpCode; +import org.ciyam.at.test.ExecutableTest; import org.junit.Test; -import common.ExecutableTest; - public class UserStackOpCodeTests extends ExecutableTest { @Test diff --git a/Java/src/test/java/common/ExecutableTest.java b/Java/src/test/java/org/ciyam/at/test/ExecutableTest.java similarity index 99% rename from Java/src/test/java/common/ExecutableTest.java rename to Java/src/test/java/org/ciyam/at/test/ExecutableTest.java index 784c75f..ad4e115 100644 --- a/Java/src/test/java/common/ExecutableTest.java +++ b/Java/src/test/java/org/ciyam/at/test/ExecutableTest.java @@ -1,4 +1,4 @@ -package common; +package org.ciyam.at.test; import java.nio.ByteBuffer; import java.security.Security; diff --git a/Java/src/test/java/common/TestAPI.java b/Java/src/test/java/org/ciyam/at/test/TestAPI.java similarity index 99% rename from Java/src/test/java/common/TestAPI.java rename to Java/src/test/java/org/ciyam/at/test/TestAPI.java index 4728efc..4ed75e5 100644 --- a/Java/src/test/java/common/TestAPI.java +++ b/Java/src/test/java/org/ciyam/at/test/TestAPI.java @@ -1,4 +1,4 @@ -package common; +package org.ciyam.at.test; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; diff --git a/Java/src/test/java/common/TestLogger.java b/Java/src/test/java/org/ciyam/at/test/TestLogger.java similarity index 93% rename from Java/src/test/java/common/TestLogger.java rename to Java/src/test/java/org/ciyam/at/test/TestLogger.java index 509ca39..bec6121 100644 --- a/Java/src/test/java/common/TestLogger.java +++ b/Java/src/test/java/org/ciyam/at/test/TestLogger.java @@ -1,4 +1,4 @@ -package common; +package org.ciyam.at.test; import org.ciyam.at.LoggerInterface; diff --git a/Java/src/test/java/common/TestUtils.java b/Java/src/test/java/org/ciyam/at/test/TestUtils.java similarity index 98% rename from Java/src/test/java/common/TestUtils.java rename to Java/src/test/java/org/ciyam/at/test/TestUtils.java index 1292510..fce6c76 100644 --- a/Java/src/test/java/common/TestUtils.java +++ b/Java/src/test/java/org/ciyam/at/test/TestUtils.java @@ -1,4 +1,4 @@ -package common; +package org.ciyam.at.test; import java.math.BigInteger; import java.nio.ByteBuffer;