void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { assert(V->getType()->isPointerTy() && "Capture is for pointers only!"); SmallVector<const Use *, Threshold> Worklist; SmallSet<const Use *, Threshold> Visited; auto AddUses = [&](const Value *V) { int Count = 0; for (const Use &U : V->uses()) { // If there are lots of uses, conservatively say that the value // is captured to avoid taking too much compile time. if (Count++ >= Threshold) return Tracker->tooManyUses(); if (!Visited.insert(&U).second) continue; if (!Tracker->shouldExplore(&U)) continue; Worklist.push_back(&U); } }; AddUses(V); while (!Worklist.empty()) { const Use *U = Worklist.pop_back_val(); Instruction *I = cast<Instruction>(U->getUser()); V = U->get(); switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { CallSite CS(I); // Not captured if the callee is readonly, doesn't return a copy through // its return value and doesn't unwind (a readonly function can leak bits // by throwing an exception or not depending on the input value). if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy()) break; // The pointer is not captured if returned pointer is not captured. // NOTE: CaptureTracking users should not assume that only functions // marked with nocapture do not capture. This means that places like // GetUnderlyingObject in ValueTracking or DecomposeGEPExpression // in BasicAA also need to know about this property. if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(CS)) { AddUses(I); break; } // Volatile operations effectively capture the memory location that they // load and store to. if (auto *MI = dyn_cast<MemIntrinsic>(I)) if (MI->isVolatile()) if (Tracker->captured(U)) return; // Not captured if only passed via 'nocapture' arguments. Note that // calling a function pointer does not in itself cause the pointer to // be captured. This is a subtle point considering that (for example) // the callee might return its own address. It is analogous to saying // that loading a value from a pointer does not cause the pointer to be // captured, even though the loaded value might be the pointer itself // (think of self-referential objects). CallSite::data_operand_iterator B = CS.data_operands_begin(), E = CS.data_operands_end(); for (CallSite::data_operand_iterator A = B; A != E; ++A) if (A->get() == V && !CS.doesNotCapture(A - B)) // The parameter is not marked 'nocapture' - captured. if (Tracker->captured(U)) return; break; } case Instruction::Load: // Volatile loads make the address observable. if (cast<LoadInst>(I)->isVolatile()) if (Tracker->captured(U)) return; break; case Instruction::VAArg: // "va-arg" from a pointer does not cause it to be captured. break; case Instruction::Store: // Stored the pointer - conservatively assume it may be captured. // Volatile stores make the address observable. if (V == I->getOperand(0) || cast<StoreInst>(I)->isVolatile()) if (Tracker->captured(U)) return; break; case Instruction::AtomicRMW: { // atomicrmw conceptually includes both a load and store from // the same location. // As with a store, the location being accessed is not captured, // but the value being stored is. // Volatile stores make the address observable. auto *ARMWI = cast<AtomicRMWInst>(I); if (ARMWI->getValOperand() == V || ARMWI->isVolatile()) if (Tracker->captured(U)) return; break; } case Instruction::AtomicCmpXchg: { // cmpxchg conceptually includes both a load and store from // the same location. // As with a store, the location being accessed is not captured, // but the value being stored is. // Volatile stores make the address observable. auto *ACXI = cast<AtomicCmpXchgInst>(I); if (ACXI->getCompareOperand() == V || ACXI->getNewValOperand() == V || ACXI->isVolatile()) if (Tracker->captured(U)) return; break; } case Instruction::BitCast: case Instruction::GetElementPtr: case Instruction::PHI: case Instruction::Select: case Instruction::AddrSpaceCast: // The original value is not captured via this if the new value isn't. AddUses(I); break; case Instruction::ICmp: { // Don't count comparisons of a no-alias return value against null as // captures. This allows us to ignore comparisons of malloc results // with null, for example. if (ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(I->getOperand(1))) if (CPN->getType()->getAddressSpace() == 0) if (isNoAliasCall(V->stripPointerCasts())) break; // Comparison against value stored in global variable. Given the pointer // does not escape, its value cannot be guessed and stored separately in a // global variable. unsigned OtherIndex = (I->getOperand(0) == V) ? 1 : 0; auto *LI = dyn_cast<LoadInst>(I->getOperand(OtherIndex)); if (LI && isa<GlobalVariable>(LI->getPointerOperand())) break; // Otherwise, be conservative. There are crazy ways to capture pointers // using comparisons. if (Tracker->captured(U)) return; break; } default: // Something else - be conservative and say it is captured. if (Tracker->captured(U)) return; break; } } // All uses examined. }
void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { assert(V->getType()->isPointerTy() && "Capture is for pointers only!"); SmallVector<const Use *, Threshold> Worklist; SmallSet<const Use *, Threshold> Visited; int Count = 0; for (const Use &U : V->uses()) { // If there are lots of uses, conservatively say that the value // is captured to avoid taking too much compile time. if (Count++ >= Threshold) return Tracker->tooManyUses(); if (!Tracker->shouldExplore(&U)) continue; Visited.insert(&U); Worklist.push_back(&U); } while (!Worklist.empty()) { const Use *U = Worklist.pop_back_val(); Instruction *I = cast<Instruction>(U->getUser()); V = U->get(); switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { CallSite CS(I); // Not captured if the callee is readonly, doesn't return a copy through // its return value and doesn't unwind (a readonly function can leak bits // by throwing an exception or not depending on the input value). if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy()) break; // Not captured if only passed via 'nocapture' arguments. Note that // calling a function pointer does not in itself cause the pointer to // be captured. This is a subtle point considering that (for example) // the callee might return its own address. It is analogous to saying // that loading a value from a pointer does not cause the pointer to be // captured, even though the loaded value might be the pointer itself // (think of self-referential objects). CallSite::data_operand_iterator B = CS.data_operands_begin(), E = CS.data_operands_end(); for (CallSite::data_operand_iterator A = B; A != E; ++A) if (A->get() == V && !CS.doesNotCapture(A - B)) // The parameter is not marked 'nocapture' - captured. if (Tracker->captured(U)) return; break; } case Instruction::Load: // Loading from a pointer does not cause it to be captured. break; case Instruction::VAArg: // "va-arg" from a pointer does not cause it to be captured. break; case Instruction::Store: if (V == I->getOperand(0)) // Stored the pointer - conservatively assume it may be captured. if (Tracker->captured(U)) return; // Storing to the pointee does not cause the pointer to be captured. break; case Instruction::AtomicRMW: case Instruction::AtomicCmpXchg: // atomicrmw and cmpxchg conceptually include both a load and store from // the same location. As with a store, the location being accessed is // not captured, but the value being stored is. (For cmpxchg, we // probably don't need to capture the original comparison value, but for // the moment, let's be conservative.) if (V != I->getOperand(0)) if (Tracker->captured(U)) return; break; case Instruction::BitCast: case Instruction::GetElementPtr: case Instruction::PHI: case Instruction::Select: case Instruction::AddrSpaceCast: // The original value is not captured via this if the new value isn't. Count = 0; for (Use &UU : I->uses()) { // If there are lots of uses, conservatively say that the value // is captured to avoid taking too much compile time. if (Count++ >= Threshold) return Tracker->tooManyUses(); if (Visited.insert(&UU).second) if (Tracker->shouldExplore(&UU)) Worklist.push_back(&UU); } break; case Instruction::ICmp: // Don't count comparisons of a no-alias return value against null as // captures. This allows us to ignore comparisons of malloc results // with null, for example. if (ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(I->getOperand(1))) if (CPN->getType()->getAddressSpace() == 0) if (isNoAliasCall(V->stripPointerCasts())) break; // Otherwise, be conservative. There are crazy ways to capture pointers // using comparisons. if (Tracker->captured(U)) return; break; default: // Something else - be conservative and say it is captured. if (Tracker->captured(U)) return; break; } } // All uses examined. }