summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2016-04-27 20:39:53 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2016-04-27 20:39:53 +0000
commita8b2f7c0d7d2432c4574cc564b6b4488c6f970b7 (patch)
treea2e99c8c523cbd9ff2fa7963cedfc91f014f088b /clang/lib
parent60c4e6aafa8904eecb79a2109ed4c8b8be942005 (diff)
downloadbcm5719-llvm-a8b2f7c0d7d2432c4574cc564b6b4488c6f970b7.tar.gz
bcm5719-llvm-a8b2f7c0d7d2432c4574cc564b6b4488c6f970b7.zip
Rework interface for bitset-using features to use a notion of LTO visibility.
Bitsets, and the compiler features they rely on (vtable opt, CFI), only have visibility within the LTO'd part of the linkage unit. Therefore, only enable these features for classes with hidden LTO visibility. This notion is based on object file visibility or (on Windows) dllimport/dllexport attributes. We provide the [[clang::lto_visibility_public]] attribute to override the compiler's LTO visibility inference in cases where the class is defined in the non-LTO'd part of the linkage unit, or where the ABI supports calling classes derived from abstract base classes with hidden visibility in other linkage units (e.g. COM on Windows). If the cross-DSO CFI mode is enabled, bitset checks are emitted even for classes with public LTO visibility, as that mode uses a separate mechanism to cause bitsets to be exported. This mechanism replaces the whole-program-vtables blacklist, so remove the -fwhole-program-vtables-blacklist flag. Because __declspec(uuid()) now implies [[clang::lto_visibility_public]], the support for the special attr:uuid blacklist entry is removed. Differential Revision: http://reviews.llvm.org/D18635 llvm-svn: 267784
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGClass.cpp9
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp57
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp4
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h12
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp17
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp9
-rw-r--r--clang/lib/Driver/Tools.cpp39
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp3
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp3
9 files changed, 76 insertions, 77 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 351dae9d4dd..71b305c773d 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2489,7 +2489,7 @@ void CodeGenFunction::EmitBitSetCodeForVCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
SourceLocation Loc) {
if (CGM.getCodeGenOpts().WholeProgramVTables &&
- !CGM.IsBitSetBlacklistedRecord(RD)) {
+ CGM.HasHiddenLTOVisibility(RD)) {
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Value *BitSetName =
@@ -2565,7 +2565,12 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
- if (CGM.IsBitSetBlacklistedRecord(RD))
+ if (!CGM.getCodeGenOpts().SanitizeCfiCrossDso &&
+ !CGM.HasHiddenLTOVisibility(RD))
+ return;
+
+ std::string TypeName = RD->getQualifiedNameAsString();
+ if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName))
return;
SanitizerScope SanScope(this);
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index f139e2c8504..478164e273b 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -902,34 +902,43 @@ void CodeGenModule::EmitDeferredVTables() {
DeferredVTables.clear();
}
-bool CodeGenModule::NeedVTableBitSets() {
- return getCodeGenOpts().WholeProgramVTables ||
- getLangOpts().Sanitize.has(SanitizerKind::CFIVCall) ||
- getLangOpts().Sanitize.has(SanitizerKind::CFINVCall) ||
- getLangOpts().Sanitize.has(SanitizerKind::CFIDerivedCast) ||
- getLangOpts().Sanitize.has(SanitizerKind::CFIUnrelatedCast);
-}
+bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
+ LinkageInfo LV = RD->getLinkageAndVisibility();
+ if (!isExternallyVisible(LV.getLinkage()))
+ return true;
-bool CodeGenModule::IsBitSetBlacklistedRecord(const CXXRecordDecl *RD) {
- std::string TypeName = RD->getQualifiedNameAsString();
- auto isInBlacklist = [&](const SanitizerBlacklist &BL) {
- if (RD->hasAttr<UuidAttr>() && BL.isBlacklistedType("attr:uuid"))
- return true;
+ if (RD->hasAttr<LTOVisibilityPublicAttr>() || RD->hasAttr<UuidAttr>())
+ return false;
- return BL.isBlacklistedType(TypeName);
- };
+ if (getTriple().isOSBinFormatCOFF()) {
+ if (RD->hasAttr<DLLExportAttr>() || RD->hasAttr<DLLImportAttr>())
+ return false;
+ } else {
+ if (LV.getVisibility() != HiddenVisibility)
+ return false;
+ }
- return isInBlacklist(WholeProgramVTablesBlacklist) ||
- ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) ||
- LangOpts.Sanitize.has(SanitizerKind::CFINVCall) ||
- LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) ||
- LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) &&
- isInBlacklist(getContext().getSanitizerBlacklist()));
+ if (getCodeGenOpts().LTOVisibilityPublicStd) {
+ const DeclContext *DC = RD;
+ while (1) {
+ auto *D = cast<Decl>(DC);
+ DC = DC->getParent();
+ if (isa<TranslationUnitDecl>(DC->getRedeclContext())) {
+ if (auto *ND = dyn_cast<NamespaceDecl>(D))
+ if (const IdentifierInfo *II = ND->getIdentifier())
+ if (II->isStr("std") || II->isStr("stdext"))
+ return false;
+ break;
+ }
+ }
+ }
+
+ return true;
}
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
- if (!NeedVTableBitSets())
+ if (!getCodeGenOpts().PrepareForLTO)
return;
CharUnits PointerWidth =
@@ -938,12 +947,8 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
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 (IsBitSetBlacklistedRecord(AP.first.getBase()))
- continue;
-
+ for (auto &&AP : VTLayout.getAddressPoints())
BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second));
- }
// Sort the bit set entries for determinism.
std::sort(BitsetEntries.begin(), BitsetEntries.end(),
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 64fe3652a9d..8ff99a6c404 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -88,9 +88,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
VMContext(M.getContext()), Types(*this), VTables(*this),
- SanitizerMD(new SanitizerMetadata(*this)),
- WholeProgramVTablesBlacklist(CGO.WholeProgramVTablesBlacklistFiles,
- C.getSourceManager()) {
+ SanitizerMD(new SanitizerMetadata(*this)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 34d1111889a..a75e4aa2a32 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -490,8 +490,6 @@ private:
/// MDNodes.
llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap;
- SanitizerBlacklist WholeProgramVTablesBlacklist;
-
public:
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
@@ -1115,12 +1113,10 @@ public:
void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
CodeGenFunction *CGF = nullptr);
- /// Returns whether we need bit sets attached to vtables.
- bool NeedVTableBitSets();
-
- /// Returns whether the given record is blacklisted from whole-program
- /// transformations (i.e. CFI or whole-program vtable optimization).
- bool IsBitSetBlacklistedRecord(const CXXRecordDecl *RD);
+ /// Returns whether the given record has hidden LTO visibility and therefore
+ /// may participate in (single-module) CFI and whole-program vtable
+ /// optimization.
+ bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
/// Emit bit set entries for the given vtable using the given layout if
/// vptr CFI is enabled.
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index e578863bfc3..0e15f5054d8 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1503,7 +1503,7 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable) {
- if (!CGM.NeedVTableBitSets())
+ if (!CGM.getCodeGenOpts().PrepareForLTO)
return;
llvm::NamedMDNode *BitsetsMD =
@@ -1519,15 +1519,13 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
: CharUnits::Zero();
if (Info->PathToBaseWithVPtr.empty()) {
- if (!CGM.IsBitSetBlacklistedRecord(RD))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
return;
}
// Add a bitset entry for the least derived base belonging to this vftable.
- if (!CGM.IsBitSetBlacklistedRecord(Info->PathToBaseWithVPtr.back()))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
- Info->PathToBaseWithVPtr.back());
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
+ Info->PathToBaseWithVPtr.back());
// Add a bitset entry for each derived class that is laid out at the same
// offset as the least derived base.
@@ -1545,12 +1543,11 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
Offset = VBI->second.VBaseOffset;
if (!Offset.isZero())
return;
- if (!CGM.IsBitSetBlacklistedRecord(DerivedRD))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
}
// Finally do the same for the most derived class.
- if (Info->FullOffsetInMDC.isZero() && !CGM.IsBitSetBlacklistedRecord(RD))
+ if (Info->FullOffsetInMDC.isZero())
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
}
@@ -1819,7 +1816,7 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
- if (CGM.NeedVTableBitSets())
+ if (CGM.getCodeGenOpts().PrepareForLTO)
CGF.EmitBitSetCodeForVCall(getClassAtVTableLocation(getContext(), GD, ML),
VTable, Loc);
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 50a93a8d431..6f19a2fa96b 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -39,6 +39,7 @@ enum : SanitizerMask {
TrappingSupported =
(Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
TrappingDefault = CFI,
+ CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
};
enum CoverageFeature {
@@ -560,6 +561,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
LinkCXXRuntimes =
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
+ // Require -fvisibility= flag on non-Windows if vptr CFI is enabled.
+ if ((Kinds & CFIClasses) && !TC.getTriple().isOSWindows() &&
+ !Args.hasArg(options::OPT_fvisibility_EQ)) {
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << lastArgumentForMask(D, Args, Kinds & CFIClasses)
+ << "-fvisibility=";
+ }
+
// Finally, initialize the set of available and recoverable sanitizers.
Sanitizers.Mask |= Kinds;
RecoverableSanitizers.Mask |= RecoverableKinds;
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index 74ac8070561..f0199aab274 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -4429,32 +4429,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-ffunction-sections");
}
- if (Args.hasFlag(options::OPT_fwhole_program_vtables,
- options::OPT_fno_whole_program_vtables, false)) {
- if (!D.isUsingLTO())
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << "-fwhole-program-vtables"
- << "-flto";
- CmdArgs.push_back("-fwhole-program-vtables");
-
- clang::SmallString<64> Path(D.ResourceDir);
- llvm::sys::path::append(Path, "vtables_blacklist.txt");
- if (llvm::sys::fs::exists(Path)) {
- SmallString<64> BlacklistOpt("-fwhole-program-vtables-blacklist=");
- BlacklistOpt += Path.str();
- CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
- }
-
- for (const Arg *A :
- Args.filtered(options::OPT_fwhole_program_vtables_blacklist_EQ)) {
- A->claim();
- if (!llvm::sys::fs::exists(A->getValue()))
- D.Diag(clang::diag::err_drv_no_such_file) << A->getValue();
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_fwhole_program_vtables_blacklist_EQ);
- }
-
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections)) {
CmdArgs.push_back("-fdata-sections");
@@ -5785,6 +5759,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(I->getFilename());
}
+ bool WholeProgramVTables =
+ Args.hasFlag(options::OPT_fwhole_program_vtables,
+ options::OPT_fno_whole_program_vtables, false);
+ if (WholeProgramVTables) {
+ if (!D.isUsingLTO())
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fwhole-program-vtables"
+ << "-flto";
+ CmdArgs.push_back("-fwhole-program-vtables");
+ }
+
// Finally add the compile command to the compilation.
if (Args.hasArg(options::OPT__SLASH_fallback) &&
Output.getType() == types::TY_Object &&
@@ -6048,11 +6033,13 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
if (Args.hasArg(options::OPT__SLASH_LDd))
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
FlagForCRT = "--dependent-lib=libcmt";
break;
case options::OPT__SLASH_MTd:
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
FlagForCRT = "--dependent-lib=libcmtd";
break;
default:
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 0c4d5c71d5c..4bef159f3bf 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -482,8 +482,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.EmitCodeView = Args.hasArg(OPT_gcodeview);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
- Opts.WholeProgramVTablesBlacklistFiles =
- Args.getAllArgValues(OPT_fwhole_program_vtables_blacklist_EQ);
+ Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
Opts.DebugExplicitImport = Triple.isPS4CPU();
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 0ba9799d042..9bf5fc9e36d 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5749,6 +5749,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, Attr);
break;
+ case AttributeList::AT_LTOVisibilityPublic:
+ handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr);
+ break;
// Microsoft attributes:
case AttributeList::AT_MSNoVTable:
OpenPOWER on IntegriCloud