void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && !LangOpts.Sanitize.has(SanitizerKind::CFINVCall) && !LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) && !LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) return; CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); typedef std::pair<const CXXRecordDecl *, unsigned> BSEntry; std::vector<BSEntry> BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) { if (IsCFIBlacklistedRecord(AP.first.getBase())) continue; BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second)); } // Sort the bit set entries for determinism. std::sort(BitsetEntries.begin(), BitsetEntries.end(), [this](const BSEntry &E1, const BSEntry &E2) { if (&E1 == &E2) return false; std::string S1; llvm::raw_string_ostream O1(S1); getCXXABI().getMangleContext().mangleTypeName( QualType(E1.first->getTypeForDecl(), 0), O1); O1.flush(); std::string S2; llvm::raw_string_ostream O2(S2); getCXXABI().getMangleContext().mangleTypeName( QualType(E2.first->getTypeForDecl(), 0), O2); O2.flush(); if (S1 < S2) return true; if (S1 != S2) return false; return E1.second < E2.second; }); llvm::NamedMDNode *BitsetsMD = getModule().getOrInsertNamedMetadata("llvm.bitsets"); for (auto BitsetEntry : BitsetEntries) CreateVTableBitSetEntry(BitsetsMD, VTable, PointerWidth * BitsetEntry.second, BitsetEntry.first); }
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!getCodeGenOpts().LTOUnit) return; CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); typedef std::pair<const CXXRecordDecl *, unsigned> BSEntry; std::vector<BSEntry> BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) BitsetEntries.push_back( std::make_pair(AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) + AP.second.AddressPointIndex)); // Sort the bit set entries for determinism. std::sort(BitsetEntries.begin(), BitsetEntries.end(), [this](const BSEntry &E1, const BSEntry &E2) { if (&E1 == &E2) return false; std::string S1; llvm::raw_string_ostream O1(S1); getCXXABI().getMangleContext().mangleTypeName( QualType(E1.first->getTypeForDecl(), 0), O1); O1.flush(); std::string S2; llvm::raw_string_ostream O2(S2); getCXXABI().getMangleContext().mangleTypeName( QualType(E2.first->getTypeForDecl(), 0), O2); O2.flush(); if (S1 < S2) return true; if (S1 != S2) return false; return E1.second < E2.second; }); for (auto BitsetEntry : BitsetEntries) AddVTableTypeMetadata(VTable, PointerWidth * BitsetEntry.second, BitsetEntry.first); }
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!getCodeGenOpts().LTOUnit) return; CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint; std::vector<AddressPoint> AddressPoints; for (auto &&AP : VTLayout.getAddressPoints()) AddressPoints.push_back(std::make_pair( AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) + AP.second.AddressPointIndex)); // Sort the address points for determinism. llvm::sort(AddressPoints, [this](const AddressPoint &AP1, const AddressPoint &AP2) { if (&AP1 == &AP2) return false; std::string S1; llvm::raw_string_ostream O1(S1); getCXXABI().getMangleContext().mangleTypeName( QualType(AP1.first->getTypeForDecl(), 0), O1); O1.flush(); std::string S2; llvm::raw_string_ostream O2(S2); getCXXABI().getMangleContext().mangleTypeName( QualType(AP2.first->getTypeForDecl(), 0), O2); O2.flush(); if (S1 < S2) return true; if (S1 != S2) return false; return AP1.second < AP2.second; }); ArrayRef<VTableComponent> Comps = VTLayout.vtable_components(); for (auto AP : AddressPoints) { // Create type metadata for the address point. AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first); // The class associated with each address point could also potentially be // used for indirect calls via a member function pointer, so we need to // annotate the address of each function pointer with the appropriate member // function pointer type. for (unsigned I = 0; I != Comps.size(); ++I) { if (Comps[I].getKind() != VTableComponent::CK_FunctionPointer) continue; llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType( Context.getMemberPointerType( Comps[I].getFunctionDecl()->getType(), Context.getRecordType(AP.first).getTypePtr())); VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD); } } }
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && !LangOpts.Sanitize.has(SanitizerKind::CFINVCall) && !LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) && !LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) return; llvm::Metadata *VTableMD = llvm::ConstantAsMetadata::get(VTable); std::vector<llvm::MDTuple *> BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) { // FIXME: Add blacklisting scheme. if (AP.first.getBase()->isInStdNamespace()) continue; std::string OutName; llvm::raw_string_ostream Out(OutName); getCXXABI().getMangleContext().mangleCXXVTableBitSet(AP.first.getBase(), Out); CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); uint64_t AddrPointOffset = AP.second * PointerWidth.getQuantity(); llvm::Metadata *BitsetOps[] = { llvm::MDString::get(getLLVMContext(), Out.str()), VTableMD, llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(Int64Ty, AddrPointOffset))}; llvm::MDTuple *BitsetEntry = llvm::MDTuple::get(getLLVMContext(), BitsetOps); BitsetEntries.push_back(BitsetEntry); } // Sort the bit set entries for determinism. std::sort(BitsetEntries.begin(), BitsetEntries.end(), [](llvm::MDTuple *T1, llvm::MDTuple *T2) { if (T1 == T2) return false; StringRef S1 = cast<llvm::MDString>(T1->getOperand(0))->getString(); StringRef S2 = cast<llvm::MDString>(T2->getOperand(0))->getString(); if (S1 < S2) return true; if (S1 != S2) return false; uint64_t Offset1 = cast<llvm::ConstantInt>( cast<llvm::ConstantAsMetadata>(T1->getOperand(2)) ->getValue())->getZExtValue(); uint64_t Offset2 = cast<llvm::ConstantInt>( cast<llvm::ConstantAsMetadata>(T2->getOperand(2)) ->getValue())->getZExtValue(); assert(Offset1 != Offset2); return Offset1 < Offset2; }); llvm::NamedMDNode *BitsetsMD = getModule().getOrInsertNamedMetadata("llvm.bitsets"); for (auto BitsetEntry : BitsetEntries) BitsetsMD->addOperand(BitsetEntry); }