From c81657d2ae45c8c4978114f3d2e6bcd361ce54ef Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:55:14 +0000 Subject: [PATCH] GP-6486 Correct distance calculation in nearestArrayedComponent methods --- .../src/decompile/cpp/ruleaction.cc | 50 ++--- .../Decompiler/src/decompile/cpp/type.cc | 176 +++++++++--------- .../Decompiler/src/decompile/cpp/type.hh | 14 +- 3 files changed, 120 insertions(+), 120 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 6ef6296904..9b92b3e2fe 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -6087,39 +6087,41 @@ bool AddTreeState::hasMatchingSubType(int8 off,uint4 arrayHint,int8 *newoff) con int8 elSizeBefore; int8 offBefore; - Datatype *typeBefore = baseType->nearestArrayedComponentBackward(off, &offBefore, &elSizeBefore); - if (typeBefore != (Datatype *)0) { - if (arrayHint == 1 || elSizeBefore == arrayHint) { - int8 sizeAddr = AddrSpace::byteToAddressInt(typeBefore->getSize(),ct->getWordSize()); - if (offBefore >= 0 && offBefore < sizeAddr) { - // If the offset is \e inside a component with a compatible array, return it. - *newoff = offBefore; - return true; - } - } - } + int8 typeBefore = baseType->nearestArrayedComponentBackward(off, 128, &offBefore, &elSizeBefore); int8 elSizeAfter; int8 offAfter; - Datatype *typeAfter = baseType->nearestArrayedComponentForward(off, &offAfter, &elSizeAfter); - if (typeBefore == (Datatype *)0 && typeAfter == (Datatype *)0) + int8 typeAfter = baseType->nearestArrayedComponentForward(off, 128, &offAfter, &elSizeAfter); + if (typeBefore < 0 && typeAfter < 0) return (baseType->getSubType(off,newoff) != (Datatype *)0); - if (typeBefore == (Datatype *)0) { + if (typeBefore < 0) { + *newoff = offAfter; // Only array is after + return true; + } + if (typeAfter < 0) { + *newoff = offBefore; // Only array is before + return true; + } + if (offAfter == offBefore) { *newoff = offAfter; return true; } - if (typeAfter == (Datatype *)0) { - *newoff = offBefore; - return true; + // Reaching here we know there is an array before and an array after the offset point + if (arrayHint != 1 && elSizeBefore != elSizeAfter) { // element sizes are different, try to distinguish by arrayHint + if (elSizeBefore == arrayHint) { + *newoff = offBefore; + return true; + } + if (elSizeAfter == arrayHint) { + *newoff = offAfter; + return true; + } + } + if (baseType->getSubType(off,newoff) != (Datatype *)0) { + if (*newoff == offBefore || *newoff == offAfter) + return true; // Offset is contained in one of the arrayed components. Return it. } - uint8 distBefore = (offBefore < 0) ? -offBefore : offBefore; uint8 distAfter = (offAfter < 0) ? -offAfter : offAfter; - if (arrayHint != 1) { - if (elSizeBefore != arrayHint) - distBefore += 0x1000; - if (elSizeAfter != arrayHint) - distAfter += 0x1000; - } *newoff = (distAfter < distBefore) ? offAfter : offBefore; return true; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index 2d48650e70..c77ca9cf95 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -179,30 +179,33 @@ Datatype *Datatype::getSubType(int8 off,int8 *newoff) const return (Datatype *)0; } -/// Find the first component data-type that is (or contains) an array starting after the given -/// offset, and pass back the difference between the component's start and the given offset. -/// Return the component data-type or null if no array is found. +/// If \b this data-type is (or contains) an array starting after the given +/// offset, return the distance in bytes to the start of the array, +/// and pass back the difference between the component's start and the given offset. /// \param off is the given offset into \b this data-type +/// \param max is the maximum distance, in bytes, to search /// \param newoff is used to pass back the offset difference /// \param elSize is used to pass back the array element size -/// \return the component data-type or null -Datatype *Datatype::nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const +/// \return the distance to the array or -1 otherwise +int8 Datatype::nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { - return (TypeArray *)0; + return -1; } -/// Find the last component data-type that is (or contains) an array starting before the given -/// offset, and pass back the difference between the component's start and the given offset. +/// If \b this data-type is (or contains) an array starting before the given +/// offset, return the distance in bytes to the end of the array, +/// and pass back the difference between the component's start and the given offset. /// Return the component data-type or null if no array is found. /// \param off is the given offset into \b this data-type +/// \param max is the maximum distance, in bytes, to search /// \param newoff is used to pass back the offset difference /// \param elSize is used to pass back the array element size -/// \return the component data-type or null -Datatype *Datatype::nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const +/// \return the distance to the array or -1 otherwise +int8 Datatype::nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { - return (TypeArray *)0; + return -1; } /// Order \b this with another data-type, in a way suitable for the type propagation algorithm. @@ -1132,14 +1135,10 @@ bool TypePointer::testForArraySlack(Datatype *dt,int8 off) int8 elSize; if (dt->getMetatype() == TYPE_ARRAY) return true; - Datatype *compType; if (off < 0) { - compType = dt->nearestArrayedComponentForward(off, &newoff, &elSize); + return (dt->nearestArrayedComponentForward(off, 128, &newoff, &elSize) >= 0); } - else { - compType = dt->nearestArrayedComponentBackward(off, &newoff, &elSize); - } - return (compType != (Datatype *)0); + return (dt->nearestArrayedComponentBackward(off, 128, &newoff, &elSize) >= 0); } /// Parse a \ element with a child describing the data-type being pointed to @@ -1378,6 +1377,26 @@ Datatype *TypeArray::getSubType(int8 off,int8 *newoff) const return arrayof; } +int8 TypeArray::nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const + +{ + if (off > 0) return -1; // Skip if we are in the middle of array + *newoff = off; + *elSize = arrayof->getAlignSize(); + return -off; +} + +int8 TypeArray::nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const + +{ + if (off < 0) return -1; // Skip if we are before array + *newoff = off; + *elSize = arrayof->getAlignSize(); + if (off <= size) + return (size - off); + return (off - size); +} + int4 TypeArray::getHoleSize(int4 off) const { @@ -1886,7 +1905,7 @@ int4 TypeStruct::getHoleSize(int4 off) const return getSize() - off; // Distance to end of structure } -Datatype *TypeStruct::nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const +int8 TypeStruct::nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { int4 firstIndex = getLowerBoundField(off); @@ -1894,28 +1913,23 @@ Datatype *TypeStruct::nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 while(i >= 0) { const TypeField &subfield( field[i] ); int8 diff = off - subfield.offset; - if (diff > 128) break; Datatype *subtype = subfield.type; - if (subtype->getMetatype() == TYPE_ARRAY) { + int8 suboff; + int8 remain = (i == firstIndex) ? diff : subtype->getSize(); + if (diff - remain > max) break; + int8 distance = subtype->nearestArrayedComponentBackward(remain, max, &suboff, elSize); + if (distance >= 0) { + distance = (diff - remain) + distance; + if (distance > max) break; *newoff = diff; - *elSize = ((TypeArray *)subtype)->getBase()->getAlignSize(); - return subtype; - } - else { - int8 suboff; - int8 remain = (i == firstIndex) ? diff : subtype->getSize() - 1; - Datatype *res = subtype->nearestArrayedComponentBackward(remain, &suboff, elSize); - if (res != (Datatype *)0) { - *newoff = diff; - return subtype; - } + return distance; } i -= 1; } - return (Datatype *)0; + return -1; } -Datatype *TypeStruct::nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const +int8 TypeStruct::nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { int4 i = getLowerBoundField(off); @@ -1924,39 +1938,26 @@ Datatype *TypeStruct::nearestArrayedComponentForward(int8 off,int8 *newoff,int8 i += 1; // First component starting after remain = 0; } - else { - const TypeField &subfield( field[i] ); - remain = off - subfield.offset; - if (remain != 0 && (subfield.type->getMetatype() != TYPE_STRUCT || remain >= subfield.type->getSize())) { - i += 1; // Middle of non-structure that we must go forward from, skip over it - remain = 0; - } - } + else + remain = off - field[i].offset; while(i 128) break; + if (diff + remain > max) break; Datatype *subtype = subfield.type; - if (subtype->getMetatype() == TYPE_ARRAY) { + int8 suboff; + int8 distance = subtype->nearestArrayedComponentForward(remain, max, &suboff, elSize); + if (distance >= 0) { + distance = diff + remain + distance; + if (distance > max) + break; *newoff = -diff; - *elSize = ((TypeArray *)subtype)->getBase()->getAlignSize(); - return subtype; - } - else { - int8 suboff; - Datatype *res = subtype->nearestArrayedComponentForward(remain, &suboff, elSize); - if (res != (Datatype *)0) { - int8 subdiff = diff + remain - suboff; - if (subdiff > 128) - break; - *newoff = -diff; - return subtype; - } + return distance; } i += 1; remain = 0; } - return (Datatype *)0; + return -1; } int4 TypeStruct::compare(const Datatype &op,int4 level) const @@ -3389,7 +3390,7 @@ Datatype *TypeSpacebase::getSubType(int8 off,int8 *newoff) const return smallest->getSymbol()->getType(); } -Datatype *TypeSpacebase::nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const +int8 TypeSpacebase::nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { Scope *scope = getMap(); @@ -3406,55 +3407,50 @@ Datatype *TypeSpacebase::nearestArrayedComponentForward(int8 off,int8 *newoff,in nextAddr = addr + 32; else { symbolType = smallest->getSymbol()->getType(); - if (symbolType->getMetatype() == TYPE_STRUCT) { - int8 structOff = addr.getOffset() - smallest->getAddr().getOffset(); - int8 dummyOff; - Datatype *res = symbolType->nearestArrayedComponentForward(structOff, &dummyOff, elSize); - if (res != (Datatype *)0) { - *newoff = structOff; - return symbolType; - } + int8 structOff = addr.getOffset() - smallest->getAddr().getOffset(); + int8 dummyOff; + int8 distance = symbolType->nearestArrayedComponentForward(structOff, max, &dummyOff, elSize); + if (distance >= 0) { + if (distance > max) + return -1; + *newoff = structOff; + return distance; } int8 sz = AddrSpace::byteToAddressInt(smallest->getSize(), spaceid->getWordSize()); nextAddr = smallest->getAddr() + sz; } if (nextAddr < addr) - return (Datatype *)0; // Don't let the address wrap + return -1; // Don't let the address wrap smallest = scope->queryContainer(nextAddr,1,nullPoint); if (smallest == (SymbolEntry *)0 || smallest->getOffset() != 0) - return (Datatype *)0; + return -1; symbolType = smallest->getSymbol()->getType(); *newoff = addr.getOffset() - smallest->getAddr().getOffset(); - if (symbolType->getMetatype() == TYPE_ARRAY) { - *elSize = ((TypeArray *)symbolType)->getBase()->getAlignSize(); - return symbolType; + int8 dummyOff; + int8 distance = symbolType->nearestArrayedComponentForward(0, max, &dummyOff, elSize); + if (distance >= 0) { + distance = distance - *newoff; + if (distance > max) + return -1; + return distance; } - if (symbolType->getMetatype() == TYPE_STRUCT) { - int8 dummyOff; - Datatype *res = symbolType->nearestArrayedComponentForward(0, &dummyOff, elSize); - if (res != (Datatype *)0) - return symbolType; - } - return (Datatype *)0; + return -1; } -Datatype *TypeSpacebase::nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const +int8 TypeSpacebase::nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const { Datatype *subType = getSubType(off, newoff); if (subType == (Datatype *)0) - return (Datatype *)0; - if (subType->getMetatype() == TYPE_ARRAY) { - *elSize = ((TypeArray *)subType)->getBase()->getAlignSize(); - return subType; + return -1; + int8 dummyOff; + int8 distance = subType->nearestArrayedComponentBackward(*newoff,max,&dummyOff,elSize); + if (distance >= 0) { + if (distance > max) + return -1; + return distance; } - if (subType->getMetatype() == TYPE_STRUCT) { - int8 dummyOff; - Datatype *res = subType->nearestArrayedComponentBackward(*newoff,&dummyOff,elSize); - if (res != (Datatype *)0) - return subType; - } - return (Datatype *)0; + return -1; } int4 TypeSpacebase::compare(const Datatype &op,int4 level) const diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index 5a2edb37b9..a49726b0f4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -249,8 +249,8 @@ public: virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream virtual const TypeField *findTruncation(int8 off,int4 sz,const PcodeOp *op,int4 slot,int8 &newoff) const; virtual Datatype *getSubType(int8 off,int8 *newoff) const; ///< Recover component data-type one-level down - virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const; - virtual Datatype *nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; /// \brief Get number of bytes at the given offset that are padding /// @@ -500,6 +500,8 @@ public: Datatype *getSubEntry(int4 off,int4 sz,int4 *newoff,int4 *el) const; ///< Figure out what a byte range overlaps virtual void printRaw(ostream &s) const; virtual Datatype *getSubType(int8 off,int8 *newoff) const; + virtual int8 nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; virtual int4 getHoleSize(int4 off) const; virtual int4 numDepend(void) const { return 1; } virtual Datatype *getDepend(int4 index) const { return arrayof; } @@ -585,8 +587,8 @@ public: bool hasBitFieldsInRange(int4 offset,int4 sz) const; ///< Return \b true if \b this structure has 1 or more bitfields in the given byte range virtual const TypeField *findTruncation(int8 off,int4 sz,const PcodeOp *op,int4 slot,int8 &newoff) const; virtual Datatype *getSubType(int8 off,int8 *newoff) const; - virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const; - virtual Datatype *nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; virtual int4 getHoleSize(int4 off) const; virtual int4 numDepend(void) const { return field.size(); } virtual Datatype *getDepend(int4 index) const { return field[index].type; } @@ -803,8 +805,8 @@ public: Scope *getMap(void) const; ///< Get the symbol table indexed by \b this Address getAddress(uintb off,int4 sz,const Address &point) const; ///< Construct an Address given an offset virtual Datatype *getSubType(int8 off,int8 *newoff) const; - virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const; - virtual Datatype *nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentForward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; + virtual int8 nearestArrayedComponentBackward(int8 off,int8 max,int8 *newoff,int8 *elSize) const; virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual Datatype *clone(void) const { return new TypeSpacebase(*this); }