GP-6691 - Find Uses of - Fixed flaws in finding structure field uses in the DataTypeReference API

This commit is contained in:
dragonmacher
2026-06-11 12:20:17 -04:00
parent b66180204a
commit 773be4fc26
6 changed files with 394 additions and 117 deletions
@@ -4,9 +4,9 @@
* 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.
@@ -94,7 +94,7 @@ public class FieldMatcher {
}
return dataType.getName() + " at " + fieldOffsets.toString();
}
return dataType.getName();
return dataType.getName() + " <matches all fields>";
}
private String generateCompositeFieldNameByOffset() {
@@ -17,12 +17,15 @@ package ghidra.app.extension.datatype.finder;
import java.util.List;
import docking.widgets.search.SearchLocationContext;
import ghidra.app.decompiler.ClangFieldToken;
import ghidra.app.decompiler.ClangLine;
import ghidra.app.services.DataTypeReference;
import ghidra.app.services.FieldMatcher;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Function;
/**
* This class represents the use of a field of a {@link Composite} data type <b>where there is no
@@ -84,12 +87,18 @@ public class AnonymousVariableAccessDR extends VariableAccessDR {
// referring to the field and not the composite.
//
if (fieldMatcher.isIgnored()) {
if (matchesFieldType) {
// no field name and the search type matches this reference's field type
String fieldName = variable.getName();
results.add(createReference(variable, fieldName));
// no field to match and the search type matches this composite's field type
String fieldName = null;
DataTypeReference ref = createReferenceToVariable(variable, fieldName);
results.add(ref);
}
// else there is no field and the search type does not match the reference's type
// else there is no field to match and the search type matched the composite type; as
// mentioned in the comment above, we are ignoring the match on the composite, as
// that is handled by the VariableAccessDR, which gets created before this object as the
// tokens are being parsed.
return;
}
@@ -99,11 +108,20 @@ public class AnonymousVariableAccessDR extends VariableAccessDR {
// The client has requested a particular field of the parent composite. We only have a
// match if the parent type matches and the field name/offset matches.
//
String text = field.getText();
String fieldName = field.getText();
int offset = field.getOffset();
if (matchesCompositeType && fieldMatcher.matches(text, offset)) {
results.add(new DataTypeReference(compositeType, fieldMatcher.getFieldName(),
getFunction(), getAddress(), getContext()));
if (!fieldMatcher.matches(fieldName, offset)) {
return; // the field does not match
}
if (matchesCompositeType) {
Function function = getFunction();
Address address = getAddress();
SearchLocationContext context = getContext();
results.add(
new DataTypeReference(compositeType, fieldName, function, address, context));
}
// else, matches the composite's field type, but not the parent type; this fails the
// requirement that the composite type must match when searching for a field
}
}
@@ -478,8 +478,12 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
DtrfDbg.println(function,
"\tcreating an anonymous variable access: " + line);
// this can happen when a field is used anonymously, such as directly
// after a nested array index operation
// This can happen when a field is used anonymously, such as directly
// after a nested array index operation. 'anonymous' here means that there
// is no named variable in the decompiler that is being dereferenced. In
// addition to seeing this for array accesses, we will also see this for
// nested composite access, like foo->bar->baz. 'baz' is being accessed
// anonymously.
results.add(new AnonymousVariableAccessDR(line, field));
continue;
}
@@ -497,15 +501,38 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
return false; // should not happen
}
/*
Unusual Code: The data type of 'field' is usually the parent structure that contains
the field (not always though?). Also, apparently sometimes the data type of the
'variable' in 'access' is that of the field being accessed instead of the parent
structure. I'm guessing these conditions are bugs. Normally, the data type of
'variable' should be the parent containing type and the data type of 'field' should
be contained in the parent type.
This is used to determine when parent->child relationship is not correct so that we
can create an special access type to represent that.
*/
DataType parentType = field.getDataType();
DataType variableType = variable.getDataType();
if (DecompilerReference.isEqual(parentType, variableType)) {
return false; // the types match; this is the normal flow
}
// Note: the field's type is that of the parent structure, not the field. We want the
// field's type, so we must retrieve that.
DataType fieldDt = DecompilerReference.getFieldDataType(field);
DataType fieldType = DecompilerReference.getFieldDataType(field);
// check for the unusual case where the 'variable' type may be that of the field
if (DecompilerReference.isEqual(variableType, fieldType)) {
// Note: it would be nice to find a case(s) to verify this path
return false; // the types match; this is the normal flow
}
return true;
// unusual code: getDataType() on the variable may return the type of the field being
// accessed. Contrastingly, getDataType() on the field may return the
// type of the parent structure.
DataType variableDt = variable.getDataType();
return !DecompilerReference.isEqual(variableDt, fieldDt);
}
private VariableAccessDR getLastAccess(List<DecompilerReference> variables) {
@@ -88,8 +88,7 @@ public abstract class DecompilerReference {
}
protected SearchLocationContext getContext() {
SearchLocationContext context = getContext(variable);
return context;
return getContext(variable);
}
protected SearchLocationContext getContext(DecompilerVariable var) {
@@ -78,4 +78,5 @@ public abstract class VariableDR extends DecompilerReference {
results.add(new DataTypeReference(dataType, fieldName, function, address, context));
}
}
}