Synchronous calls in init/1 detection.
Identifies GenServer/Supervisor modules whose init/1 callback makes
synchronous calls (directly or transitively through the call graph). When
combined with supervision ordering, detects guaranteed deadlocks: a child's
init blocks on a sibling that hasn't started yet.
Supervision-aware filtering removes proven-safe findings:
- Safe sibling: the callee starts earlier under the same supervisor,
so it is already running when the caller's
init/1executes. - Safe cross-supervisor: the caller and callee are under disjoint supervisor trees, so the callee was started by a different supervisor and is already running.
Requires the OTP and Supervision extractors for sync_call,
implements_behaviour, supervisor, and supervisor_child facts.
Output relations
sync_call_in_init(mod, callee_mod)— module whose init/1 sync-calls callee_mod (after filtering proven-safe cases).init_deadlock_risk(sup, child, dep, child_pos, dep_pos)— child's init calls a later-starting sibling.sup_call_in_init(mod, api, op, target, site)— init/1 reaches a supervisor management call (start_child,terminate_child, ...).init_waits_on_blocking_server(mod, dep, handler, op_site)— a call from init/1 that the tree-order argument accepts, into a server whose handler itself blocks on a supervisor op or a GenServer.call.
Finding severities
sync_call_in_init—:info. The target's liveness couldn't be proven either way; the call stalls startup whenever the target is slow or absent.init_deadlock_risk—:error. Supervisors start children in order andinit/1blocks that sequence, so an init that waits on a later-starting sibling is a deadlock by construction.sup_call_in_init—:info. Starting children from init/1 puts their inits on the startup path; whether one calls back is not known here.init_waits_on_blocking_server—:warning. The callee is running, but a handler of its blocks on something with no bound: aterminate_child/stop, or a GenServer.call with:infinity.