GP-812 corrected improper exposure of DatabaseObject methods

This commit is contained in:
ghidra1 2021-03-26 15:49:55 -04:00
parent 6a8788acbc
commit d688f580dc
25 changed files with 209 additions and 195 deletions

View file

@ -986,7 +986,7 @@ public class FunctionEditorModel {
if (!paramInfo.isAutoParameter() && paramInfo.isNameModified()) {
Parameter param = paramInfo.getOriginalParameter();
if (param != null) {
if (!param.getSymbol().checkIsValid()) {
if (param.getSymbol().isDeleted()) {
// concurrent removal of param - must do full update
paramsOrReturnModified = true;
break;

View file

@ -38,7 +38,6 @@ import ghidra.app.plugin.core.compositeeditor.CompositeEditorModel;
import ghidra.app.plugin.core.compositeeditor.DataTypeHelper;
import ghidra.app.util.datatype.EmptyCompositeException;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.database.DatabaseObject;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
@ -1271,11 +1270,8 @@ class StackEditorModel extends CompositeEditorModel {
for (int i = comps.length - 1; i >= 0; i--) {
DataTypeComponent component = comps[i];
DataType compDt = component.getDataType();
if (compDt instanceof DatabaseObject) {
DatabaseObject dbObj = (DatabaseObject) compDt;
if (!dbObj.checkIsValid()) {
clearComponent(component.getOrdinal());
}
if (compDt.isDeleted()) {
clearComponent(component.getOrdinal());
}
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,18 +15,16 @@
*/
package ghidra.app.plugin.core.stackeditor;
import ghidra.app.plugin.core.compositeeditor.CompositeEditorPanel;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.DatabaseObject;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.util.exception.UsrException;
import java.awt.event.*;
import javax.swing.*;
import docking.widgets.OptionDialog;
import ghidra.app.plugin.core.compositeeditor.CompositeEditorPanel;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.util.exception.UsrException;
/**
* Panel for editing a function stack.
@ -274,14 +271,12 @@ public class StackEditorPanel extends CompositeEditorPanel {
if (originalDt instanceof StackFrameDataType) {
StackFrameDataType sfdt = (StackFrameDataType) originalDt;
Function function = sfdt.getFunction();
if (function instanceof DatabaseObject) {
if (!((DatabaseObject) function).checkIsValid()) {
// Cancel Editor.
provider.dispose();
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
return;
}
if (function.isDeleted()) {
// Cancel Editor.
provider.dispose();
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
return;
}
StackFrame stack = function.getStackFrame();
StackFrameDataType newSfdt = new StackFrameDataType(stack, dtm);
@ -329,13 +324,10 @@ public class StackEditorPanel extends CompositeEditorPanel {
super.dispose();
}
/**
* @param localSizeField
*/
private void removeFocusListeners(JTextField textField) {
FocusListener[] fl = textField.getFocusListeners();
for (int i = 0; i < fl.length; i++) {
textField.removeFocusListener(fl[i]);
for (FocusListener element : fl) {
textField.removeFocusListener(element);
}
}

View file

@ -568,7 +568,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
SymbolTreeRootNode rootNode = (SymbolTreeRootNode) tree.getModelRoot();
// the symbol may have been deleted while we are processing bulk changes
if (symbol.checkIsValid()) {
if (!symbol.isDeleted()) {
GTreeNode newNode = rootNode.symbolAdded(symbol);
tree.refilterLater(newNode);
}
@ -588,7 +588,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
root.symbolRemoved(symbol, monitor);
// the symbol may have been deleted while we are processing bulk changes
if (symbol.checkIsValid()) {
if (!symbol.isDeleted()) {
root.symbolAdded(symbol);
}
tree.refilterLater();

View file

@ -379,7 +379,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public Symbol getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
return symbol;
@ -400,7 +400,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public Boolean getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
return symbol.isPinned();
@ -435,7 +435,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public ProgramLocation getProgramLocation(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
return symbol.getProgramLocation();
@ -454,7 +454,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public String getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
@ -483,7 +483,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public String getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
@ -520,7 +520,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public String getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
return symbol.getParentNamespace().getName(true);
@ -580,7 +580,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
@Override
public Integer getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
return Integer.valueOf(symbol.getReferenceCount());
@ -612,7 +612,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
@Override
public Integer getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
@ -665,7 +665,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public String getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}
@ -702,7 +702,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
public String getValue(Symbol symbol, Settings settings, Program p,
ServiceProvider svcProvider) throws IllegalArgumentException {
if (!symbol.checkIsValid()) {
if (symbol.isDeleted()) {
return null;
}

View file

@ -250,7 +250,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
case ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED:
case ChangeManager.DOCR_SYMBOL_DATA_CHANGED:
symbol = (Symbol) rec.getObject();
if (symbol.checkIsValid()) { // symbol may have been removed (e.g., parameter)
if (!symbol.isDeleted()) { // symbol may have been removed (e.g., parameter)
symProvider.symbolChanged(symbol);
refProvider.symbolChanged(symbol);
}

View file

@ -54,22 +54,28 @@ public class UndefinedFunction implements Function {
frame = new StackFrameImpl(this);
}
@Override
public boolean isDeleted() {
return false;
}
/**
* locates the function based on the location given at construction time.
* Identifies a <code>UndefinedFunction</code> based on the location given based upon the current
* listing disassembly at time of construction using a block model.
* @param program program to be searched
* @param address address within body of function
* @param monitor task monitor
* @return function or null if invalid parameters, not found, or cancelled
*/
public static UndefinedFunction findFunction(Program program, Address address,
TaskMonitor monitor) {
if (program == null || address == null) {
return null;
}
if (monitor.isCancelled()) {
if (program == null || address == null || monitor.isCancelled()) {
return null;
}
// first try to walk back up to the top of the function
UndefinedFunction function = findFunctionUsingSimpleBlockModel(program, address, monitor);
if (function != null) {
if (function != null || monitor.isCancelled()) {
return function;
}

View file

@ -16,7 +16,7 @@
/*
*
*/
package ghidra.program.database.util;
package ghidra.program.database;
import static org.junit.Assert.*;

View file

@ -17,14 +17,12 @@ package ghidra.program.database.symbol;
import static org.junit.Assert.*;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import org.junit.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.function.FunctionDB;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
@ -52,8 +50,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
super();
}
@Before
public void setUp() throws Exception {
@Before
public void setUp() throws Exception {
program = createDefaultProgram("Test", ProgramBuilder._TOY, this);
space = program.getAddressFactory().getDefaultAddressSpace();
namespaceManager = program.getNamespaceManager();
@ -65,14 +63,14 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
addBlock("BlockTwo", addr(0x2000), 0x4000);
}
@After
public void tearDown() throws Exception {
@After
public void tearDown() throws Exception {
program.endTransaction(transactionID, true);
program.release(this);
}
@Test
public void testCreateSubNamespace() throws Exception {
@Test
public void testCreateSubNamespace() throws Exception {
GhidraClass gc =
symbolMgr.createClass(globalNamespace, "classNamespace", SourceType.USER_DEFINED);
AddressSet set = new AddressSet();
@ -85,9 +83,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
AddressSet set2 = new AddressSet();
set2.addRange(addr(0x100), addr(0x130));
Function f2 =
functionMgr.createFunction("TextFunctionNamespace", addr(0x100), set2,
SourceType.USER_DEFINED);
Function f2 = functionMgr.createFunction("TextFunctionNamespace", addr(0x100), set2,
SourceType.USER_DEFINED);
f2.setParentNamespace(gc);
assertTrue(gc.getBody().hasSameAddresses(set.union(set2)));
@ -99,8 +96,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(f2, namespaceManager.getNamespaceContaining(addr(0x110)));
}
@Test
public void testGetBody() throws Exception {
@Test
public void testGetBody() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
AddressSet set = new AddressSet();
@ -139,8 +136,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(gcSet.hasSameAddresses(newSet));
}
@Test
public void testFullName() throws Exception {
@Test
public void testFullName() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
AddressSet set = new AddressSet();
@ -168,8 +165,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals("TestNamespaceClass::F3", f3.getName(true));
}
@Test
public void testRemoveNamespace() throws Exception {
@Test
public void testRemoveNamespace() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -206,22 +203,12 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0x100)));
assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0x255)));
try {
((FunctionDB) f2).checkDeleted();
Assert.fail("Function 2 should be marked as deleted!");
}
catch (ConcurrentModificationException e) {
}
try {
((FunctionDB) f3).checkDeleted();
Assert.fail("Function 3 should be marked as deleted!");
}
catch (ConcurrentModificationException e) {
}
Assert.assertTrue("Function 2 should be marked as deleted!", f2.isDeleted());
Assert.assertTrue("Function 3 should be marked as deleted!", f3.isDeleted());
}
@Test
public void testMoveNamespace() throws Exception {
@Test
public void testMoveNamespace() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
GhidraClass classNamespace2 =
@ -252,8 +239,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(classNamespace3, f2.getParentNamespace());
}
@Test
public void testMoveAddressRange() throws Exception {
@Test
public void testMoveAddressRange() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -287,8 +274,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(f2.getBody().hasSameAddresses(set2));
}
@Test
public void testMoveAddressRange2() throws Exception {
@Test
public void testMoveAddressRange2() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -319,8 +306,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(f2.getBody().hasSameAddresses(set2));
}
@Test
public void testDeleteAddressRange() throws Exception {
@Test
public void testDeleteAddressRange() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -344,8 +331,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0)));
}
@Test
public void testIsOverlappedNamespace() throws Exception {
@Test
public void testIsOverlappedNamespace() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -376,7 +363,6 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Should overlap!");
}
set2 = new AddressSet();
set.addRange(addr(0x200), addr(0x210));
set.addRange(addr(0x55), addr(0xff));
@ -386,8 +372,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
}
@Test
public void testNamespaceIteratorForOverlaps() throws Exception {
@Test
public void testNamespaceIteratorForOverlaps() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -438,8 +424,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testNamespaceIteratorForOverlaps2() throws Exception {
@Test
public void testNamespaceIteratorForOverlaps2() throws Exception {
GhidraClass classNamespace =
symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED);
@ -497,7 +483,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest {
}
private void addBlock(String name, Address addr, int length) throws Exception {
program.getMemory().createInitializedBlock(name, addr, length, (byte) 0,
TaskMonitorAdapter.DUMMY_MONITOR, false);
program.getMemory()
.createInitializedBlock(name, addr, length, (byte) 0,
TaskMonitorAdapter.DUMMY_MONITOR, false);
}
}

View file

@ -1389,7 +1389,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Listing listing = program.getListing();
Symbol s = createSymbol(addr(100), "fred");
assertTrue(s.checkIsValid());
assertFalse(s.isDeleted());
AddressSet set = new AddressSet();
set.addRange(addr(100), addr(150));
@ -1400,11 +1400,11 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Parameter p = f.addParameter(new ParameterImpl(null, ByteDataType.dataType, program),
SourceType.DEFAULT);
Symbol paramSym = p.getSymbol();
assertTrue(paramSym.checkIsValid());
assertFalse(paramSym.isDeleted());
listing.removeFunction(addr(100));
assertTrue(!paramSym.checkIsValid());
assertTrue(paramSym.isDeleted());
Symbol s1 = st.getPrimarySymbol(addr(100));
assertNotNull(s1);

View file

@ -15,8 +15,7 @@
*/
package ghidra.program.database.code;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import org.junit.*;
@ -80,12 +79,12 @@ public class DefaultDataCacheTest extends AbstractGenericTest {
assertTrue(cu instanceof Data);
DataDB data = (DataDB) cu;
assertTrue(!data.isDefined());
assertTrue(!data.isInvalid());
assertTrue(!((Boolean) invokeInstanceMethod("isInvalid", data)));
AddressSet restrictedSet = new AddressSet(addr(0x1000), addr(0x1003));
Disassembler disassembler = Disassembler.getDisassembler(program, TaskMonitor.DUMMY, null);
AddressSetView disAddrs = disassembler.disassemble(addr(0x1000), restrictedSet);
assertTrue(!disAddrs.isEmpty());
assertTrue(!data.checkIsValid());
assertTrue(!((Boolean) invokeInstanceMethod("checkIsValid", data)));
assertNull(listing.getCodeUnitAt(addr(0x1001)));
}

View file

@ -30,7 +30,6 @@ import ghidra.program.model.mem.Memory;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.util.AddressSetPropertyMap;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -615,7 +614,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
if (nsSymbol == null) {
return false; // global namespace.
}
return !nsSymbol.checkIsValid();
return nsSymbol.isDeleted();
}
/**

View file

@ -26,7 +26,7 @@ import ghidra.util.Lock;
* been deleted. Instantiating an object will cause it to be added immediately to the associated
* cache.
*/
abstract public class DatabaseObject {
public abstract class DatabaseObject {
protected long key;
private volatile boolean deleted;
@ -41,7 +41,7 @@ abstract public class DatabaseObject {
* @param key database key to uniquely identify this object
*/
@SuppressWarnings("unchecked")
public DatabaseObject(@SuppressWarnings("rawtypes") DBObjectCache cache, long key) {
protected DatabaseObject(@SuppressWarnings("rawtypes") DBObjectCache cache, long key) {
this.key = key;
this.cache = cache;
if (cache != null) {
@ -64,17 +64,6 @@ abstract public class DatabaseObject {
deleted = true;
}
/**
* Returns true if this object has been deleted. Note: once an object has been deleted, it will
* never be "refreshed". For example, if an object is ever deleted and is resurrected via an
* "undo", you will have get a fresh instance of the object.
*
* @return true if this object has been deleted.
*/
public boolean isDeleted() {
return deleted;
}
/**
*
* Invalidate this object. This does not necessarily mean that this object can never be used
@ -101,21 +90,28 @@ abstract public class DatabaseObject {
}
/**
* Returns true if object is currently invalid. Calling checkIsValid may successfully refresh
* object making it valid.
* Returns true if object is currently invalid and must be validated prior to further use.
* An invalid object may result from a cache invalidation which corresponds to wide-spread
* record changes. A common situation where this can occur is an undo/redo operation
* against the underlying database. The methods {@link #checkIsValid()}, {@link #checkDeleted()},
* {@link #validate(Lock)} and {@link #isDeleted(Lock)} are methods which will force
* a re-validation if required.
*
* @see #checkIsValid()
* @return true if this object is invalid and must be re-validated, else false if object state
* is currently valid which may include a deleted state.
*/
public boolean isInvalid() {
return invalidateCount != getCurrentValidationCount();
protected boolean isInvalid() {
return !deleted && invalidateCount != getCurrentValidationCount();
}
/**
* Checks if this object has been deleted, in which case any use of the object is not allowed.
* This method should be invoked before any modifications to the object are performed to
* ensure it still exists and is in a valid state.
*
* @throws ConcurrentModificationException if the object has been deleted from the database.
*/
public void checkDeleted() {
protected void checkDeleted() {
if (!checkIsValid()) {
throw new ConcurrentModificationException("Object has been deleted.");
}
@ -125,9 +121,9 @@ abstract public class DatabaseObject {
* Check whether this object is still valid. If the object is invalid, the object will attempt
* to refresh itself. If the refresh fails, the object will be marked as deleted.
*
* @return true if the object is valid.
* @return true if the object is valid, else false if deleted
*/
public boolean checkIsValid() {
protected boolean checkIsValid() {
return checkIsValid(null);
}
@ -140,10 +136,7 @@ abstract public class DatabaseObject {
* @param record optional record which may be used to refresh invalid object
* @return true if the object is valid.
*/
public boolean checkIsValid(DBRecord record) {
if (deleted) {
return false;
}
protected boolean checkIsValid(DBRecord record) {
if (isInvalid()) {
setValid();// prevent checkIsValid recursion during refresh
if (!refresh(record)) {
@ -162,10 +155,10 @@ abstract public class DatabaseObject {
* invalid, then the lock will be used to refresh as needed.
*
* @param lock the lock that will be used if the object needs to be refreshed.
* @return true if object is valid, else false
* @return true if object is valid, else false if deleted
*/
public boolean validate(Lock lock) {
if (!deleted && !isInvalid()) {
protected boolean validate(Lock lock) {
if (!isInvalid()) {
return true;
}
lock.acquire();
@ -177,6 +170,18 @@ abstract public class DatabaseObject {
}
}
/**
* Returns true if this object has been deleted. Note: once an object has been deleted, it will
* never be "refreshed". For example, if an object is ever deleted and is resurrected via an
* "undo", you will have get a fresh instance of the object.
*
* @param lock object cache lock object
* @return true if this object has been deleted.
*/
public boolean isDeleted(Lock lock) {
return deleted || !validate(lock);
}
/**
* Tells the object to refresh its state from the database.
*

View file

@ -19,8 +19,8 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import db.Field;
import db.DBRecord;
import db.Field;
import ghidra.program.database.DBObjectCache;
import ghidra.program.database.DatabaseObject;
import ghidra.program.model.data.*;
@ -92,8 +92,7 @@ class CategoryDB extends DatabaseObject implements Category {
}
mgr.lock.acquire();
try {
checkIsValid();
if (isRoot() || isDeleted()) {
if (!checkIsValid() || isRoot()) {
categoryPath = CategoryPath.ROOT;
}
if (categoryPath == null) {

View file

@ -216,7 +216,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
*/
@Override
public boolean isDeleted() {
return !checkIsValid();
return isDeleted(lock);
}
/**

View file

@ -95,6 +95,11 @@ public class FunctionDB extends DatabaseObject implements Function {
frame = new FunctionStackFrame(this);
}
@Override
public boolean isDeleted() {
return isDeleted(manager.lock);
}
public void setValidationEnabled(boolean state) {
validateEnabled = state;
}
@ -105,6 +110,12 @@ public class FunctionDB extends DatabaseObject implements Function {
entryPoint = functionSymbol.getAddress();
}
@Override
protected void checkDeleted() {
// expose method to function package
super.checkDeleted();
}
@Override
public boolean isThunk() {
manager.lock.acquire();
@ -853,8 +864,7 @@ public class FunctionDB extends DatabaseObject implements Function {
private void renumberParameterOrdinals() {
int ordinal = autoParams != null ? autoParams.size() : 0;
for (int i = 0; i < params.size(); i++) {
ParameterDB param = params.get(i);
for (ParameterDB param : params) {
param.setOrdinal(ordinal++);
}
}
@ -1096,21 +1106,18 @@ public class FunctionDB extends DatabaseObject implements Function {
loadVariables();
ArrayList<Variable> list = new ArrayList<>();
if (autoParams != null) {
for (int i = 0; i < autoParams.size(); i++) {
Parameter p = autoParams.get(i);
for (AutoParameterImpl p : autoParams) {
if (filter == null || filter.matches(p)) {
list.add(p);
}
}
}
for (int i = 0; i < params.size(); i++) {
Parameter p = params.get(i);
for (ParameterDB p : params) {
if (filter == null || filter.matches(p)) {
list.add(p);
}
}
for (int i = 0; i < locals.size(); i++) {
Variable var = locals.get(i);
for (VariableDB var : locals) {
if (filter == null || filter.matches(var)) {
list.add(var);
}
@ -1140,15 +1147,13 @@ public class FunctionDB extends DatabaseObject implements Function {
loadVariables();
ArrayList<Parameter> list = new ArrayList<>();
if (autoParams != null) {
for (int i = 0; i < autoParams.size(); i++) {
Parameter p = autoParams.get(i);
for (AutoParameterImpl p : autoParams) {
if (filter == null || filter.matches(p)) {
list.add(p);
}
}
}
for (int i = 0; i < params.size(); i++) {
Parameter p = params.get(i);
for (ParameterDB p : params) {
if (filter == null || filter.matches(p)) {
list.add(p);
}
@ -1176,8 +1181,7 @@ public class FunctionDB extends DatabaseObject implements Function {
}
loadVariables();
ArrayList<Variable> list = new ArrayList<>();
for (int i = 0; i < locals.size(); i++) {
Variable var = locals.get(i);
for (VariableDB var : locals) {
if (filter == null || filter.matches(var)) {
list.add(var);
}
@ -1657,8 +1661,7 @@ public class FunctionDB extends DatabaseObject implements Function {
}
if (ordinal != params.size()) {
// shift params to make room for inserted param
for (int i = 0; i < params.size(); i++) {
ParameterDB param = params.get(i);
for (ParameterDB param : params) {
int paramOrdinal = param.getOrdinal();
if (paramOrdinal >= ordinal) {
param.setOrdinal(paramOrdinal + 1);

View file

@ -505,7 +505,7 @@ public class FunctionManagerDB implements FunctionManager {
try {
FunctionDB func = cache.get(key);
if (func != null) {
func.checkIsValid();
func.checkDeleted();
func.createClassStructIfNeeded();
func.updateParametersAndReturn();
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +15,8 @@
*/
package ghidra.program.database.function;
import java.util.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
@ -23,8 +24,6 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import java.util.*;
class FunctionStackFrame implements StackFrame {
// NOTE: Program stack frame may contain compound variables which have a stack component
@ -46,17 +45,17 @@ class FunctionStackFrame implements StackFrame {
}
boolean checkIsValid() {
if (function.checkIsValid()) {
if (invalid) {
stackGrowsNegative =
function.getFunctionManager().getProgram().getCompilerSpec().stackGrowsNegative();
variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER);
Arrays.sort(variables, StackVariableComparator.get());
invalid = false;
}
return true;
if (function.isDeleted()) {
return false;
}
return false;
if (invalid) {
stackGrowsNegative =
function.getFunctionManager().getProgram().getCompilerSpec().stackGrowsNegative();
variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER);
Arrays.sort(variables, StackVariableComparator.get());
invalid = false;
}
return true;
}
void checkDeleted() {
@ -101,9 +100,9 @@ class FunctionStackFrame implements StackFrame {
}
}
else {
for (int i = 0; i < params.length; i++) {
if (offset >= params[i].getLastStorageVarnode().getOffset()) {
ordinal = params[i].getOrdinal();
for (Parameter param : params) {
if (offset >= param.getLastStorageVarnode().getOffset()) {
ordinal = param.getOrdinal();
}
}
}
@ -159,9 +158,9 @@ class FunctionStackFrame implements StackFrame {
try {
checkIsValid();
ArrayList<Variable> list = new ArrayList<Variable>();
for (int i = 0; i < variables.length; i++) {
if (!(variables[i] instanceof Parameter)) {
list.add(variables[i]);
for (Variable variable : variables) {
if (!(variable instanceof Parameter)) {
list.add(variable);
}
}
Variable[] vars = new Variable[list.size()];
@ -182,9 +181,9 @@ class FunctionStackFrame implements StackFrame {
try {
checkIsValid();
ArrayList<Parameter> list = new ArrayList<Parameter>();
for (int i = 0; i < variables.length; i++) {
if (variables[i] instanceof Parameter) {
list.add((Parameter) variables[i]);
for (Variable variable : variables) {
if (variable instanceof Parameter) {
list.add((Parameter) variable);
}
}
Parameter[] vars = new Parameter[list.size()];
@ -329,8 +328,8 @@ class FunctionStackFrame implements StackFrame {
try {
checkIsValid();
int cnt = 0;
for (int i = 0; i < variables.length; i++) {
if (variables[i] instanceof Parameter) {
for (Variable variable : variables) {
if (variable instanceof Parameter) {
++cnt;
}
}

View file

@ -25,7 +25,6 @@ import db.*;
import db.util.ErrorHandler;
import ghidra.program.database.*;
import ghidra.program.database.external.ExternalManagerDB;
import ghidra.program.database.function.FunctionDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.database.symbol.*;
import ghidra.program.model.address.*;
@ -638,13 +637,12 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
lock.acquire();
try {
Function function = var.getFunction();
if (!(function instanceof FunctionDB) || function.getProgram() != program ||
!((FunctionDB) function).checkIsValid()) {
if (function.getProgram() != program || function.isDeleted()) {
return NO_REFS;
}
SymbolDB varSymbol = (SymbolDB) var.getSymbol();
if (varSymbol != null && !varSymbol.checkIsValid()) {
if (varSymbol != null && varSymbol.isDeleted()) {
return NO_REFS;
}

View file

@ -82,6 +82,17 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
lock = symbolMgr.getLock();
}
@Override
public boolean isDeleted() {
return isDeleted(lock);
}
@Override
protected void checkDeleted() {
// expose method to symbol package
super.checkDeleted();
}
@Override
public String toString() {
return getName();

View file

@ -34,8 +34,8 @@ public class GlobalSymbol implements Symbol {
}
@Override
public boolean checkIsValid() {
return true;
public boolean isDeleted() {
return false;
}
@Override

View file

@ -711,4 +711,11 @@ public interface Function extends Namespace {
* symbol will be removed.
*/
public void promoteLocalUserLabelsToGlobal();
/**
* Determine if this function object has been deleted. NOTE: the function could be
* deleted at anytime due to asynchronous activity.
* @return true if function has been deleted, false if not.
*/
public boolean isDeleted();
}

View file

@ -109,6 +109,7 @@ public interface Variable extends Comparable<Variable> {
/**
* Returns the function that contains this Variable. May be null if the variable is not in
* a function.
* @return containing function or null
*/
public Function getFunction();
@ -190,7 +191,7 @@ public interface Variable extends Comparable<Variable> {
/**
* @return true if this is a simple variable consisting of a single register varnode
* which will be returned by either the {@link #getFirstStorageVarnode()} or
* {@link getLastStorageVarnode()} methods. The register can be obtained using the
* {@link #getLastStorageVarnode()} methods. The register can be obtained using the
* {@link #getRegister()} method.
*/
public boolean isRegisterVariable();
@ -262,11 +263,13 @@ public interface Variable extends Comparable<Variable> {
/**
* @return the symbol associated with this variable or null if no symbol
* associated. Certain dynamic variables such as auto-parameters do not
* have a symbol.
* have a symbol and will return null.
*/
public Symbol getSymbol();
/**
* Determine is another variable is equivalent to this variable.
* @param variable other variable
* @return true if the specified variable is equivalent to this variable
*/
public boolean isEquivalent(Variable variable);

View file

@ -40,12 +40,6 @@ public interface Symbol {
*/
public String getName();
/**
* Check whether this symbol is still valid (i.e., deleted).
* @return true if valid or false if deleted.
*/
public boolean checkIsValid();
/**
* Gets the full path name for this symbol as an ordered array of strings ending
* with the symbol name. The global symbol will return an empty array.
@ -67,12 +61,14 @@ public interface Symbol {
public String getName(boolean includeNamespace);
/**
* @return the namespace that contains this symbol
* Return the parent namespace for this symbol.
* @return the namespace that contains this symbol.
*/
public Namespace getParentNamespace();
/**
* Returns namespace symbol of the namespace containing this symbol
* @return parent namespace symbol
*/
public Symbol getParentSymbol();
@ -84,14 +80,16 @@ public interface Symbol {
public boolean isDescendant(Namespace namespace);
/**
* Returns whether the given parent is valid for this Symbol.
* @param parent
* Determines if the given parent is valid for this Symbol. Specified namespace
* must belong to the same symbol table as this symbol.
* @param parent prospective parent namespace for this symbol
* @return true if parent is valid
*/
public boolean isValidParent(Namespace parent);
/**
* Returns the symbol type
* Returns this symbol's type
* @return symbol type
*/
public SymbolType getSymbolType();
@ -273,4 +271,11 @@ public interface Symbol {
* @return the source of this symbol
*/
public SourceType getSource();
/**
* Determine if this symbol object has been deleted. NOTE: the symbol could be
* deleted at anytime due to asynchronous activity.
* @return true if symbol has been deleted, false if not.
*/
public boolean isDeleted();
}

View file

@ -47,6 +47,11 @@ public class FunctionTestDouble implements Function {
functionSignature = signature;
}
@Override
public boolean isDeleted() {
return false;
}
@Override
public String toString() {
return name;