First detect doublelock on each relation(a, b), use non-doublelock relations to build `ConflictLockGraph`. Then find the cycles in `ConflictLockGraph` as conflictlock.
(
&self,
lockguards: &LockGuardMap<'tcx>,
callgraph: &'a CallGraph<'tcx>,
alias_analysis: &mut AliasAnalysis<'a, 'tcx>,
)
| 587 | } |
| 588 | } else { |
| 589 | // if is terminator |
| 590 | for succ_bb in body[loc.block].terminator().successors() { |
| 591 | let succ = Location { |
| 592 | block: succ_bb, |
| 593 | statement_index: 0, |
| 594 | }; |
| 595 | // union and reprocess if changed |
| 596 | let changed = states.get_mut(&succ).unwrap().union_in_place(after.clone()); |
| 597 | if changed { |
| 598 | worklist.push_back(succ); |
| 599 | } |
| 600 | } |
| 601 | } |
| 602 | } |
| 603 | states |
| 604 | } |
| 605 | |
| 606 | /// First detect doublelock on each relation(a, b), |
| 607 | /// use non-doublelock relations to build `ConflictLockGraph`. |
| 608 | /// Then find the cycles in `ConflictLockGraph` as conflictlock. |
| 609 | fn detect_deadlock<'a>( |
| 610 | &self, |
| 611 | lockguards: &LockGuardMap<'tcx>, |
| 612 | callgraph: &'a CallGraph<'tcx>, |
| 613 | alias_analysis: &mut AliasAnalysis<'a, 'tcx>, |
| 614 | ) -> Vec<Report> { |
| 615 | let mut reports = Vec::new(); |
| 616 | let mut conflictlock_graph = ConflictLockGraph::new(); |
| 617 | let mut relation_to_nodes = FxHashMap::default(); |
| 618 | // Detect doublelock: |
| 619 | // forall relation(a, b): deadlock(a, b) => doublelock(a, b) |
| 620 | for (a, b) in &self.lockguard_relations { |
| 621 | let (possibility, reason) = deadlock_possibility(a, b, lockguards, alias_analysis); |
| 622 | match possibility { |
| 623 | DeadlockPossibility::Probably | DeadlockPossibility::Possibly => { |
| 624 | let diagnosis = diagnose_doublelock(a, b, lockguards, callgraph, self.tcx); |
| 625 | let report = Report::DoubleLock(ReportContent::new( |
| 626 | "DoubleLock".to_owned(), |
| 627 | format!("{:?}", possibility), |
| 628 | diagnosis, |
| 629 | "The first lock is not released when acquiring the second lock".to_owned(), |
| 630 | )); |
| 631 | reports.push(report); |
| 632 | } |
| 633 | _ if NotDeadlockReason::RecursiveRead != reason |
| 634 | && NotDeadlockReason::SameSpan != reason => |
| 635 | { |
| 636 | // if unlikely doublelock, add the pair into graph to check conflictlock |
| 637 | // when the lockguards are gen by call rather than move |
| 638 | if !lockguards[a].is_gen_only_by_move() && !lockguards[b].is_gen_only_by_move() |
| 639 | { |
| 640 | let node = conflictlock_graph.add_node((*a, *b)); |
| 641 | relation_to_nodes.insert((*a, *b), node); |
| 642 | } |
| 643 | } |
| 644 | _ => {} |
| 645 | } |
| 646 | } |
no test coverage detected