diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/DataManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/DataManagerTest.java index e2c6df067f..edac7529e7 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/DataManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/DataManagerTest.java @@ -27,6 +27,7 @@ import ghidra.program.database.ProgramDB; import ghidra.program.model.data.*; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.util.InvalidNameException; +import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitorAdapter; public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest { @@ -112,27 +113,27 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(4, list.size()); ArrayList dataTypeList = new ArrayList(); - dataMgr.findDataTypes("nu", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("nu", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(0, dataTypeList.size()); dataTypeList.clear(); - dataMgr.findDataTypes("*num", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("*num", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(4, dataTypeList.size()); dataTypeList.clear(); - dataMgr.findDataTypes("*num*", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("*num*", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(4, dataTypeList.size()); dataTypeList.clear(); - dataMgr.findDataTypes("num*", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("num*", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(0, dataTypeList.size()); dataTypeList.clear(); - dataMgr.findDataTypes("*n*m*", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("*n*m*", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(4, dataTypeList.size()); dataTypeList.clear(); - dataMgr.findDataTypes("*n*u*", dataTypeList, false, TaskMonitorAdapter.DUMMY_MONITOR); + dataMgr.findDataTypes("*n*u*", dataTypeList, false, TaskMonitor.DUMMY); assertEquals(4, dataTypeList.size()); } 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 327aa91932..c9ff2b264b 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 @@ -18,6 +18,7 @@ package ghidra.program.database.data; import java.io.File; import java.io.IOException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -306,6 +307,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * @param errHandler the error handler * @param lock database lock * @param monitor the current task monitor + * @throws CancelledException if an upgrade is cancelled + * @throws IOException if there is a problem reading the database + * @throws VersionException if any database handle's version doesn't match the expected version */ protected DataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode, ErrorHandler errHandler, Lock lock, TaskMonitor monitor) @@ -657,6 +661,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { baseName = baseName.substring(0, pos); } catch (NumberFormatException e) { + // the number will get updated below } } while (getDataType(path, name) != null) { @@ -678,6 +683,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { baseName = baseName.substring(0, pos); } catch (NumberFormatException e) { + // the number will get updated below } } while (getDataType(path1, name) != null || getDataType(path2, name) != null) { @@ -972,7 +978,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * * @param existingDataType existing datatype * @param dataType new datatype - * @return true if replacment approach was successful, else false + * @return true if replacement approach was successful, else false * @throws DataTypeDependencyException if datatype contains dependency issues * during resolve process */ @@ -980,7 +986,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { throws DataTypeDependencyException { // TODO: this approach could be added to other DB datatypes to avoid - // unnececesary creation and removal. + // unnecessary creation and removal. try { if (existingDataType instanceof StructureDB) { @@ -1266,6 +1272,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager { replacementDt.setLastChangeTime(lastChangeTime); } catch (Exception e) { + Msg.error(this, "Unable to set the name to " + existingDt.getName() + + "on " + replacementDt + " while replacing the original datatype", e); } } CategoryPath path = existingDt.getCategoryPath(); @@ -1276,6 +1284,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } catch (Exception e) { // not sure what to do here + Msg.error(this, "Unable to set the CatagoryPath to " + path + + "on " + replacementDt + " while replacing the original datatype", e); } } return replacementDt; @@ -1543,10 +1553,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager { return BAD_DATATYPE_ID; } if (dt instanceof DatabaseObject) { - // NOTE: Implementation DOES NOT check or guarentee that dt - // or its returned ID correspond to this datatype manager instance. - // This seems incorrect although it's possible that uses depend - // on this behavior. + // NOTE: Implementation DOES NOT check or guarantee that datatype or its returned ID + // correspond to this datatype manager instance. This seems incorrect although it's + // possible that uses depend on this behavior. return ((DatabaseObject) dt).getKey(); } @@ -1801,7 +1810,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { case BUILT_IN: boolean status = builtinAdapter.removeRecord(dataID); if (status) { - dt = builtInMap.remove(new Long(dataID)); + dt = builtInMap.remove(dataID); builtIn2IdMap.remove(dt); } break; @@ -2049,51 +2058,57 @@ abstract public class DataTypeManagerDB implements DataTypeManager { private DataType getBuiltInDataType(long dataTypeID, Record record) { lock.acquire(); try { - Long key = new Long(dataTypeID); + Long key = dataTypeID; DataType dt = builtInMap.get(key); - if (dt == null) { - if (record == null) { - record = builtinAdapter.getRecord(dataTypeID); - } - if (record != null) { - long catID = record.getLongValue(BuiltinDBAdapter.BUILT_IN_CAT_COL); - CategoryDB catDB = getCategoryDB(catID); - CategoryPath catPath = catDB.getCategoryPath(); - String classPath = record.getString(BuiltinDBAdapter.BUILT_IN_CLASSNAME_COL); - String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL); - try { // TODO: !! Can we look for alternate constructor which takes DTM argument - Class c; + if (dt != null) { + return dt; + } - try { - c = Class.forName(classPath); - } - catch (ClassNotFoundException | NoClassDefFoundError e) { - // Check the classNameMap. - String newClassPath = ClassTranslator.get(classPath); - if (newClassPath == null) { - throw e; - } - try { - c = Class.forName(newClassPath); - } - catch (ClassNotFoundException e1) { - throw e1; - } - } - dt = (BuiltInDataType) c.newInstance(); - dt.setName(name); - dt.setCategoryPath(catPath); - dt = dt.clone(this); - dt.setDefaultSettings(new SettingsDBManager(this, dt, dataTypeID)); - } - catch (Exception e) { - dt = new MissingBuiltInDataType(catPath, name, classPath, this); - } - builtInMap.put(key, dt); - builtIn2IdMap.put(dt, key); + if (record == null) { + record = builtinAdapter.getRecord(dataTypeID); + + if (record == null) { + return null; } } + + long catID = record.getLongValue(BuiltinDBAdapter.BUILT_IN_CAT_COL); + CategoryDB catDB = getCategoryDB(catID); + CategoryPath catPath = catDB.getCategoryPath(); + String classPath = record.getString(BuiltinDBAdapter.BUILT_IN_CLASSNAME_COL); + String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL); + try { // TODO: !! Can we look for alternate constructor which takes DTM argument + Class c; + + try { + c = Class.forName(classPath); + } + catch (ClassNotFoundException | NoClassDefFoundError e) { + // Check the classNameMap. + String newClassPath = ClassTranslator.get(classPath); + if (newClassPath == null) { + throw e; + } + try { + c = Class.forName(newClassPath); + } + catch (ClassNotFoundException e1) { + throw e1; + } + } + + dt = (BuiltInDataType) c.getDeclaredConstructor().newInstance(); + dt.setName(name); + dt.setCategoryPath(catPath); + dt = dt.clone(this); + dt.setDefaultSettings(new SettingsDBManager(this, dt, dataTypeID)); + } + catch (Exception e) { + dt = new MissingBuiltInDataType(catPath, name, classPath, this); + } + builtInMap.put(key, dt); + builtIn2IdMap.put(dt, key); return dt; } catch (IOException e) { @@ -2745,6 +2760,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } } catch (IOException e) { + Msg.error(this, "Unexpected exception iterating structures", e); } } } @@ -2788,6 +2804,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } } catch (IOException e) { + Msg.error(this, "Unexpected exception iterating composites", e); } } } @@ -2799,12 +2816,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * than the second. *

* - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. + * @param d1 the first datatype to be compared + * @param d2 the second datatype to be compared * @return a negative integer, zero, or a positive integer as the first argument - * is less than, equal to, or greater than the second. + * is less than, equal to, or greater than the second * @throws ClassCastException if the arguments' types prevent them from being - * compared by this Comparator. + * compared by this Comparator */ @Override public int compare(DataType d1, DataType d2) { @@ -2830,10 +2847,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Notifys the category path changed + * Notifies the category path changed * - * @param dt the datatype whose path changed. - * @param oldPath the old category. + * @param dt the datatype whose path changed + * @param oldPath the old category * @param oldCatId the old category's record id */ void dataTypeCategoryPathChanged(DataTypeDB dt, CategoryPath oldPath, long oldCatId) { @@ -2986,6 +3003,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * @param name the name of the settings * @param value the value for the settings, must be either a String, byte[] * or Long + * @return true if the settings were updated */ public boolean setSettings(Address dataAddr, String name, Object value) { if (value instanceof String) { @@ -3068,6 +3086,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * * @param dataAddr the address of the data for this settings * @param name the name of settings. + * @return the settings object */ public Object getSettings(Address dataAddr, String name) { Object obj = getStringSettingsValue(dataAddr, name); @@ -3082,10 +3101,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Clear the setting. + * Clear the setting * * @param dataAddr min address of data - * @param name settings name + * @param name settings name + * @return true if the settings were cleared */ public boolean clearSetting(Address dataAddr, String name) { if (instanceSettingsAdapter == null) { @@ -3175,12 +3195,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Move the settings in the range to the new start address. + * Move the settings in the range to the new start address * * @param fromAddr start address from where to move * @param toAddr new Address to move to - * @param length number of addresses to move. + * @param length number of addresses to move * @param monitor progress monitor + * @throws CancelledException if the operation was cancelled */ public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor) throws CancelledException { @@ -3246,9 +3267,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Returns all the Settings names for the given address. + * Returns all the Settings names for the given address * * @param dataAddr the address + * @return the names */ public String[] getNames(Address dataAddr) { if (instanceSettingsAdapter == null) { @@ -3275,9 +3297,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Returns true if no settings are set for the given address. + * Returns true if no settings are set for the given address * - * @param dataAddr the address to test. + * @param dataAddr the address to test + * @return true if not settings */ public boolean isEmptySetting(Address dataAddr) { if (instanceSettingsAdapter == null) { @@ -3665,8 +3688,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager { // DT remove this check throw new AssertException("should not be called with id of 0"); } - UniversalID sourceID = sourceArchive == null ? null : sourceArchive.getSourceArchiveID(); + UniversalID sourceID = sourceArchive == null ? null : sourceArchive.getSourceArchiveID(); return idsToDataTypeMap.getDataType(sourceID, datatypeID); } @@ -3978,14 +4001,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * * @param key datatype identity pair (see * {@link DataTypeManagerDB#getEquivalenceKey(DataTypeDB, DataType)} - * @return true if cache contains specified dataype identify pair + * @return true if cache contains specified datatype identify pair */ boolean contains(long key) { return cacheMap.containsKey(key); } /** - * Replace or put datatype pair equivalance state into cache without impacting + * Replace or put datatype pair equivalence state into cache without impacting * its internal activity counter. * * @param key datatype identity pair (see @@ -3996,13 +4019,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } /** - * Put datatype pair equivalance state into cache. A null value is used to + * Put datatype pair equivalence state into cache. A null value is used to * indicate an equivalence check will be determined and another call made to * this method to update the cache with the equivalence state. * * @param key datatype identity pair (see * {@link DataTypeManagerDB#getEquivalenceKey(DataTypeDB, DataType)} - * @param value equivelence state (specify {@code null} to indicate equivalence + * @param value equivalence state (specify {@code null} to indicate equivalence * determination is in-progress) */ void putValue(long key, Boolean value) { @@ -4031,19 +4054,21 @@ abstract public class DataTypeManagerDB implements DataTypeManager { */ private class IdsToDataTypeMap { - private Map> map = new HashMap<>(); + private Map> map = new ConcurrentHashMap<>(); DataType getDataType(UniversalID sourceID, UniversalID dataTypeID) { if (sourceID == null || sourceID.equals(universalID)) { sourceID = LOCAL_ARCHIVE_UNIVERSAL_ID; } - Map idMap = map.computeIfAbsent(sourceID, k -> new HashMap<>()); + + Map idMap = + map.computeIfAbsent(sourceID, k -> new ConcurrentHashMap<>()); final UniversalID sourceArchiveID = sourceID; return idMap.computeIfAbsent(dataTypeID, k -> findDataTypeForIDs(sourceArchiveID, dataTypeID)); } - public void clear() { + void clear() { map.clear(); }