diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java index 30534e0d9b..e3b0058727 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java @@ -36,10 +36,6 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest { super(); } - /** - * This method just tries to parse a bunch o' - * data types just checking for stack traces. - */ @Test public void testSimple() throws Exception { CParser parser = new CParser(); @@ -68,10 +64,6 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest { assertEquals(comp.getDataType().getName(),"char"); } - /** - * This method just tries to parse a bunch o' - * data types just checking for stack traces. - */ @Test public void testLongLong() throws Exception { CParser parser; @@ -96,6 +88,27 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest { assertEquals(8, pdt32.getLength()); } + @Test + public void testTypedef() throws Exception { + CParser parser; + + parser = new CParser(); + DataType tdDt = parser.parse("typedef struct foo * foo;"); + + assertTrue(tdDt != null); + assertTrue(tdDt instanceof TypeDef); + System.out.println(tdDt.getPathName()); + System.out.println(((TypeDef)tdDt).getDataType().getPathName()); + assertEquals("foo", tdDt.getName()); + assertEquals("foo.conflict *", ((TypeDef)tdDt).getDataType().getName()); + assertEquals(4, tdDt.getLength()); + + DataType dt = parser.getDataTypeManager().getDataType("/foo"); + assertTrue(dt != null); + assertTrue(dt instanceof TypeDef); + + } + @Test public void testWcharT() throws Exception { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java index bbb429b9c5..d70f68f7f3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java @@ -1445,6 +1445,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager { *
* NOTE: The original datatype name will be returned unchanged for pointers and arrays since * they cannot be renamed. + *
+ * NOTE: Otherwise, if category does not exist the non-conflict name will be returned. * * @param path the category path of the category where the new data type live in * the data type manager. @@ -1452,16 +1454,39 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * @return the unused conflict name */ public String getUnusedConflictName(CategoryPath path, DataType dt) { - String name = dt.getName(); if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) { // name not used - anything will do - return name; + return dt.getName(); } + return getUnusedConflictName(getCategory(path), dt); + } + /** + * This method gets a ".conflict" name that is not currently used by any data + * types in the indicated category within this data type manager. If the baseName without + * conflict suffix is not used that name will be returned. + *
+ * NOTE: The original datatype name will be returned unchanged for pointers and arrays since + * they cannot be renamed. + *
+ * NOTE: Otherwise, if category does not exist the non-conflict name will be returned. + * + * @param cat the existing category to check. + * @param dt datatype who name is used to establish non-conflict base name + * @return the unused conflict name + */ + private String getUnusedConflictName(Category cat, DataType dt) { + if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) { + // name not used - anything will do + return dt.getName(); + } String baseName = DataTypeUtilities.getNameWithoutConflict(dt); + if (cat == null) { + return baseName; + } String testName = baseName; int count = 0; - while (getDataType(path, testName) != null) { + while (cat.getDataType(testName) != null) { testName = baseName + DataType.CONFLICT_SUFFIX; if (count > 0) { testName += Integer.toString(count); @@ -3116,6 +3141,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager { flags = (short) TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME; cat = getCategory(dataType.getCategoryPath()); // force category } + else if (cat.getDataType(name) != null) { + // force use of conflict name if needed + name = getUnusedConflictName(cat, typedef); + } DBRecord record = typedefAdapter.createRecord(getID(dataType), name, flags, cat.getID(), sourceArchiveIdValue, universalIdValue, typedef.getLastChangeTime()); TypedefDB typedefDB = new TypedefDB(this, dtCache, typedefAdapter, record); diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java new file mode 100644 index 0000000000..ff3a5dc935 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java @@ -0,0 +1,69 @@ +/* ### + * 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.program.database.data; + +import static org.junit.Assert.*; + +import org.junit.*; + +import generic.test.AbstractGenericTest; +import ghidra.program.model.data.*; + +public class TypedefDBTest extends AbstractGenericTest { + + private final String NAME = "Test"; + + private DataTypeManagerDB dataMgr; + private int txId; + + @Before + public void setUp() throws Exception { + dataMgr = new StandAloneDataTypeManager("dummyDTM"); + txId = dataMgr.startTransaction("Test"); + } + + @After + public void tearDown() { + if (txId > 0) { + dataMgr.endTransaction(txId, true); + dataMgr.close(); + } + } + + @Test + public void testDuplicateNameResolve() throws Exception { + + Structure struct = new StructureDataType(NAME, 0); + struct.add(new ByteDataType(), "field1", "Comment1"); + struct.add(new WordDataType(), null, "Comment2"); + struct.add(new DWordDataType(), "field3", null); + struct.add(new ByteDataType(), "field4", "Comment4"); + + Pointer structPtr = new PointerDataType(struct); + + TypeDef typeDef = new TypedefDataType(NAME, structPtr); + + TypeDef td = (TypeDef) dataMgr.resolve(typeDef, null); + assertNotNull(td); + assertEquals(NAME + ".conflict", td.getName()); + + assertTrue(td.isEquivalent(typeDef)); + + assertEquals("typedef Test.conflict Test *", td.toString()); + + } + +}