diff options
| author | blasty <blasty@local> | 2026-08-07 00:18:55 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-08-07 00:18:55 +0200 |
| commit | c70acf6881c83d6de1f33022dc6210b93ed86f2e (patch) | |
| tree | 9b3f613e9d5bf5d82218050bdda5831cc923e782 /idatui/launch.py | |
| parent | worker_client: tests, and stop resurrecting a closed worker (diff) | |
| download | ida-tui-c70acf6881c83d6de1f33022dc6210b93ed86f2e.tar.gz ida-tui-c70acf6881c83d6de1f33022dc6210b93ed86f2e.tar.xz ida-tui-c70acf6881c83d6de1f33022dc6210b93ed86f2e.zip | |
launch: the sweep could delete the file it was asked to open
_sweep_locks removes the scratch IDA unpacks beside a .i64 (.id0/.id1/.id2/
.nam/.til) when an open fails, keyed on both the full name and the stem. It
never touched the .i64, which is the dangerous one everybody thinks of.
It did delete the input. '.til' is an unpacked-DB suffix AND the extension of an
IDA type library, so 'ida-tui mylib.til' swept its own argument out of
existence -- irreversibly, on a path that runs automatically. Same for anything
named *.id0/*.id1/*.id2/*.nam. Now the sweep skips whatever it was asked to
open, compared as an absolute path so a relative argument is covered too.
tests/test_launch.py pins the whole contract: what it takes, what it must never
take (the .i64, the input, the neighbours), and what it reports. Pure, in the
--fast tier. It is the right shape of test for code whose failure mode is
deleting the wrong file.
Also: _load_args parsed the base with bare int(), which raises on the
'0x8000000' string a project file writes. Unreachable from our own CLI (which
int()s first) but the asymmetry with project._as_addr was a trap, so both go
through the same parser now.
813 checks; --fast is 324 in 3.4s.
Diffstat (limited to 'idatui/launch.py')
| -rw-r--r-- | idatui/launch.py | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/idatui/launch.py b/idatui/launch.py index 1f9c51c..35221a1 100644 --- a/idatui/launch.py +++ b/idatui/launch.py @@ -24,9 +24,16 @@ _LOCK_SUFFIXES = (".id0", ".id1", ".id2", ".nam", ".til") def _load_args(load: dict) -> str: - """``load`` as IDA switches, for the single-binary path (no project ref).""" + """``load`` as IDA switches, for the single-binary path (no project ref). + + The base goes through project._as_addr rather than bare int(): our own CLI + hands over an int, but a project file writes "0x8000000" as a string and + int() raises on that. One parser, so the two paths can't disagree about what + an address looks like. + """ from .formats import load_args - return load_args(load.get("processor", ""), int(load.get("base", 0) or 0), + from .project import _as_addr + return load_args(load.get("processor", ""), _as_addr(load.get("base", 0)), str(load.get("ida_args", "") or "")) @@ -35,13 +42,24 @@ def _log(msg: str) -> None: def _sweep_locks(binary: str) -> int: - """Remove stale unpacked DB files next to ``binary``. Returns how many.""" + """Remove stale unpacked DB files next to ``binary``. Returns how many. + + Never touches the ``.i64`` -- that is the real database, and nothing is + saved unless ``idb_save`` was called -- and never the input file itself. + The second guard is not theoretical: ``.til`` is both an unpacked-DB suffix + and the extension of an IDA type library, so ``ida-tui mylib.til`` swept its + own argument out of existence. Same for anything named ``*.id0``/``*.nam``. + """ + keep = os.path.abspath(binary) stem = os.path.splitext(binary)[0] n = 0 for base in (binary, stem): # IDA may key on the full name or the stem for suf in _LOCK_SUFFIXES: + victim = base + suf + if os.path.abspath(victim) == keep: + continue # that's what the user asked us to open try: - os.remove(base + suf) + os.remove(victim) n += 1 except OSError: pass |
