mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-196 fixed issue with emulating accessing varnodes in unique space
This commit is contained in:
parent
2ceda07e1d
commit
342ef10c85
4 changed files with 472 additions and 39 deletions
|
@ -310,10 +310,12 @@ public class Emulate {
|
|||
else {
|
||||
takeBranch = memstate.getValue(condVar) != 0;
|
||||
}
|
||||
if (takeBranch)
|
||||
if (takeBranch) {
|
||||
executeBranch(op);
|
||||
else
|
||||
}
|
||||
else {
|
||||
fallthruOp();
|
||||
}
|
||||
}
|
||||
|
||||
/// Since the full instruction is cached, we can do relative branches properly
|
||||
|
@ -324,10 +326,12 @@ public class Emulate {
|
|||
long id = destaddr.getOffset();
|
||||
id = id + current_op;
|
||||
current_op = (int) id;
|
||||
if (current_op == pcode.length)
|
||||
if (current_op == pcode.length) {
|
||||
fallthruOp();
|
||||
else if ((current_op < 0) || (current_op >= pcode.length))
|
||||
}
|
||||
else if ((current_op < 0) || (current_op >= pcode.length)) {
|
||||
throw new LowlevelError("Bad intra-instruction branch");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setCurrentAddress(destaddr);
|
||||
|
@ -451,18 +455,18 @@ public class Emulate {
|
|||
"Unsupported pcode op (opcode=" + op.getOpcode() + ", seq=" + op.getSeqnum() + ")");
|
||||
}
|
||||
if (behave instanceof UnaryOpBehavior) {
|
||||
UnaryOpBehavior uniaryBehave = (UnaryOpBehavior) behave;
|
||||
UnaryOpBehavior unaryBehave = (UnaryOpBehavior) behave;
|
||||
Varnode in1var = op.getInput(0);
|
||||
Varnode outvar = op.getOutput();
|
||||
if (in1var.getSize() > 8 || outvar.getSize() > 8) {
|
||||
BigInteger in1 = memstate.getBigInteger(op.getInput(0), false);
|
||||
BigInteger out = uniaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
BigInteger out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
else {
|
||||
long in1 = memstate.getValue(op.getInput(0));
|
||||
long out = uniaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
long out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,28 @@ import generic.stl.MapSTL;
|
|||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/**
|
||||
* An subclass of {@link MemoryBank} intended for modeling the "unique" memory
|
||||
* space. The space is byte-addressable and paging is not supported.
|
||||
*/
|
||||
public class UniqueMemoryBank extends MemoryBank {
|
||||
|
||||
protected MapSTL<Long, byte[]> map = new ComparableMapSTL<Long, byte[]>();
|
||||
/**A map from {@link Long} offsets to byte values would require many lookups.
|
||||
* As an optimization, this map is defined from {@link Long} values to
|
||||
* {@link WordInfo} objects, each of which represents an eight-byte word
|
||||
* of memory. Each key in this map must be 0 mod 8.
|
||||
*/
|
||||
protected MapSTL<Long, WordInfo> map = new ComparableMapSTL<Long, WordInfo>();
|
||||
|
||||
private static final long ALIGNMENT_MASK = 0xfffffffffffffff8L;
|
||||
|
||||
//note that WordInfo use the bits in a byte to record whether
|
||||
//or not a given byte has been written to, so you can't just
|
||||
//change WORD_SIZE to another value and without also changing
|
||||
//the implementation of WordInfo
|
||||
private static final int WORD_SIZE = 8;
|
||||
|
||||
private byte[] buffer = new byte[WORD_SIZE];
|
||||
|
||||
public UniqueMemoryBank(AddressSpace spc, boolean isBigEndian) {
|
||||
super(spc, isBigEndian, 0, null);
|
||||
|
@ -45,24 +64,93 @@ public class UniqueMemoryBank extends MemoryBank {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getChunk(long addrOffset, int size, byte[] res, boolean ignoreFault) {
|
||||
byte[] value = map.get(addrOffset);
|
||||
if (value == null) {
|
||||
throw new LowlevelError("Unique value read before written: 0x" +
|
||||
Long.toHexString(addrOffset));
|
||||
public int getChunk(long offset, int size, byte[] dest, boolean stopOnUninitialized) {
|
||||
int bytesRead = 0;
|
||||
if (size == 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
if (value.length != size) {
|
||||
throw new LowlevelError("Unique value size mismatch: 0x" + Long.toHexString(addrOffset));
|
||||
try {
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE && bytesRead < size; ++i) {
|
||||
dest[bytesRead++] = word.getByte(i);
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
//copy a word at a time
|
||||
while (size - bytesRead > 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
offset += WORD_SIZE;
|
||||
//whole word is initialized, copy it (or the appropriate
|
||||
//initial segment) all at once
|
||||
int bytesToRead = Math.min(WORD_SIZE, size - bytesRead);
|
||||
if (word.isEntireWordInitialized()) {
|
||||
word.getWord(buffer);
|
||||
System.arraycopy(buffer, 0, dest, bytesRead,
|
||||
Math.min(WORD_SIZE, size - bytesRead));
|
||||
bytesRead += bytesToRead;
|
||||
continue;
|
||||
}
|
||||
//not entirely initialized, copy one byte at a time until
|
||||
//all requested bytes read (or word.getByte throws an exception)
|
||||
int base = bytesRead;
|
||||
for (int i = 0; i < bytesToRead; ++i) {
|
||||
dest[base + i] = word.getByte(i);
|
||||
bytesRead += 1;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
catch (LowlevelError e) {
|
||||
if (stopOnUninitialized) {
|
||||
return bytesRead;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
System.arraycopy(value, 0, res, 0, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunk(long offset, int size, byte[] val) {
|
||||
byte[] value = new byte[size];
|
||||
System.arraycopy(val, 0, value, 0, size);
|
||||
map.put(offset, value);
|
||||
public void setChunk(long offset, int size, byte[] src) {
|
||||
if (size == 0 || src.length == 0) {
|
||||
return;
|
||||
}
|
||||
int currentPosition = 0;
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE; ++i) {
|
||||
word.setByte(src[currentPosition], i);
|
||||
offset += 1;
|
||||
currentPosition += 1;
|
||||
}
|
||||
}
|
||||
while (size > currentPosition) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
int bytesToWrite = Math.min(WORD_SIZE, size - currentPosition);
|
||||
for (int i = 0; i < bytesToWrite; i++) {
|
||||
word.setByte(src[currentPosition + i], i);
|
||||
}
|
||||
offset += bytesToWrite;
|
||||
currentPosition += bytesToWrite;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,4 +160,95 @@ public class UniqueMemoryBank extends MemoryBank {
|
|||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class representing a byte-addressable word of memory. Each
|
||||
* byte can be either initialized to a byte value or uninitialized.
|
||||
* It is an error to attempt to read an uninitialized byte.
|
||||
*/
|
||||
public static class WordInfo {
|
||||
public byte initialized;
|
||||
public long word;
|
||||
|
||||
/**
|
||||
* Constructs a {@link WordInfo} object with all bytes uninitialized.
|
||||
*/
|
||||
public WordInfo() {
|
||||
initialized = 0;
|
||||
word = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the byte at {@code index} and sets its value to
|
||||
* {@code val}
|
||||
* @param val new value
|
||||
* @param index index
|
||||
* @throws LowlevelError if the index is invalid
|
||||
*/
|
||||
public void setByte(byte val, int index) {
|
||||
validateIndex(index);
|
||||
word &= ~(0xffL << (WORD_SIZE * index));
|
||||
long shifted = ((long) val) << (WORD_SIZE * index);
|
||||
word |= shifted;
|
||||
initialized |= (1 << index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte at the given index
|
||||
* @param index index
|
||||
* @return corresponding byte value
|
||||
* @throws LowlevelError if the index is invalid or the requested byte
|
||||
* is not initialized.
|
||||
*/
|
||||
public byte getByte(int index) {
|
||||
validateIndex(index);
|
||||
checkInitialized(index);
|
||||
long selected = word & (0xffL << (WORD_SIZE * index));
|
||||
long adjusted = selected >> (WORD_SIZE * index);
|
||||
return (byte) adjusted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an entire word into {@code buffer}
|
||||
* @param buffer buffer to write a single word to. Must have
|
||||
* length 8.
|
||||
* @throws LowlevelError if the entire word is not initialized
|
||||
*/
|
||||
public void getWord(byte[] buffer) {
|
||||
if (initialized != ((byte) (0xff))) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
if (buffer.length != WORD_SIZE) {
|
||||
throw new IllegalArgumentException("Buffer must have length 8");
|
||||
}
|
||||
for (int i = 0; i < WORD_SIZE; ++i) {
|
||||
buffer[i] = (byte) ((word & (0xffL << (WORD_SIZE * i))) >> (WORD_SIZE * i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true precisely when the entire word is initialized.
|
||||
* @return true if entire work initialized
|
||||
*/
|
||||
protected boolean isEntireWordInitialized() {
|
||||
return initialized == (byte) 0xff;
|
||||
}
|
||||
|
||||
//assumes 0 <= index <= 7
|
||||
private void checkInitialized(int index) {
|
||||
if ((initialized & (1 << (index))) == 0) {
|
||||
throw new LowlevelError(
|
||||
"Attempted to read uninitialized memory in the unique space.");
|
||||
}
|
||||
}
|
||||
|
||||
//ensure that the provided index is valid
|
||||
private void validateIndex(int index) {
|
||||
if (index < 0 || index > 7) {
|
||||
throw new LowlevelError("Invalid index: " + Integer.toString(index));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.memstate.UniqueMemoryBank.WordInfo;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.GenericAddressSpace;
|
||||
|
||||
public class UniqueMemoryBankTest extends AbstractGenericTest {
|
||||
|
||||
private AddressSpace uniqueSpace;
|
||||
private UniqueMemoryBank uniqueBank;
|
||||
private byte[] eightTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 };
|
||||
private byte[] eightZeroBytes = new byte[8];
|
||||
private byte[] sixteenTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
uniqueSpace = new GenericAddressSpace("unique", 64, AddressSpace.TYPE_UNIQUE, 0);
|
||||
uniqueBank = new UniqueMemoryBank(uniqueSpace, false);
|
||||
}
|
||||
|
||||
public UniqueMemoryBankTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void WordInfoBasicTest() {
|
||||
WordInfo info = new WordInfo();
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x0, 0);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x1, 1);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x2, 2);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x3, 3);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x4, 4);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x5, 5);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x6, 6);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x7, 7);
|
||||
assertTrue(info.isEntireWordInitialized());
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
assertEquals((byte) i, info.getByte(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testGetUnitializedByte() {
|
||||
WordInfo info = new WordInfo();
|
||||
info.setByte((byte) 0, 0);
|
||||
info.setByte((byte) 1, 1);
|
||||
info.setByte((byte) 3, 3);
|
||||
info.setByte((byte) 4, 4);
|
||||
info.setByte((byte) 5, 5);
|
||||
info.setByte((byte) 6, 6);
|
||||
info.setByte((byte) 7, 7);
|
||||
@SuppressWarnings("unused")
|
||||
byte val = info.getByte(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRead() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentlySizedReads() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x0, 0x1, 0x2, 0x3 }));
|
||||
numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x4, 0x5, 0x6, 0x7 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeReadWrite() {
|
||||
uniqueBank.setChunk(0x1004, 16, sixteenTestBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
assertTrue(Arrays.equals(dest, sixteenTestBytes));
|
||||
|
||||
byte[] largeSrc = new byte[64];
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
largeSrc[i] = (byte) (i + 1);
|
||||
}
|
||||
uniqueBank.setChunk(0x1007, 64, largeSrc);
|
||||
dest = new byte[64];
|
||||
numBytes = uniqueBank.getChunk(0x1007, 64, dest, true);
|
||||
assertEquals(64, numBytes);
|
||||
assertTrue(Arrays.equals(dest, largeSrc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAcrossUndefined() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1007, 4, fourBytes);
|
||||
uniqueBank.setChunk(0x100c, 4, fourBytes);
|
||||
byte[] dest = new byte[9];
|
||||
int numBytes = uniqueBank.getChunk(0x1007, 9, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertEquals(0x11, dest[0]);
|
||||
assertEquals(0x22, dest[1]);
|
||||
assertEquals(0x33, dest[2]);
|
||||
assertEquals(0x44, dest[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAlignedReadWrite() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1004, 4, fourBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(fourBytes, dest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlappingReadWrite() {
|
||||
uniqueBank.setChunk(0x1000, 16, sixteenTestBytes);
|
||||
uniqueBank.setChunk(0x1004, 8, eightZeroBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i > 3 && i < 12) {
|
||||
assertEquals(0, dest[i]);
|
||||
}
|
||||
else {
|
||||
assertEquals(i, dest[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneByteRead() {
|
||||
byte[] one = new byte[] { (byte) 0x7f };
|
||||
uniqueBank.setChunk(0x1000, 1, one);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 1, dest, false);
|
||||
assertEquals(1, numBytes);
|
||||
assertEquals(dest[0], (byte) 0x7f);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
uniqueBank.clear();
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 7, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 6, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 5, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 3, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 2, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 1, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 0, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOverwrite() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
uniqueBank.setChunk(0x1000, 8, eightZeroBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightZeroBytes));
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testUnitializedReadStop() {
|
||||
byte[] dest = new byte[16];
|
||||
uniqueBank.getChunk(0x1000, 0x10, dest, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnitializedReadContinue() {
|
||||
byte[] dest = new byte[16];
|
||||
int bytesRead = uniqueBank.getChunk(0x1000, 0x10, dest, true);
|
||||
assertEquals(0, bytesRead);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testGetPageException() {
|
||||
MemoryPage page = uniqueBank.getPage(0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageException() {
|
||||
uniqueBank.setPage(0, new byte[0], 0, 4096, 0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageInitializedException() {
|
||||
uniqueBank.setPageInitialized(0, true, 0, 4096, 0);
|
||||
}
|
||||
|
||||
//possibly add:
|
||||
//zero-byte read/write
|
||||
//try to write more bytes than the array has
|
||||
//try to read more bytes into the array than it has
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue