diff options
| author | blasty <peter@haxx.in> | 2026-07-11 10:59:48 +0200 |
|---|---|---|
| committer | blasty <peter@haxx.in> | 2026-07-11 10:59:48 +0200 |
| commit | e769336aa753639f26208fd7755c1585d59caf41 (patch) | |
| tree | 4be70a40c201206f4e6286742af5c6ca2ebb1c78 /idatui/domain.py | |
| parent | drive pc: render pseudocode in the TUI, not just the driver (diff) | |
| download | ida-tui-e769336aa753639f26208fd7755c1585d59caf41.tar.gz ida-tui-e769336aa753639f26208fd7755c1585d59caf41.tar.xz ida-tui-e769336aa753639f26208fd7755c1585d59caf41.zip | |
fix: don't hang drive pc on undecompilable functions
toggle_view's settle predicate (lambda: app._active != before) never
fired when tabbing toward pseudocode on a function Hex-Rays can't
decompile: App._apply_decomp snaps the view back to disasm, so _active
returns to its prior value -> full 20s settle timeout (x2 in _show_decomp,
~40s for drive pc). Recognize the decomp-failed fallback as settled.
Also harden two amplifiers surfaced by the same case:
- rpcclient: the CLI socket had no read timeout and would block forever
on any server slowness; add a bounded settimeout (IDATUI_RPC_TIMEOUT,
default 90s) with a clear error.
- domain.decompile: pass a bounded 15s timeout and cache failures, so a
failing decompile can't sit at the 30s client default or be re-run by
transport retries.
Diffstat (limited to 'idatui/domain.py')
| -rw-r--r-- | idatui/domain.py | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/idatui/domain.py b/idatui/domain.py index 826d0f7..cc95b21 100644 --- a/idatui/domain.py +++ b/idatui/domain.py @@ -36,6 +36,7 @@ from .client import IDAClient, IDAToolError LIST_PAGE = 500 DISASM_BLOCK = 256 # instructions per cached/fetched block (<= disasm cap) HEX_BLOCK = 4096 # bytes per cached/fetched hex block +DECOMPILE_TIMEOUT = 15.0 # s; cap per decompile so a failing one can't hang the CLI _TRUNC_RE = re.compile(r"\[(\d+) chars total\]\s*$") @@ -741,7 +742,21 @@ class Program: self.client.call("force_recompile", items=[{"addr": hex(ea)}]) except Exception: # noqa: BLE001 pass - envelope = self.client.call_envelope("decompile", addr=hex(ea)) + # Bound the decompile: a function Hex-Rays can't handle tends to stall + # near the client's default 30s timeout, and the transport retries a + # dropped connection up to max_retries+1 times, re-running the failing + # decompile each time. Cap it so the worst case stays well under the + # rpcclient socket timeout, and cache the failure below so a re-request + # returns instantly instead of re-grinding. + try: + envelope = self.client.call_envelope( + "decompile", addr=hex(ea), timeout=DECOMPILE_TIMEOUT + ) + except Exception as e: # noqa: BLE001 -- surface as a failed decompile + dec = Decompilation(ea, None, True, f"decompile error: {e}", False, None) + with self._lock: + self._decomp[ea] = (dec, self._name_gen) + return dec result = envelope.get("result", {}) payload = result.get("structuredContent") if payload is None: # fall back to text content |
