mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-7307 Corrected data type merge conflict fixup
This commit is contained in:
@@ -529,7 +529,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
}
|
||||
sb.append(dt.getDisplayName());
|
||||
sb.append(", ");
|
||||
if (info.resultOrdinal < 0) {
|
||||
if (info.resultIndex < 0) {
|
||||
if (dt instanceof FunctionDefinition) {
|
||||
sb.append("return-type");
|
||||
}
|
||||
@@ -540,25 +540,25 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
else {
|
||||
if (dt instanceof FunctionDefinition) {
|
||||
sb.append("param-");
|
||||
sb.append(info.resultOrdinal);
|
||||
sb.append(info.resultIndex);
|
||||
}
|
||||
else if (dt instanceof Union) {
|
||||
sb.append("component-");
|
||||
sb.append(info.resultOrdinal);
|
||||
sb.append(info.resultIndex);
|
||||
}
|
||||
else if (dt instanceof Structure) {
|
||||
Structure resultStruct = (Structure) info.ht.get(info.id);
|
||||
sb.append("component-");
|
||||
sb.append(info.resultOrdinal);
|
||||
sb.append("defined-component-");
|
||||
sb.append(info.resultIndex);
|
||||
if (!resultStruct.isPackingEnabled()) {
|
||||
sb.append(", offset-");
|
||||
sb.append(", source-offset-");
|
||||
sb.append("0x");
|
||||
sb.append(Integer.toHexString(info.offset));
|
||||
}
|
||||
}
|
||||
else {
|
||||
sb.append("resultOrdinal-"); // unknown use case
|
||||
sb.append(info.resultOrdinal);
|
||||
sb.append("resultIndex-"); // unknown use case
|
||||
sb.append(info.resultIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1234,6 +1234,38 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
return nextOrdinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of a defined component in the structure's defined-component sequence.
|
||||
* Unlike its ordinal, this index is unaffected by changes to implicit undefined bytes.
|
||||
* @param struct destination structure
|
||||
* @param component newly inserted defined component
|
||||
* @return index in the destination's defined-component sequence
|
||||
*/
|
||||
private static int getDefinedComponentIndex(Structure struct, DataTypeComponent component) {
|
||||
if (component.getDataType() == DataType.DEFAULT) {
|
||||
throw new IllegalArgumentException("Expected defined component");
|
||||
}
|
||||
int ordinal = component.getOrdinal();
|
||||
int low = 0;
|
||||
int high = struct.getNumDefinedComponents() - 1;
|
||||
// Defined components have unique, increasing ordinals even when offsets overlap.
|
||||
while (low <= high) {
|
||||
int mid = low + (high - low) / 2;
|
||||
int midOrdinal = struct.getDefinedComponent(mid).getOrdinal();
|
||||
if (midOrdinal < ordinal) {
|
||||
low = mid + 1;
|
||||
}
|
||||
else if (midOrdinal > ordinal) {
|
||||
high = mid - 1;
|
||||
}
|
||||
else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
throw new AssertException(
|
||||
"Expected defined component at ordinal " + ordinal + " in " + struct.getPathName());
|
||||
}
|
||||
|
||||
private void updateStructure(long sourceDtID, Structure sourceDt, Structure destStruct,
|
||||
MyIdentityHashMap<Long, DataType> resolvedDataTypes) {
|
||||
|
||||
@@ -1434,15 +1466,14 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
}
|
||||
}
|
||||
else if (packed) {
|
||||
// Add fixup placeholder to prevent the ordinal values and component sizes from
|
||||
// changing. Nothing we can do about packing which may be affected.
|
||||
// These should get fixed-up later.
|
||||
// Preserve a defined component for later fixup. Packing and dependency size
|
||||
// changes may alter its offset and ordinal, but not its defined-component index.
|
||||
resultComp = destStruct.add(BadDataType.dataType, sourceComp.getLength(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
}
|
||||
else {
|
||||
// Add fixup placeholder to prevent the ordinal values and component sizes from
|
||||
// changing. These should get fixed-up later.
|
||||
// Preserve a defined component and its reserved space for later fixup.
|
||||
// Changes to preceding undefined bytes may alter its ordinal.
|
||||
resultComp = destStruct.insertAtOffset(sourceComp.getOffset(), BadDataType.dataType,
|
||||
sourceComp.getLength(), sourceComp.getFieldName(), comment);
|
||||
}
|
||||
@@ -1450,7 +1481,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
if (fixupRequired) {
|
||||
// Component datatype has not been added/resolved yet, put an entry in the fixup list
|
||||
fixUpList.add(new FixUpInfo(sourceDtID, sourceComponentID,
|
||||
resultComp.getOrdinal(), sourceComp, resolvedDataTypes));
|
||||
getDefinedComponentIndex(destStruct, resultComp), sourceComp, resolvedDataTypes));
|
||||
fixUpIDSet.add(sourceDtID);
|
||||
}
|
||||
}
|
||||
@@ -1607,7 +1638,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Add fixup placeholder to prevent the ordinal values and component sizes from
|
||||
// Add fixup placeholder to prevent the ordinal values and component sizes from
|
||||
// changing. Nothing we can do about packing which may be affected.
|
||||
// These should get fixed-up later.
|
||||
destUnion.add(BadDataType.dataType, sourceComp.getLength(),
|
||||
@@ -2470,7 +2501,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
|
||||
/**
|
||||
* NOTE: It is important that fixups for a Structure are processed bottom-up
|
||||
* (i.e., last-ordinal to first-ordinal) to ensure that subsequent fixup ordinal
|
||||
* (i.e., last defined-component index to first) to ensure that subsequent fixup
|
||||
* indexes remain valid even after components are removed as a result of processing
|
||||
* a Structure fixup.
|
||||
*/
|
||||
@@ -2542,22 +2573,22 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
long lastChangeTime = fd.getLastChangeTime(); // Don't let the time change.
|
||||
try {
|
||||
if (dt != null) {
|
||||
if (info.resultOrdinal < 0) { // -1 for return type
|
||||
if (info.resultIndex < 0) { // -1 for return type
|
||||
fd.setReturnType(dt);
|
||||
}
|
||||
else {
|
||||
ParameterDefinition[] args = fd.getArguments();
|
||||
args[info.resultOrdinal].setDataType(dt);
|
||||
args[info.resultIndex].setDataType(dt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.resultOrdinal < 0) { // -1 for return type
|
||||
if (info.resultIndex < 0) { // -1 for return type
|
||||
// nowhere to set error comment
|
||||
}
|
||||
else {
|
||||
ParameterDefinition[] args = fd.getArguments();
|
||||
ParameterDefinition arg = args[info.resultOrdinal];
|
||||
ParameterDefinition arg = args[info.resultIndex];
|
||||
String comment =
|
||||
buildDataTypeFailureComment(info.componentDataType, null, arg.getComment());
|
||||
arg.setComment(comment);
|
||||
@@ -2577,16 +2608,8 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
* @return false if component not found, else true
|
||||
*/
|
||||
private boolean fixUpPackedStructureComponent(FixUpInfo info, Structure struct, DataType dt) {
|
||||
int ordinal = info.resultOrdinal;
|
||||
|
||||
DataTypeComponent dtc;
|
||||
if (ordinal >= 0 || ordinal < struct.getNumComponents()) {
|
||||
dtc = struct.getComponent(ordinal);
|
||||
}
|
||||
else {
|
||||
throw new AssertException(
|
||||
"Expected fixup component at ordinal " + ordinal + " in " + struct.getPathName());
|
||||
}
|
||||
DataTypeComponent dtc = getStructureFixupComponent(info, struct);
|
||||
int ordinal = dtc.getOrdinal();
|
||||
|
||||
long lastChangeTime = struct.getLastChangeTime(); // Don't let the time change.
|
||||
try {
|
||||
@@ -2674,16 +2697,8 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
private boolean fixUpNonPackedStructureComponent(FixUpInfo info, Structure struct,
|
||||
DataType dt) {
|
||||
|
||||
int ordinal = info.resultOrdinal;
|
||||
|
||||
DataTypeComponent dtc;
|
||||
if (ordinal >= 0 || ordinal < struct.getNumComponents()) {
|
||||
dtc = struct.getComponent(ordinal);
|
||||
}
|
||||
else {
|
||||
throw new AssertException(
|
||||
"Expected fixup component at ordinal " + ordinal + " in " + struct.getPathName());
|
||||
}
|
||||
DataTypeComponent dtc = getStructureFixupComponent(info, struct);
|
||||
int ordinal = dtc.getOrdinal();
|
||||
|
||||
long lastChangeTime = struct.getLastChangeTime(); // Don't let the time change.
|
||||
try {
|
||||
@@ -2760,6 +2775,21 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a fixup after dependency resolution, which may have changed the structure's layout.
|
||||
* Do not retain component instances or ordinals across fixups or packing changes.
|
||||
* @param info fixup identifying a defined component
|
||||
* @param struct current result structure
|
||||
* @return current component to fix up
|
||||
*/
|
||||
private static DataTypeComponent getStructureFixupComponent(FixUpInfo info, Structure struct) {
|
||||
if (info.resultIndex < 0 || info.resultIndex >= struct.getNumDefinedComponents()) {
|
||||
throw new AssertException("Expected fixup component at defined-component index " +
|
||||
info.resultIndex + " in " + struct.getPathName());
|
||||
}
|
||||
return struct.getDefinedComponent(info.resultIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix up the structure using the fix up info for a component.
|
||||
* @param info fixup info
|
||||
@@ -2780,10 +2810,11 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
|
||||
String loc;
|
||||
if (struct.isPackingEnabled()) {
|
||||
loc = "ordinal " + info.resultOrdinal;
|
||||
loc = "defined-component index " + info.resultIndex;
|
||||
}
|
||||
else {
|
||||
loc = "offset 0x" + Integer.toHexString(info.offset);
|
||||
loc = "defined-component index " + info.resultIndex + " (source offset 0x" +
|
||||
Integer.toHexString(info.offset) + ")";
|
||||
}
|
||||
Msg.warn(this, "Structure Merge: Failed to resolve data type '" +
|
||||
info.componentDataType.getName() + "' at " + loc + " in " + struct.getPathName());
|
||||
@@ -2794,7 +2825,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
|
||||
DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht);
|
||||
|
||||
int ordinal = info.resultOrdinal;
|
||||
int ordinal = info.resultIndex;
|
||||
|
||||
DataTypeComponent dtc = null;
|
||||
if (ordinal >= 0 && ordinal <= union.getNumComponents()) {
|
||||
@@ -2865,7 +2896,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
}
|
||||
Msg.warn(this,
|
||||
"Union Merge: Failed to resolve data type '" + info.componentDataType.getName() +
|
||||
"' at ordinal " + info.resultOrdinal + " in " + union.getPathName());
|
||||
"' at ordinal " + info.resultIndex + " in " + union.getPathName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2889,7 +2920,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
FixUpInfo info = fixUpList.get(i); // assume info applies to union
|
||||
if (!fixUpUnionComponent(union, info)) {
|
||||
Msg.warn(this, "Union Merge: Failed to apply data type at ordinal " +
|
||||
info.resultOrdinal + " in " + union.getPathName());
|
||||
info.resultIndex + " in " + union.getPathName());
|
||||
unresolvedFixups.add(info);
|
||||
}
|
||||
}
|
||||
@@ -3427,10 +3458,12 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
final long compID; // Source datatype ID for component
|
||||
final DataType componentDataType; // Source component datatype
|
||||
|
||||
// Result ordinal when id represents a container such as a structure/union or
|
||||
// function definition. In such cases, 'compID' corresponds to the component datatype.
|
||||
// A -1 may be used when not applicable.
|
||||
final int resultOrdinal;
|
||||
// Result defined-component index for a structure, component ordinal for a union,
|
||||
// or parameter index for a function definition. A -1 denotes a return type or
|
||||
// a dependency without a component index. Structure indexes exclude implicit
|
||||
// undefined bytes and survive layout changes, but must be regenerated when the
|
||||
// selected definition is rebuilt (see removeFixUps).
|
||||
final int resultIndex;
|
||||
|
||||
final MyIdentityHashMap<Long, DataType> ht;
|
||||
|
||||
@@ -3449,16 +3482,16 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
* @param id source data type ID needing to be fixed up
|
||||
* @param compID source datatype ID of either param/component or bitfield base type
|
||||
* @param componentDataType source component/dependency datatype
|
||||
* @param resultOrdinal the result ordinal into a structure/union; or
|
||||
* parameter/return ordinal; or -1 for other cases where index is not used
|
||||
* @param resultIndex result defined-component index for a structure, union component
|
||||
* ordinal, function parameter index, or -1 for a return type/other dependency
|
||||
* @param resolvedDataTypes hashtable used for resolving the data type
|
||||
*/
|
||||
FixUpInfo(long id, long compID, DataType componentDataType, int resultOrdinal,
|
||||
FixUpInfo(long id, long compID, DataType componentDataType, int resultIndex,
|
||||
MyIdentityHashMap<Long, DataType> resolvedDataTypes) {
|
||||
this.id = id;
|
||||
this.compID = compID;
|
||||
this.componentDataType = componentDataType;
|
||||
this.resultOrdinal = resultOrdinal;
|
||||
this.resultIndex = resultIndex;
|
||||
this.ht = resolvedDataTypes;
|
||||
|
||||
if (componentDataType instanceof BitFieldDataType) {
|
||||
@@ -3472,13 +3505,13 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
* or components were resolved.
|
||||
* @param id id of data type needing to be fixed up
|
||||
* @param compID datatype ID of either param/component or bitfield base type
|
||||
* @param resultOrdinal component ordinal within result composite
|
||||
* @param resultIndex defined-component index within a result structure or ordinal in a union
|
||||
* @param sourceDtc associated composite datatype component
|
||||
* @param resolvedDataTypes hashtable used for resolving the data type
|
||||
*/
|
||||
FixUpInfo(long id, long compID, int resultOrdinal, DataTypeComponent sourceDtc,
|
||||
FixUpInfo(long id, long compID, int resultIndex, DataTypeComponent sourceDtc,
|
||||
MyIdentityHashMap<Long, DataType> resolvedDataTypes) {
|
||||
this(id, compID, getDataType(sourceDtc), resultOrdinal, resolvedDataTypes);
|
||||
this(id, compID, getDataType(sourceDtc), resultIndex, resolvedDataTypes);
|
||||
offset = sourceDtc.getOffset();
|
||||
if (sourceDtc.isBitFieldComponent()) {
|
||||
BitFieldDataType bfDt = (BitFieldDataType) sourceDtc.getDataType();
|
||||
@@ -3497,11 +3530,11 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
|
||||
@Override
|
||||
public int compareTo(FixUpInfo o) {
|
||||
// Compare such that items are grouped by id and sort such that the greatest resultOrdinal
|
||||
// Compare such that items are grouped by id and sort such that the greatest resultIndex
|
||||
// is first within that group.
|
||||
long c = id - o.id;
|
||||
if (c == 0) {
|
||||
c = Integer.toUnsignedLong(o.resultOrdinal) - Integer.toUnsignedLong(resultOrdinal);
|
||||
c = Integer.toUnsignedLong(o.resultIndex) - Integer.toUnsignedLong(resultIndex);
|
||||
}
|
||||
if (c == 0) {
|
||||
return 0;
|
||||
@@ -3527,7 +3560,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
}
|
||||
return "\n" + "ID = " + Long.toHexString(id) + ",\ndt = " + dtm.getDataType(id) +
|
||||
",\ncomponent ID = " + Long.toHexString(compID) + ",\ncomponent dt = " +
|
||||
dtm.getDataType(compID) + ",\nresultOrdinal = " + resultOrdinal + ",\n" + bitInfo +
|
||||
dtm.getDataType(compID) + ",\nresultIndex = " + resultIndex + ",\n" + bitInfo +
|
||||
"ht = " +
|
||||
htStr + "\n";
|
||||
}
|
||||
|
||||
@@ -1098,6 +1098,12 @@ class StackFrameDataType implements Structure {
|
||||
return dtc != null ? new StackComponentWrapper(dtc) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getDefinedComponent(int index) throws IndexOutOfBoundsException {
|
||||
DataTypeComponent dtc = wrappedStruct.getDefinedComponent(index);
|
||||
return new StackComponentWrapper(dtc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackComponentWrapper getComponent(int ordinal) throws IndexOutOfBoundsException {
|
||||
DataTypeComponent dtc = wrappedStruct.getComponent(ordinal);
|
||||
|
||||
@@ -1169,6 +1169,72 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiEdits14() throws Exception {
|
||||
|
||||
mtf.initialize("notepad2", new ProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
|
||||
|
||||
// Create a conflict while retaining Bar's original six-byte length.
|
||||
assertEquals(6, bar.getLength());
|
||||
bar.getComponent(0).setComment("Latest Bar component");
|
||||
|
||||
int junk = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
CategoryPath path = new CategoryPath("/MISC");
|
||||
Structure bar = (Structure) dtm.getDataType(path, "Bar");
|
||||
bar.delete(1); // Remove the pointer, shrinking Bar from six bytes to two.
|
||||
assertEquals(2, bar.getLength());
|
||||
|
||||
// Allocate the container before its target so that the merge records a fixup
|
||||
// for the as-yet-unresolved target when processing the added container.
|
||||
Structure container = (Structure) dtm.addDataType(
|
||||
new StructureDataType(path, "FixupContainer", 0),
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
Structure target = new StructureDataType(path, "FixupTarget", 0);
|
||||
target.add(ByteDataType.dataType);
|
||||
target = (Structure) dtm.addDataType(target, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
|
||||
container.add(bar, "bar", null);
|
||||
container.growStructure(4);
|
||||
container.add(target, "target", null);
|
||||
assertFalse(container.isPackingEnabled());
|
||||
assertEquals(6, container.getComponent(5).getOffset());
|
||||
|
||||
int junk = 0;
|
||||
}
|
||||
});
|
||||
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// The added container initially uses Latest's six-byte Bar, so the placeholder
|
||||
// at offset 6 has ordinal 1. Choosing MY Bar shrinks that component to two bytes,
|
||||
// introducing four undefined components before the placeholder. Its ordinal is
|
||||
// now 5, but FixUpInfo still records 1. The merge must not use that stale ordinal.
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);
|
||||
waitForCompletion();
|
||||
|
||||
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
|
||||
Structure container =
|
||||
(Structure) dtm.getDataType(new CategoryPath("/MISC"), "FixupContainer");
|
||||
DataType target = dtm.getDataType(new CategoryPath("/MISC"), "FixupTarget");
|
||||
assertEquals(2, bar.getLength());
|
||||
assertEquals(7, container.getLength());
|
||||
assertEquals(2, container.getNumDefinedComponents());
|
||||
assertEquals(bar, container.getComponent(0).getDataType());
|
||||
assertEquals(6, container.getComponent(5).getOffset());
|
||||
assertEquals(target, container.getComponent(5).getDataType());
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedBaseTypeDef() throws Exception {
|
||||
|
||||
|
||||
@@ -28,6 +28,107 @@ import ghidra.program.model.data.*;
|
||||
*/
|
||||
public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
|
||||
|
||||
@Test
|
||||
public void testDefinedComponentFixupAfterResize() throws Exception {
|
||||
checkDefinedComponentFixupAfterLayoutChange(false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefinedComponentFixupAfterEnablingPacking() throws Exception {
|
||||
checkDefinedComponentFixupAfterLayoutChange(false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefinedComponentFixupAfterDisablingPacking() throws Exception {
|
||||
checkDefinedComponentFixupAfterLayoutChange(true, false);
|
||||
}
|
||||
|
||||
private void checkDefinedComponentFixupAfterLayoutChange(boolean initiallyPacked,
|
||||
boolean finallyPacked) throws Exception {
|
||||
CategoryPath path = new CategoryPath("/MISC");
|
||||
mtf.initialize("notepad2", new OriginalProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
// Ensure the zero-length type is already resolved when the container is added.
|
||||
program.getDataTypeManager().addDataType(new ArrayDataType(ByteDataType.dataType, 0),
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
Structure bar = (Structure) program.getDataTypeManager().getDataType(path, "Bar");
|
||||
bar.getComponent(0).setComment("Latest Bar component");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
Structure bar = (Structure) dtm.getDataType(path, "Bar");
|
||||
bar.delete(1);
|
||||
assertEquals(2, bar.getLength());
|
||||
|
||||
// Allocate the container first so its target components require deferred fixups.
|
||||
Structure container = (Structure) dtm.addDataType(
|
||||
new StructureDataType(path, "LayoutContainer", 0),
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
Structure target = new StructureDataType(path, "LayoutTarget", 0);
|
||||
target.add(ByteDataType.dataType);
|
||||
target = (Structure) dtm.addDataType(target, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
|
||||
container.add(bar, "bar", null);
|
||||
container.growStructure(4);
|
||||
container.insertBitFieldAt(6, 1, 0, ByteDataType.dataType, 3, "bits1", null);
|
||||
container.insertBitFieldAt(6, 1, 3, ByteDataType.dataType, 2, "bits2", null);
|
||||
container.add(new ArrayDataType(ByteDataType.dataType, 0), "zero1", null);
|
||||
container.add(new ArrayDataType(ByteDataType.dataType, 0), "zero2", null);
|
||||
container.add(target, "target1", null);
|
||||
container.add(target, "target2", null);
|
||||
container.setPackingEnabled(initiallyPacked);
|
||||
}
|
||||
});
|
||||
|
||||
executeMerge();
|
||||
waitForPrompting(); // Wait until additions are complete and the Bar conflict is displayed.
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
Structure container = (Structure) dtm.getDataType(path, "LayoutContainer");
|
||||
assertNotNull(container);
|
||||
DataTypeComponent[] components = container.getDefinedComponents();
|
||||
assertEquals(7, components.length);
|
||||
assertEquals(BadDataType.dataType, components[5].getDataType());
|
||||
assertEquals(BadDataType.dataType, components[6].getDataType());
|
||||
|
||||
// The merge is paused at the Bar conflict, after the container fixups were recorded.
|
||||
// Exercise a packing transition without replacing its defined-component sequence.
|
||||
int tx = resultProgram.startTransaction("Change packing with pending fixups");
|
||||
try {
|
||||
container.setPackingEnabled(finallyPacked);
|
||||
}
|
||||
finally {
|
||||
resultProgram.endTransaction(tx, true);
|
||||
}
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);
|
||||
waitForCompletion();
|
||||
|
||||
container = (Structure) dtm.getDataType(path, "LayoutContainer");
|
||||
components = container.getDefinedComponents();
|
||||
assertEquals(finallyPacked, container.isPackingEnabled());
|
||||
assertEquals(7, components.length);
|
||||
assertEquals(2, components[0].getLength());
|
||||
assertTrue(components[1].isBitFieldComponent());
|
||||
assertTrue(components[2].isBitFieldComponent());
|
||||
assertEquals(components[1].getOffset(), components[2].getOffset());
|
||||
assertEquals(0, components[3].getLength());
|
||||
assertEquals(0, components[4].getLength());
|
||||
assertEquals(components[3].getOffset(), components[4].getOffset());
|
||||
DataType target = dtm.getDataType(path, "LayoutTarget");
|
||||
assertNotNull(target);
|
||||
assertEquals("target1", components[5].getFieldName());
|
||||
assertEquals(target, components[5].getDataType());
|
||||
assertEquals("target2", components[6].getFieldName());
|
||||
assertEquals(target, components[6].getDataType());
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
private void setupRemoveInnerVsAddOuterContainingChangedInner() throws Exception {
|
||||
|
||||
final CategoryPath rootPath = new CategoryPath("/");
|
||||
|
||||
@@ -746,10 +746,22 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
@Override
|
||||
public int getNumDefinedComponents() {
|
||||
try (Closeable c = lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return components.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB getDefinedComponent(int index) throws IndexOutOfBoundsException {
|
||||
try (Closeable c = lock.read()) {
|
||||
refreshIfNeeded();
|
||||
if (index < 0 || index >= components.size()) {
|
||||
throw new IndexOutOfBoundsException(index);
|
||||
}
|
||||
return components.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB getComponent(int ordinal) {
|
||||
try (Closeable c = lock.read()) {
|
||||
|
||||
@@ -389,16 +389,21 @@ class UnionDB extends CompositeDB implements UnionInternal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB getComponent(int ordinal) {
|
||||
public DataTypeComponentDB getDefinedComponent(int index) throws IndexOutOfBoundsException {
|
||||
try (Closeable c = lock.read()) {
|
||||
refreshIfNeeded();
|
||||
if (ordinal < 0 || ordinal >= components.size()) {
|
||||
return null;
|
||||
if (index < 0 || index >= components.size()) {
|
||||
throw new IndexOutOfBoundsException(index);
|
||||
}
|
||||
return components.get(ordinal);
|
||||
return components.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB getComponent(int ordinal) {
|
||||
return getDefinedComponent(ordinal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB[] getComponents() {
|
||||
try (Closeable c = lock.read()) {
|
||||
|
||||
@@ -47,6 +47,17 @@ public interface Composite extends DataType {
|
||||
*/
|
||||
public abstract int getNumDefinedComponents();
|
||||
|
||||
/**
|
||||
* Returns the defined component of this data type at the specified index
|
||||
* within the ordered sequence of {@link #getDefinedComponents() defined components}.
|
||||
* See {@link #getNumDefinedComponents()}.
|
||||
* @param index the index of the defined component (numbering starts at 0).
|
||||
* @return the data type component.
|
||||
* @throws IndexOutOfBoundsException if the index is out of bounds
|
||||
*/
|
||||
public abstract DataTypeComponent getDefinedComponent(int index)
|
||||
throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Returns the component of this data type with the indicated ordinal.
|
||||
* @param ordinal the component's ordinal (numbering starts at 0).
|
||||
|
||||
@@ -448,6 +448,14 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||
dtc.setOrdinal(dtc.getOrdinal() + deltaOrdinal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentImpl getDefinedComponent(int index) throws IndexOutOfBoundsException {
|
||||
if (index < 0 || index >= components.size()) {
|
||||
throw new IndexOutOfBoundsException(index);
|
||||
}
|
||||
return components.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentImpl getComponent(int ordinal) {
|
||||
if (ordinal < 0 || ordinal >= numComponents) {
|
||||
|
||||
@@ -104,8 +104,16 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getComponent(int ordinal) {
|
||||
return components.get(ordinal);
|
||||
public DataTypeComponentImpl getDefinedComponent(int index) throws IndexOutOfBoundsException {
|
||||
if (index < 0 || index >= components.size()) {
|
||||
throw new IndexOutOfBoundsException(index);
|
||||
}
|
||||
return components.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentImpl getComponent(int ordinal) throws IndexOutOfBoundsException {
|
||||
return getDefinedComponent(ordinal);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user