One function
IDASessionManager in mrexodia/ida-pro-mcp
The author described this change as “Fix stale strings cache when switching binaries in idalib worker”. It counts as a record because the check below fails on the code as it stood at 1be78d041 and passes on e12fbb514, with nothing else changed between the two runs.
Projectmrexodia/ida-pro-mcp
Fix saved2026-07-13
Sharing licenceMIT · LICENSE
Change size+12 −8
What the code was meant to do, written into the code itself as a docstring
Manages multiple IDA database sessions for idalib mode. `_sessions` stores all known session metadata. `_active_session_id` tracks the database currently opened in the idalib process. Callers select which session a request applies to by passing its session_id explicitly.
The change
| 70 | 70 | logger.info(f"Closing session: {session_id} ({session.input_path.name})") | |
| 71 | 71 | ||
| 72 | 72 | if self._active_session_id == session_id: | |
| 73 | - | idapro.close_database() | |
| 74 | - | self._active_session_id = None | |
| 73 | + | self._close_active_database() | |
| 75 | 74 | ||
| 76 | 75 | del self._sessions[session_id] | |
| 77 | 76 | logger.info(f"Session closed: {session_id}") | |
| ⋯ | |||
| 108 | 107 | with self._lock: | |
| 109 | 108 | logger.info(f"Closing all {len(self._sessions)} sessions") | |
| 110 | 109 | ||
| 111 | - | if self._active_session_id is not None: | |
| 112 | - | idapro.close_database() | |
| 113 | - | self._active_session_id = None | |
| 110 | + | self._close_active_database() | |
| 114 | 111 | ||
| 115 | 112 | self._sessions.clear() | |
| 116 | 113 | logger.info("All sessions closed") | |
| ⋯ | |||
| 126 | 123 | logger.info("Activated session %s (%s)", session_id, session.input_path.name) | |
| 127 | 124 | ||
| 128 | 125 | def _activate_database_path(self, input_path: str, run_auto_analysis: bool) -> None: | |
| 126 | + | self._close_active_database() | |
| 127 | + | ||
| 128 | + | if idapro.open_database(input_path, run_auto_analysis=run_auto_analysis): | |
| 129 | + | raise RuntimeError(f"Failed to open database: {input_path}") | |
| 130 | + | ||
| 131 | + | def _close_active_database(self) -> None: | |
| 129 | 132 | if self._active_session_id is not None: | |
| 130 | - | logger.debug("Closing active database before opening %s", input_path) | |
| 133 | + | logger.debug("Closing active database (session: %s)", self._active_session_id) | |
| 131 | 134 | idapro.close_database() | |
| 132 | 135 | self._active_session_id = None | |
| 133 | 136 | ||
| 134 | - | if idapro.open_database(input_path, run_auto_analysis=run_auto_analysis): | |
| 135 | - | raise RuntimeError(f"Failed to open database: {input_path}") | |
| 137 | + | # The strings cache is process-global, so drop it on every DB change or | |
| 138 | + | # the next binary would serve the previous one's strings. | |
| 139 | + | invalidate_strings_cache() | |
The check that tells the two apart
fail→pass·tests/test_idalib_session_manager.py::test_switching_binaries_invalidates_strings_cache
Check file tests/test_idalib_session_manager.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before it1be78d04119748066d5e73070302ad62916002ea
Broken version dated2026-07-13
Moduleida_pro_mcp.idalib_session_manager
Units changedIDASessionManager
Fingerprintddf515132003fcdd
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.