Skip to content

Commit 46ba6f3

Browse files
committed
fix: hold _conn_lock across check-create-append in _get_connection()
Previously the lock was acquired for the closed check, released, then reacquired for the append — leaving a window where close() could run between check and append, leaking the new connection. The fast path (existing connection) remains lock-free since _thread_local is per-thread.
1 parent 424c805 commit 46ba6f3

1 file changed

Lines changed: 4 additions & 4 deletions

File tree

src/impactguard/call_graph.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,12 @@ def _get_connection(self) -> sqlite3.Connection:
202202
203203
Raises :class:`RuntimeError` if the instance has been closed.
204204
"""
205+
con = getattr(self._thread_local, "con", None)
206+
if con is not None:
207+
return con
205208
with self._conn_lock:
206209
if self._closed:
207210
raise RuntimeError("CallGraphDB has been closed")
208-
con = getattr(self._thread_local, "con", None)
209-
if con is None:
210211
con = sqlite3.connect(
211212
str(self.db_path), check_same_thread=False, timeout=5,
212213
)
@@ -216,8 +217,7 @@ def _get_connection(self) -> sqlite3.Connection:
216217
con.execute("PRAGMA busy_timeout=5000")
217218
con.executescript(_SCHEMA_SQL)
218219
self._thread_local.con = con
219-
with self._conn_lock:
220-
self._all_connections.append(con)
220+
self._all_connections.append(con)
221221
return con
222222

223223
@property

0 commit comments

Comments
 (0)