GT-2136 - Fixed NPE in program data type manager

This commit is contained in:
dragonmacher 2019-06-04 10:46:15 -04:00
parent 67198eb40f
commit 2f2c2ca8b0
3 changed files with 150 additions and 112 deletions

View file

@ -26,30 +26,14 @@ import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.InvalidNameException;
import ghidra.util.task.TaskMonitorAdapter;
/**
*
* Tests for the DataManager.
*
*
*/
public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramDB program;
private DataTypeManagerDB dataMgr;
private int transactionID;
/**
* Constructor for DataManagerTest.
* @param arg0
*/
public DataManagerTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
@ -57,9 +41,6 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
startTransaction();
}
/*
* @see TestCase#tearDown()
*/
@After
public void tearDown() throws Exception {
endTransaction();
@ -67,14 +48,23 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testGetUniqueName() throws Exception {
public void testSetName() throws InvalidNameException {
String oldName = dataMgr.getName();
String newName = "NewName";
dataMgr.setName("NewName");
assertEquals(newName, dataMgr.getName());
}
@Test
public void testGetUniqueName() throws Exception {
DataType bt = new EnumDataType("test", 2);
dataMgr.resolve(bt, null);
assertEquals("test_1", dataMgr.getUniqueName(CategoryPath.ROOT, "test"));
}
@Test
public void testGetDataTypeByID() throws Exception {
public void testGetDataTypeByID() throws Exception {
Category root = dataMgr.getRootCategory();
Category sub1 = root.createCategory("SubCat-A");
@ -95,7 +85,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testFindDataTypes() throws Exception {
public void testFindDataTypes() throws Exception {
Category root = dataMgr.getRootCategory();
Category sub1 = root.createCategory("SubCat-A");
@ -147,7 +137,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testFindDataTypesWildcard() throws Exception {
public void testFindDataTypesWildcard() throws Exception {
Category root = dataMgr.getRootCategory();
Category sub1 = root.createCategory("SubCat-A");
@ -180,7 +170,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testFindDataType() throws Exception {
public void testFindDataType() throws Exception {
Category root = dataMgr.getRootCategory();
Category subc = root.createCategory("subc");
subc.createCategory("subc2");
@ -193,7 +183,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreateCategoryHierarchy() throws Exception {
public void testCreateCategoryHierarchy() throws Exception {
String fullName = "/cat1/cat2/cat3/cat4/cat5";
CategoryPath cp = new CategoryPath(fullName);
dataMgr.createCategory(cp);
@ -211,7 +201,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreateArray() throws Exception {
public void testCreateArray() throws Exception {
ArrayDataType adt = new ArrayDataType(new ByteDataType(), 3, 1);
Array array = (Array) dataMgr.addDataType(adt, null);
assertNotNull(array);
@ -222,7 +212,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreateTypedef() throws Exception {
public void testCreateTypedef() throws Exception {
ArrayDataType adt = new ArrayDataType(new ByteDataType(), 3, 1);
Array array = (Array) dataMgr.addDataType(adt, null);
TypedefDataType tdt = new TypedefDataType("ArrayTypedef", array);
@ -232,7 +222,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreatePointer() throws Exception {
public void testCreatePointer() throws Exception {
ArrayDataType adt = new ArrayDataType(new ByteDataType(), 5, 1);
Array array = (Array) dataMgr.addDataType(adt, null);
@ -249,7 +239,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreatePointers() throws Exception {
public void testCreatePointers() throws Exception {
Array array = new ArrayDataType(new ByteDataType(), 5, 1);
TypeDef td = new TypedefDataType("ByteTypedef", array);
@ -269,7 +259,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testRemoveDataType() throws Exception {
public void testRemoveDataType() throws Exception {
Array array = new ArrayDataType(new ByteDataType(), 5, 1);
TypeDef td = new TypedefDataType("ByteTypedef", array);
Pointer p = new Pointer32DataType(td);
@ -292,7 +282,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testRemoveDataType2() throws Exception {
public void testRemoveDataType2() throws Exception {
Array array = new ArrayDataType(new ByteDataType(), 5, 1);
TypeDef td = new TypedefDataType("ByteTypedef", array);
Pointer p = new Pointer32DataType(td);
@ -322,7 +312,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
// }
@Test
public void testCreateStructure() {
public void testCreateStructure() {
StructureDataType sdt = new StructureDataType("test", 0);
Structure struct = (Structure) dataMgr.addDataType(sdt, null);
assertNotNull(struct);
@ -333,7 +323,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreateUnion() {
public void testCreateUnion() {
UnionDataType udt = new UnionDataType("test");
Union union = (Union) dataMgr.addDataType(udt, null);
assertNotNull(union);
@ -342,7 +332,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testCreateFunctionDef() {
public void testCreateFunctionDef() {
FunctionDefinitionDataType fdt =
new FunctionDefinitionDataType(new FunctionDefinitionDataType("test"));
FunctionDefinition funcDef = (FunctionDefinition) dataMgr.addDataType(fdt, null);
@ -366,7 +356,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testDataTypeSizeChanged() {
public void testDataTypeSizeChanged() {
Structure dt = new StructureDataType("MyStruct", 100);
dt.insert(0, new ByteDataType());
@ -391,7 +381,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testResolveDataType() {
public void testResolveDataType() {
DataTypeManager dtm = new StandAloneDataTypeManager("Test");
int id = dtm.startTransaction("");
@ -409,7 +399,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testResolveDataType2() throws Exception {
public void testResolveDataType2() throws Exception {
DataTypeManager dtm = new StandAloneDataTypeManager("Test");
int id = dtm.startTransaction("");
Category otherRoot = dataMgr.getRootCategory();
@ -424,7 +414,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testResolveDataType3() throws Exception {
public void testResolveDataType3() throws Exception {
DataTypeManager dtm = new StandAloneDataTypeManager("Test");
int id = dtm.startTransaction("");
Category otherRoot = dataMgr.getRootCategory();
@ -443,9 +433,8 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
dtm.close();
}
@Test
public void testDoubleReplace() throws Exception {
public void testDoubleReplace() throws Exception {
Structure struct = new StructureDataType("test", 0);
struct.add(new ByteDataType());
struct.add(new WordDataType());

View file

@ -40,8 +40,8 @@ import ghidra.util.task.TaskMonitor;
/**
* Class for managing data types in a program
*/
public class ProgramDataTypeManager extends DataTypeManagerDB implements ManagerDB,
ProgramBasedDataTypeManager {
public class ProgramDataTypeManager extends DataTypeManagerDB
implements ManagerDB, ProgramBasedDataTypeManager {
private static final String OLD_DT_ARCHIVE_FILENAMES = "DataTypeArchiveFilenames"; // eliminated with Ghidra 4.3
@ -61,15 +61,12 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
* @throws IOException if a database io error occurs.
*/
public ProgramDataTypeManager(DBHandle handle, AddressMap addrMap, int openMode,
ErrorHandler errHandler, Lock lock, TaskMonitor monitor) throws CancelledException,
VersionException, IOException {
ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, VersionException, IOException {
super(handle, addrMap, openMode, errHandler, lock, monitor);
upgrade = (openMode == DBConstants.UPGRADE);
}
/**
* @see ghidra.program.database.ManagerDB#setProgram(ghidra.program.database.ProgramDB)
*/
@Override
public void setProgram(ProgramDB p) {
this.program = p;
@ -85,17 +82,11 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
}
}
/**
* @see ghidra.program.database.ManagerDB#invalidateCache(boolean)
*/
@Override
public void invalidateCache(boolean all) throws IOException {
super.invalidateCache();
}
/**
* @see ghidra.program.database.ManagerDB#programReady(int, int, ghidra.util.task.TaskMonitor)
*/
@Override
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException {
@ -104,9 +95,6 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
}
}
/**
* @see ghidra.program.model.data.DataTypeManager#getName()
*/
@Override
public String getName() {
return program.getName();
@ -117,9 +105,6 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
return PointerDataType.getPointer(dt, this);
}
/**
* @see ghidra.program.model.data.DataTypeManager#setName(java.lang.String)
*/
@Override
public void setName(String name) throws InvalidNameException {
if (name == null || name.length() == 0) {
@ -127,10 +112,10 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
}
program.setName(name);
categoryRenamed(CategoryPath.ROOT, null);
Category root = getRootCategory();
categoryRenamed(CategoryPath.ROOT, root);
}
////////////////////
@Override
public void sourceArchiveChanged(UniversalID sourceArchiveID) {
super.sourceArchiveChanged(sourceArchiveID);
@ -219,7 +204,6 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
super.favoritesChanged(dataType, isFavorite);
}
///////////////////
@Override
protected void replaceDataTypeIDs(long oldDataTypeID, long newDataTypeID) {
if (oldDataTypeID == newDataTypeID) {
@ -249,9 +233,6 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
return program.isChangeable();
}
/**
* @see ghidra.program.model.data.DataTypeManager#startTransaction(java.lang.String)
*/
@Override
public int startTransaction(String description) {
return program.startTransaction(description);
@ -262,34 +243,22 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
program.flushEvents();
}
/**
* @see ghidra.program.model.data.DataTypeManager#endTransaction(int, boolean)
*/
@Override
public void endTransaction(int transactionID, boolean commit) {
program.endTransaction(transactionID, commit);
}
/**
* @see ghidra.program.model.data.DataTypeManager#close()
*/
@Override
public void close() {
// do nothing - cannot close the program's data type manager
}
/* (non-Javadoc)
* @see ghidra.program.model.data.ProgramDataTypeManager#getProgram()
*/
@Override
public Program getProgram() {
return program;
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DomainFileBasedDataTypeManager#getDomainFile()
*/
@Override
public DomainFile getDomainFile() {
return program.getDomainFile();
@ -319,5 +288,4 @@ public class ProgramDataTypeManager extends DataTypeManagerDB implements Manager
}
return dataOrganization;
}
}

View file

@ -53,22 +53,25 @@ public interface DataTypeManager {
public final UniversalID BUILT_IN_ARCHIVE_UNIVERSAL_ID = new UniversalID(BUILT_IN_ARCHIVE_KEY);
/**
* Returns the universal ID for this dataType manager.
* Returns the universal ID for this dataType manager
* @return the universal ID for this dataType manager
*/
public UniversalID getUniversalID();
/**
* Returns true if the given category path exists in this datatype manager.
* @param path
* @return
* Returns true if the given category path exists in this datatype manager
* @param path the path
* @return true if the given category path exists in this datatype manager
*/
public boolean containsCategory(CategoryPath path);
/**
* Returns a unique name not currently used by any other dataType or category
* with the same baseName.
* @param baseName the base name to be made unique.
* @return a unique name starting with baseName.
* with the same baseName
*
* @param path the path of the name
* @param baseName the base name to be made unique
* @return a unique name starting with baseName
*/
public String getUniqueName(CategoryPath path, String baseName);
@ -96,22 +99,26 @@ public interface DataTypeManager {
/**
* Returns an iterator over all the dataTypes in this manager
* @return an iterator over all the dataTypes in this manager
*/
public Iterator<DataType> getAllDataTypes();
/**
* Adds all data types to the specified list.
* @param list
* Adds all data types to the specified list.]
*
* @param list the result list into which the types will be placed
*/
public void getAllDataTypes(List<DataType> list);
/**
* Returns an iterator over all structures in this manager.
* Returns an iterator over all structures in this manager
* @return the iterator
*/
public Iterator<Structure> getAllStructures();
/**
* Returns an iterator over all composite data types (structures and unions) in this manager.
* Returns an iterator over all composite data types (structures and unions) in this manager
* @return the iterator
*/
public Iterator<Composite> getAllComposites();
@ -159,8 +166,9 @@ public interface DataTypeManager {
* there is also a category "b" under category "a". A better solution is to use
* the {@link #getDataType(DataTypePath)} method because the DataTypePath keeps the
* category and datatype name separate.
* @param dataType path;
* @return the dataType or null if it isn't found.
*
* @param dataTypePath path
* @return the dataType or null if it isn't found
*/
public DataType getDataType(String dataTypePath);
@ -182,31 +190,44 @@ public interface DataTypeManager {
/**
* Returns the dataTypeId for the given dataType. If the dataType is not
* currently in the dataTypeManger, it will be added.
* currently in the dataTypeManger, it will be added
*
* @param dt the data type
* @return the ID of the resolved type
*/
public long getResolvedID(DataType dt);
/**
* Returns the dataTypeId for the given dataType. If the dataType does not exist,
* a -1 will be returned
* @param dt the datatype to get an id for.
*
* @param dt the datatype to get an id for
* @return the ID of the type
*/
public long getID(DataType dt);
/**
* Returns the dataType associated with the given dataTypeId or null if the
* dataTypeId is not valid.
* Returns the dataType associated with the given dataTypeId or null if the dataTypeId is
* not valid
*
* @param dataTypeID the ID
* @return the type
*/
public DataType getDataType(long dataTypeID);
/**
* Returns the Category with the given id.
* @param categoryID id of the desired category.
* Returns the Category with the given id
*
* @param categoryID id of the desired category
* @return the category
*/
public Category getCategory(long categoryID);
/**
* Get the category that has the given path.
* Get the category that has the given path
*
* @param path the path
* @return the category
*/
public Category getCategory(CategoryPath path);
@ -244,18 +265,25 @@ public interface DataTypeManager {
/**
* Remove the given datatype from this manager
* @param dataType the dataType to be removed.
* @param dataType the dataType to be removed
* @param monitor the task monitor
* @return true if the data type existed and was removed
*/
public boolean remove(DataType dataType, TaskMonitor monitor);
/**
* Return true if the given dataType exists in this data type manager.
* Return true if the given dataType exists in this data type manager
*
* @param dataType the type
* @return true if the type is in this manager
*/
public boolean contains(DataType dataType);
/**
* @param path
* Create a category for the given path; returns the current category if it already exits
*
* @param path the path
* @return the category
*/
public Category createCategory(CategoryPath path);
@ -268,19 +296,22 @@ public interface DataTypeManager {
public DataType getDataType(CategoryPath path, String name);
/**
* Returns this data type manager's name.
* Returns this data type manager's name
* @return the name
*/
public String getName();
/**
* Sets this data type manager's name.
* Sets this data type manager's name
* @param name the new name
* @throws InvalidNameException if the given name is invalid (such as when null or empty)
*/
public void setName(String name) throws InvalidNameException;
/**
* Starts a transaction for making changes in this data type manager.
* @param description a short description of the changes to be made.
* @return the transaction ID
*/
public int startTransaction(String description);
@ -293,22 +324,27 @@ public interface DataTypeManager {
/**
* Ends the current transaction
* @param transactionID id of the transaction to end
* @param commit if true the changes are commited, otherwise all changes in transaction are revoked.
* @param commit true if changes are committed, false if changes in transaction are revoked
*/
public void endTransaction(int transactionID, boolean commit);
/**
* Force all pending notification events to be flushed
* @throws IllegalStateException if the client is holding this object's lock
*/
public void flushEvents();
/**
* Closes this dataType manager.
*
* Closes this dataType manager
*/
public void close();
/**
* Returns a default sized pointer to the given datatype. The pointer size is established
* dynamically based upon the data organization established by the compiler specification.
* @param datatype the pointed to data type.
*
* @param datatype the pointed to data type
* @return the pointer
*/
public Pointer getPointer(DataType datatype);
@ -316,13 +352,16 @@ public interface DataTypeManager {
* Returns a pointer of the given size to the given datatype.
* Note: It is preferred to use default sized pointers when possible (i.e., size=-1,
* see {@link #getPointer(DataType)}) instead of explicitly specifying the size value.
* @param datatype the pointed to data type.
* @param size the size of the pointer to be created or -1 for a default sized pointer.
*
* @param datatype the pointed to data type
* @param size the size of the pointer to be created or -1 for a default sized pointer
* @return the pointer
*/
public Pointer getPointer(DataType datatype, int size);
/**
* Returns the root category Manager
* @return the category
*/
public Category getRootCategory();
@ -350,13 +389,14 @@ public interface DataTypeManager {
/**
* Returns the total number of data type categories
* @return the count
*/
public int getCategoryCount();
/**
* Returns the total number of defined data types.
* @param includePointersAndArrays if true all pointers and array
* data types will be included.
* @param includePointersAndArrays if true all pointers and array data types will be included
* @return the count
*/
public int getDataTypeCount(boolean includePointersAndArrays);
@ -376,16 +416,46 @@ public interface DataTypeManager {
*/
public DataType findDataTypeForID(UniversalID datatypeID);
/**
* Returns the timestamp of the last time this manager was changed
* @return the timestamp
*/
public long getLastChangeTimeForMyManager();
/**
* Returns the source archive for the given ID
*
* @param sourceID the ID
* @return the archive; null if the ID is null; null if the archive does not exist
*/
public SourceArchive getSourceArchive(UniversalID sourceID);
/**
* Returns this manager's archive type
* @return the type
*/
public ArchiveType getType();
/**
* Returns all data types within this manager that have as their source the given archive
*
* @param sourceArchive the archive
* @return the types
*/
public List<DataType> getDataTypes(SourceArchive sourceArchive);
/**
* Returns the source archive for this manager
* @return the archive; null if the ID is null; null if the archive does not exist
*/
public SourceArchive getLocalSourceArchive();
/**
* Change the given data type so that its source archive is the given archive
*
* @param datatype the type
* @param archive the archive
*/
public void associateDataTypeWithArchive(DataType datatype, SourceArchive archive);
/**
@ -425,8 +495,19 @@ public interface DataTypeManager {
*/
public List<SourceArchive> getSourceArchives();
/**
* Removes the source archive from this manager. This will disassociate all data types in
* this manager from the given archive.
*
* @param sourceArchive the archive
*/
public void removeSourceArchive(SourceArchive sourceArchive);
/**
* Returns or creates a persisted version of the given source archive
* @param sourceArchive the archive
* @return the archive
*/
public SourceArchive resolveSourceArchive(SourceArchive sourceArchive);
/**