Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ida-explorer: fix TypeError when sorting locations with mixed address types#2867

Merged
mike-hunhoff merged 3 commits intomandiant:masterfrom
devs6186:fix/2195-ida-address-sort
Feb 26, 2026
Merged

ida-explorer: fix TypeError when sorting locations with mixed address types#2867
mike-hunhoff merged 3 commits intomandiant:masterfrom
devs6186:fix/2195-ida-address-sort

Conversation

Copy link
Contributor

devs6186 commented Feb 18, 2026

closes #2195

When a feature has multiple matched locations and those locations contain a mix of integer-based addresses (e.g. AbsoluteVirtualAddress) and _NoAddress, calling sorted(locations) raises a TypeError:

TypeError: '<' not supported between instances of 'AbsoluteVirtualAddress' and '_NoAddress'

This happens because Python's sort evaluates AbsoluteVirtualAddress(x) < _NoAddress(), which falls through to int.__lt__(x, _NoAddress()) - NotImplemented, then tries the reflected operation _NoAddress.__gt__(x). Since _NoAddress does not define __gt__, Python falls back to the object default which also returns NotImplemented, causing the TypeError.

Fix: Add a sort key to sorted(locations) in render_capa_doc_feature_node that places integer-based addresses first (sorted by value) and non-integer addresses (e.g. _NoAddress) last, avoiding the cross-type comparison entirely.

Checklist

  • No CHANGELOG update needed
  • No new tests needed
  • No documentation update needed
  • This submission includes AI-generated code and I have provided details in the description.

Copy link

google-cla bot commented Feb 18, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Contributor

gemini-code-assist bot commented Feb 18, 2026

Summary of Changes

Hello @devs6186, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in the IDA Explorer plugin where attempting to sort feature locations with mixed address types would result in a TypeError. The fix introduces a custom sort key to prevent incompatible type comparisons, ensuring robust handling of diverse address representations and improving the stability of feature rendering.

Highlights

  • Fixed TypeError in IDA Explorer: Resolved a TypeError that occurred when sorting feature locations containing a mix of integer-based addresses (e.g., AbsoluteVirtualAddress) and _NoAddress types within the IDA Pro plugin.

New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • capa/ida/plugin/model.py
    • Fixed TypeError when sorting locations containing mixed address types.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini or @gemini-code-assist . Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with and on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. -

Copy link
Contributor

gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively resolves a TypeError that occurs when sorting a list of feature locations with mixed address types, such as AbsoluteVirtualAddress and _NoAddress. The fix introduces a custom sort key that correctly groups integer-based addresses and non-integer addresses, preventing the cross-type comparison that caused the error. The implementation is clean and directly addresses the issue. The changelog has also been updated accordingly. Overall, this is a solid contribution that improves the robustness of the IDA explorer plugin.

Copy link
Contributor Author

devs6186 commented Feb 18, 2026

I have read the CLA Document and I hereby sign the CLA

devs6186 closed this Feb 18, 2026
devs6186 reopened this Feb 18, 2026
devs6186 force-pushed the fix/2195-ida-address-sort branch from df3308d to 827700e Compare February 18, 2026 22:40
Copy link
Contributor Author

devs6186 commented Feb 18, 2026

Thanks for the review! Appreciate the confirmation that the sort key approach is clean.

Copy link
Collaborator

williballenthin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks fine for ida-explorer, but i wonder if there are other places in the code with this pattern?

or, even better, could we fix the comparison routines for all addresses directly? so we can just do sorted(locations) and it works as intended?

Copy link
Contributor Author

devs6186 commented Feb 19, 2026

this looks fine for ida-explorer, but i wonder if there are other places in the code with this pattern?

or, even better, could we fix the comparison routines for all addresses directly? so we can just do sorted(locations) and it works as intended?

this looks fine for ida-explorer, but i wonder if there are other places in the code with this pattern?

or, even better, could we fix the comparison routines for all addresses directly? so we can just do sorted(locations) and it works as intended?

Thanks a lot for the review!

_1. Other places with this pattern-:_
Yes -- the same pattern also appears in capa/ida/plugin/view.py.
Line 1054 uses sorted(features.items(), key=lambda k: sorted(k[1])), where sorted(k[1]) operates on lists of addresses that may include both AbsoluteVirtualAddress and _NoAddress.

Line 1077 does for addr in sorted(addrs), which can hit the same mixed-type comparison issue when a feature has no address (e.g., line 1085 constructs _NoAddress()).

So the same TypeError is possible there as well.

The only other sorted(locations) I found is in capa/render/vverbose.py (line 75), but that path uses frozen addresses (frz.Address). Those already implement a proper lt in capa/features/freeze, so they shouldn't be affected.

2. Fixing comparison at the source
I agree that fixing this in capa/features/address.py is the cleaner solution.
Right now, the failure happens because:
AbsoluteVirtualAddress subclasses int, so ava < noaddr delegates to int.lt, which returns NotImplemented.
Python then attempts the reflected operation _NoAddress.gt(ava).
Since _NoAddress doesn't define gt, that also resolves to NotImplemented, and Python raises a TypeError.
One straightforward fix would be to implement gt on _NoAddress, for example returning other is not self, effectively treating "no address" as greater than any real address (so it sorts last). With that in place, sorted(locations) would work consistently everywhere without needing per-call-site sort keys.

A Sample Snippet for your Reference before I Implement-

  1. To Add gt to _NoAddress (so "no address" sorts after real addresses):
class _NoAddress(Address):
def __eq__(self, other):
return True

def __lt__(self, other):
return False

def __gt__(self, other):
# So that mixed-type comparison works: (real_address < NO_ADDRESS) uses this.
# NoAddress sorts last.
return other is not self

def __hash__(self):
return hash(0)

def __repr__(self):
return "no address"
  1. In capa/ida/plugin/model.py -- revert to a simple sort (no key):
    for location in sorted(locations):

  2. In capa/ida/plugin/view.py -- keep using sorted(); no change needed once gt is in place:
    Line 1054: sorted(features.items(), key=lambda k: sorted(k[1]))
    Line 1077: for addr in sorted(addrs):
    Both will work as-is after the _NoAddress.gt change.

I'm happy to proceed in either of the following ways:
Expand this PR to add the same sort-key workaround in view.py (lines 1054 and 1077), and

Either in a follow-up PR (or in this one, if you prefer), add _NoAddress.gt in address.py and then remove the custom sort keys in both model.py and view.py, so we can just use sorted(locations) / sorted(addrs) directly.

Let me know whether you'd prefer the IDA-side workarounds first with the address fix in a separate PR, or if you'd like everything handled together in this one.

Copy link
Collaborator

williballenthin commented Feb 19, 2026

the gt solution sounds great, thanks for the careful study. let's update this PR with that strategy and use it consistently throughout.

Copy link
Contributor Author

devs6186 commented Feb 19, 2026

Done. I've updated the PR to use the gt approach and keep it consistent:

capa/features/address.py -- Implemented gt on _NoAddress so that "no address" is greater than any real address and sorts last. That way sorted(locations) and sorted(addrs) work everywhere without special keys, and we avoid the mixed-type TypeError at the source.

capa/ida/plugin/model.py -- Dropped the custom sort key and now use plain sorted(locations).

capa/ida/plugin/view.py -- No edits. The existing sorted(k[1]) and sorted(addrs) (lines 1054 and 1077)
now behave correctly with mixed address types thanks to the address comparison fix.
I ran the engine and rules tests; all passed.

williballenthin approved these changes Feb 20, 2026
mike-hunhoff requested changes Feb 23, 2026
devs6186 added 3 commits February 24, 2026 08:55
When a feature has multiple locations and those locations contain a mix
of integer-based addresses (e.g. AbsoluteVirtualAddress) and non-integer
addresses (e.g. _NoAddress), calling sorted() raises a TypeError because
Python falls back to the reflected comparison (__gt__) which is not
defined on _NoAddress.

Add a sort key to sorted() that places integer-based addresses first
(sorted by value) and non-integer addresses last, avoiding the
cross-type comparison.

Fixes mandiant#2195
...rywhere

Implement the gt solution per review: fix comparison for all addresses
so we can use sorted(locations) / sorted(addrs) consistently without
per-call-site sort keys.

- Add _NoAddress.__gt__ so mixed-type comparison works: (real_address <
NO_ADDRESS) invokes it and NoAddress sorts last. Avoids TypeError
when sorting AbsoluteVirtualAddress with _NoAddress.
- In ida/plugin/model.py, use sorted(locations) instead of a custom
key. view.py (lines 1054, 1077) already use sorted(); they now work
with mixed address types without change.

Fixes mandiant#2195
Per maintainer feedback: fix applies beyond ida-explorer.
devs6186 force-pushed the fix/2195-ida-address-sort branch from 61caee5 to 872c7e3 Compare February 24, 2026 03:26
devs6186 requested a review from mike-hunhoff February 24, 2026 03:48
mike-hunhoff approved these changes Feb 24, 2026
mike-hunhoff merged commit e1ffa1d into mandiant:master Feb 26, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

williballenthin williballenthin approved these changes

mike-hunhoff mike-hunhoff approved these changes

+1 more reviewer

gemini-code-assist[bot] gemini-code-assist[bot] left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

ida-explorer: '<' not supported between instances of 'AbsoluteVirtualAddress' and '_NoAddress'

3 participants