aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--idatui/app.py5
-rw-r--r--tests/test_project_ui.py23
2 files changed, 27 insertions, 1 deletions
diff --git a/idatui/app.py b/idatui/app.py
index f589cea..c3578da 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -2120,7 +2120,10 @@ class SymbolPalette(ModalScreen):
for h in hits:
at = h.text.lower().find(q)
scored.append((at if at >= 0 else 1 << 30, len(h.text), h.text, h))
- scored.sort()
+ # Sort on an explicit key: the same symbol name in two binaries ties
+ # on (position, length, text), and a bare sort() would then fall
+ # through to comparing Hit objects, which aren't orderable.
+ scored.sort(key=lambda t: (t[0], t[1], t[2], t[3].binary, t[3].addr))
rows = [(h.binary, h.addr, h.text,
tuple(range(at, at + len(q))) if at < (1 << 30) else ())
for at, _, _, h in scored[:self.LIMIT]]
diff --git a/tests/test_project_ui.py b/tests/test_project_ui.py
index 025107d..8a0fd2b 100644
--- a/tests/test_project_ui.py
+++ b/tests/test_project_ui.py
@@ -138,6 +138,29 @@ async def run(bins):
again and app._cur.ea == where,
f"cur={app._cur.ea if app._cur else None} want={where}")
+ # -- project-wide symbol search ------------------------------- #
+ # 'main' exists in BOTH binaries: identical name, so the rank tuple
+ # ties and a bare sort() would fall through to comparing Hit objects
+ # ('<' not supported between instances of 'Hit').
+ from idatui.app import SymbolPalette
+ await settle(lambda: app._index is not None
+ and len(app._index.counts()) == 2, 60)
+ check("both binaries got indexed",
+ len(app._index.counts()) == 2, f"{app._index.counts()}")
+ await pilot.press("ctrl+n")
+ if await settle(lambda: isinstance(app.screen, SymbolPalette), 20):
+ pal = app.screen
+ pal.query_one(Input).value = "main"
+ await pilot.pause(0.3)
+ await pilot.press("f2") # widen to the whole project
+ await pilot.pause(0.4)
+ names = [(b, n) for b, _, n in pal._results]
+ check("project scope finds a name shared by both binaries",
+ len({b for b, n in names if n == "main"}) == 2,
+ f"{names[:6]}")
+ await pilot.press("escape")
+ await pilot.pause(0.2)
+
# -- the promise: nothing was written next to the sources ---------- #
left = sorted(os.listdir(src))
check("the source tree stays pristine (no .i64/scratch beside it)",