3
0
mirror of https://github.com/Qortal/AT.git synced 2025-01-30 19:02:14 +00:00

More tests (now in org.ciyam.at), better exception messages, tidying, tightened visibilty.

Added unit test to cover branching to beyond end of code segment.
Added unit test to cover branching to before start of code segment.

Added very naive fuzzy disassembly test to see how it handles random, invalid code.

Refactored data address checking in FunctionCode.postCheckExecute() methods to
single FunctionCode.checkDataAddress method. New method includes FunctionCode's name
when throwing due to out-of-bounds address.

Tidied narrowing conversions by replacing literal 0x7fffffffL with Integer.MAX_VALUE.

Tightened OpCode methods visiblity from public to protected.
Added branch target checking to OpCode.executeBranchConditional but maybe this is
already covered by call to Utils.getCodeOffset() when assembling params in Opcode.execute().
Improved message in Utils.getCodeOffset() anyway.

Moved unit tests to org.ciyam.at package.
Moved unit test support classes from 'common' to org.ciyam.at.test.
This commit is contained in:
catbref 2020-04-09 12:05:27 +01:00
parent 36008bdeac
commit 6e9198b226
19 changed files with 189 additions and 134 deletions

View File

@ -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));
}
}

View File

@ -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<Byte, OpCode> 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<Object> args = new ArrayList<>();
@ -914,7 +914,7 @@ public enum OpCode {
* - typically a lambda operating on two <tt>long</tt> params, e.g. <tt>(a, b) -> a + b</tt>
* @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 <tt>long</tt> params, e.g. <tt>(a, b) -> a == b</tt>
* @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);

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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");
}
}

View File

@ -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();

View File

@ -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.";

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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;

View File

@ -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

View File

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.nio.ByteBuffer;
import java.security.Security;

View File

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;

View File

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import org.ciyam.at.LoggerInterface;

View File

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.math.BigInteger;
import java.nio.ByteBuffer;