コード例 #1
0
void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
  if (!successorBlocksThatMustBeVisited.empty()) {
    // If we are asked to store any leaking blocks, put them in the leaking
    // blocks array.
    if (leakingBlocks) {
      copy(successorBlocksThatMustBeVisited,
           std::back_inserter(*leakingBlocks));
    }

    // If we are supposed to error on leaks, do so now.
    error.handleLeak([&] {
      llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
                   << "Error! Found a leak due to a consuming post-dominance "
                      "failure!\n"
                   << "    Value: " << *value
                   << "    Post Dominating Failure Blocks:\n";
      for (auto *succBlock : successorBlocksThatMustBeVisited) {
        llvm::errs() << "        bb" << succBlock->getDebugID();
      }
      llvm::errs() << '\n';
    });

    // Otherwise... see if we have any other failures. This signals the user
    // wants us to tell it where to insert compensating destroys.
  }

  // Make sure that we do not have any lifetime ending uses left to visit that
  // are not transitively unreachable blocks.... so return early.
  if (blocksWithNonConsumingUses.empty()) {
    return;
  }

  // If we do have remaining blocks, then these non lifetime ending uses must be
  // outside of our "alive" blocks implying a use-after free.
  for (auto &pair : blocksWithNonConsumingUses) {
    if (deBlocks.isDeadEnd(pair.first)) {
      continue;
    }

    error.handleUseAfterFree([&] {
      llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
                   << "Found use after free due to unvisited non lifetime "
                      "ending uses?!\n"
                   << "Value: " << *value << "    Remaining Users:\n";
      for (auto &pair : blocksWithNonConsumingUses) {
        llvm::errs() << "User:"******"Block: bb"
                     << pair.first->getDebugID() << "\n";
      }
      llvm::errs() << "\n";
    });
  }
}
コード例 #2
0
bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
  // Make sure that we visited all successor blocks that we needed to visit to
  // make sure we didn't leak.
  if (!successorBlocksThatMustBeVisited.empty()) {
    return handleError([&] {
      llvm::errs()
          << "Function: '" << value->getFunction()->getName() << "'\n"
          << "Error! Found a leak due to a consuming post-dominance failure!\n"
          << "    Value: " << *value << "    Post Dominating Failure Blocks:\n";
      for (auto *succBlock : successorBlocksThatMustBeVisited) {
        llvm::errs() << "        bb" << succBlock->getDebugID();
      }
      llvm::errs() << '\n';
    });
  }

  // Make sure that we do not have any lifetime ending uses left to visit that
  // are not transitively unreachable blocks.... so return early.
  if (blocksWithNonConsumingUses.empty()) {
    return true;
  }

  // If we do have remaining blocks, then these non lifetime ending uses must be
  // outside of our "alive" blocks implying a use-after free.
  for (auto &pair : blocksWithNonConsumingUses) {
    if (deBlocks.isDeadEnd(pair.first)) {
      continue;
    }

    return handleError([&] {
      llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
                   << "Found use after free due to unvisited non lifetime "
                      "ending uses?!\n"
                   << "Value: " << *value << "    Remaining Users:\n";
      for (auto &pair : blocksWithNonConsumingUses) {
        llvm::errs() << "User:"******"Block: bb"
                     << pair.first->getDebugID() << "\n";
      }
      llvm::errs() << "\n";
    });
  }

  // If all of our remaining blocks were dead uses, then return true. We are
  // good.
  return true;
}
コード例 #3
0
void State::performDataflow(DeadEndBlocks &deBlocks) {
  LLVM_DEBUG(llvm::dbgs() << "    Beginning to check dataflow constraints\n");
  // Until the worklist is empty...
  while (!worklist.empty()) {
    // Grab the next block to visit.
    SILBasicBlock *block = worklist.pop_back_val();
    LLVM_DEBUG(llvm::dbgs() << "    Visiting Block: bb" << block->getDebugID()
                            << '\n');

    // Since the block is on our worklist, we know already that it is not a
    // block with lifetime ending uses, due to the invariants of our loop.

    // First remove BB from the SuccessorBlocksThatMustBeVisited list. This
    // ensures that when the algorithm terminates, we know that BB was not the
    // beginning of a non-covered path to the exit.
    successorBlocksThatMustBeVisited.remove(block);

    // Then remove BB from BlocksWithNonLifetimeEndingUses so we know that
    // this block was properly joint post-dominated by our lifetime ending
    // users.
    blocksWithNonConsumingUses.erase(block);

    // Ok, now we know that we do not have an overconsume. If this block does
    // not end in a no return function, we need to update our state for our
    // successors to make sure by the end of the traversal we visit them.
    //
    // We must consider such no-return blocks since we may be running during
    // SILGen before NoReturn folding has run.
    for (auto *succBlock : block->getSuccessorBlocks()) {
      // If we already visited the successor, there is nothing to do since we
      // already visited the successor.
      if (visitedBlocks.count(succBlock))
        continue;

      // Then check if the successor is a transitively unreachable block. In
      // such a case, we ignore it since we are going to leak along that path.
      if (deBlocks.isDeadEnd(succBlock))
        continue;

      // Otherwise, add the successor to our SuccessorBlocksThatMustBeVisited
      // set to ensure that we assert if we do not visit it by the end of the
      // algorithm.
      successorBlocksThatMustBeVisited.insert(succBlock);
    }

    // If we are at the dominating block of our walk, continue. There is nothing
    // further to do since we do not want to visit the predecessors of our
    // dominating block. On the other hand, we do want to add its successors to
    // the successorBlocksThatMustBeVisited set.
    if (block == value->getParentBlock())
      continue;

    // Then for each predecessor of this block:
    //
    // 1. If we have visited the predecessor already, then it is not a block
    // with lifetime ending uses. If it is a block with uses, then we have a
    // double release... so assert. If not, we continue.
    //
    // 2. We add the predecessor to the worklist if we have not visited it yet.
    for (auto *predBlock : block->getPredecessorBlocks()) {
      // Check if we have an over consume.
      checkPredsForDoubleConsume(predBlock);

      if (visitedBlocks.count(predBlock)) {
        continue;
      }

      visitedBlocks.insert(predBlock);
      worklist.push_back(predBlock);
    }
  }
}