GP-6654: Fix state.get/setVar(size=0)

This commit is contained in:
Dan
2026-04-21 15:03:26 +00:00
parent 9c066df19d
commit 16f720139f
6 changed files with 110 additions and 0 deletions
@@ -761,6 +761,9 @@ public enum TraceEmulationIntegration {
value)) { value)) {
return; return;
} }
if (length == 0) {
return;
}
Address end = address.addWrap(length - 1); Address end = address.addWrap(length - 1);
if (address.compareTo(end) <= 0) { if (address.compareTo(end) <= 0) {
written.add(address, end); written.add(address, end);
@@ -32,6 +32,7 @@ import ghidra.pcode.emu.PcodeEmulator;
import ghidra.pcode.emu.PcodeThread; import ghidra.pcode.emu.PcodeThread;
import ghidra.pcode.exec.*; import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason; import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
import ghidra.pcode.exec.trace.TraceEmulationIntegration.TraceWriter;
import ghidra.pcode.exec.trace.TraceEmulationIntegration.Writer; import ghidra.pcode.exec.trace.TraceEmulationIntegration.Writer;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRangeImpl; import ghidra.program.model.address.AddressRangeImpl;
@@ -55,6 +56,74 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
return new PcodeEmulator(platform.getLanguage(), writer.callbacks()); return new PcodeEmulator(platform.getLanguage(), writer.callbacks());
} }
@Test
public void testSetVarSize0() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
initTrace(tb, """
RIP = 0x00400000;
""",
List.of());
Writer writer = createWriter(tb.host, 0);
PcodeEmulator emu = createEmulator(tb.host, writer);
emu.getSharedState().setVar(tb.addr(0x00400000), 0, false, tb.arr());
TraceWriter tw = (TraceWriter) writer;
assertEquals(tb.set(), tw.memWritten);
}
}
@Test
public void testGetVarSize0Uninit() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
initTrace(tb, """
RIP = 0x00400000;
""",
List.of());
Writer writer = createWriter(tb.host, 0);
PcodeEmulator emu = createEmulator(tb.host, writer);
PcodeExecutorState<byte[]> state = emu.getSharedState();
Address addr = tb.addr(0x00400000);
byte[] result = state.getVar(addr, 0, false, Reason.EXECUTE_READ);
assertArrayEquals(new byte[0], result);
assertNull(state.getNextEntryInternal(addr.getAddressSpace(), 0));
}
}
@Test
public void testGetVarSize0Init() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
// Put some known data in a place likely to show in erroneous "uninitialized" set
initTrace(tb, """
RIP = 0x00400000;
*:8 RIP = 0xdeadbeefcafeface;
""",
List.of());
Writer writer = createWriter(tb.host, 0);
PcodeEmulator emu = createEmulator(tb.host, writer);
PcodeExecutorState<byte[]> state = emu.getSharedState();
Address addr = tb.addr(0x00400000);
state.setVar(addr, 4, false, tb.arr(1, 2, 3, 4));
var entry = state.getNextEntryInternal(addr.getAddressSpace(), 0);
assertEquals(0x00400000L, entry.getKey().longValue());
assertArrayEquals(tb.arr(1, 2, 3, 4), entry.getValue());
assertNull(state.getNextEntryInternal(addr.getAddressSpace(), 0x00400004));
byte[] result = state.getVar(addr, 0, false, Reason.EXECUTE_READ);
assertArrayEquals(tb.arr(), result);
entry = state.getNextEntryInternal(addr.getAddressSpace(), 0);
assertEquals(0x00400000L, entry.getKey().longValue());
assertArrayEquals(tb.arr(1, 2, 3, 4), entry.getValue());
assertNull(state.getNextEntryInternal(addr.getAddressSpace(), 0x00400004));
}
}
/** /**
* Test a single instruction * Test a single instruction
* *
@@ -16,6 +16,7 @@
package ghidra.pcode.exec; package ghidra.pcode.exec;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream; import java.util.stream.Stream;
import ghidra.pcode.exec.PcodeArithmetic.Purpose; import ghidra.pcode.exec.PcodeArithmetic.Purpose;
@@ -103,4 +104,9 @@ public abstract class AbstractPcodeExecutorState<A, T> implements PcodeExecutorS
public void clear() { public void clear() {
piece.clear(); piece.clear();
} }
@Override
public Entry<Long, T> getNextEntryInternal(AddressSpace space, long offset) {
return piece.getNextEntryInternal(space, offset);
}
} }
@@ -15,6 +15,12 @@
*/ */
package ghidra.pcode.exec; package ghidra.pcode.exec;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import generic.ULongSpan;
import generic.ULongSpan.ULongSpanSet;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
@@ -45,4 +51,24 @@ public class BytesPcodeExecutorStatePiece
protected BytesPcodeExecutorStateSpace newSpace(AddressSpace space) { protected BytesPcodeExecutorStateSpace newSpace(AddressSpace space) {
return new BytesPcodeExecutorStateSpace(language, space, this); return new BytesPcodeExecutorStateSpace(language, space, this);
} }
@Override
public Entry<Long, byte[]> getNextEntryInternal(AddressSpace space, long offset) {
BytesPcodeExecutorStateSpace s = getForSpace(space, false);
if (s == null) {
return null;
}
ULongSpanSet initialized = s.bytes.getInitialized(0, -1);
ULongSpan span = initialized.spanContaining(offset);
if (span == null) {
var it = initialized.intersecting(ULongSpan.span(offset, -1)).iterator();
if (!it.hasNext()) {
return null;
}
span = it.next();
}
byte[] data = new byte[(int) span.length()];
s.bytes.getData(span.min(), data);
return Map.entry(span.min(), data);
}
} }
@@ -180,6 +180,9 @@ public class BytesPcodeExecutorStateSpace {
* @return the uninitialized offset ranges * @return the uninitialized offset ranges
*/ */
protected AddressSetView computeUninitialized(long offset, int size) { protected AddressSetView computeUninitialized(long offset, int size) {
if (size == 0) {
return new AddressSet();
}
long max = offset + size - 1; long max = offset + size - 1;
if (Long.compareUnsigned(max, space.getMaxAddress().getOffset()) <= 0 && if (Long.compareUnsigned(max, space.getMaxAddress().getOffset()) <= 0 &&
Long.compareUnsigned(offset, max) <= 0) { Long.compareUnsigned(offset, max) <= 0) {
@@ -55,6 +55,9 @@ public interface PcodeStateCallbacks {
* @return the address set * @return the address set
*/ */
static AddressSet rngSet(AddressSpace space, long offset, int length) { static AddressSet rngSet(AddressSpace space, long offset, int length) {
if (length == 0) {
return new AddressSet();
}
Address min = space.getAddress(offset); Address min = space.getAddress(offset);
return new AddressSet(min, min.add(length - 1)); return new AddressSet(min, min.add(length - 1));
} }