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
This commit is contained in:
Peter Collingbourne 2016-04-27 20:39:53 +00:00
parent 60c4e6aafa
commit a8b2f7c0d7
36 changed files with 432 additions and 209 deletions

View File

@ -25,13 +25,25 @@ As currently implemented, all schemes rely on link-time optimization (LTO);
so it is required to specify ``-flto``, and the linker used must support LTO,
for example via the `gold plugin`_.
To allow the checks to be implemented efficiently, the program must be
structured such that certain object files are compiled with CFI
To allow the checks to be implemented efficiently, the program must
be structured such that certain object files are compiled with CFI
enabled, and are statically linked into the program. This may preclude
the use of shared libraries in some cases. Experimental support for
:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
does not have these requirements. This cross-DSO support has unstable
ABI at this time.
the use of shared libraries in some cases.
The compiler will only produce CFI checks for a class if it can infer hidden
LTO visibility for that class. LTO visibility is a property of a class that
is inferred from flags and attributes. For more details, see the documentation
for :doc:`LTO visibility <LTOVisibility>`.
The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
require that a ``-fvisibility=`` flag also be specified. This is because the
default visibility setting is ``-fvisibility=default``, which would disable
CFI checks for classes without visibility attributes. Most users will want
to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
Experimental support for :ref:`cross-DSO control flow integrity
<cfi-cross-dso>` exists that does not require classes to have hidden LTO
visibility. This cross-DSO support has unstable ABI at this time.
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
@ -233,11 +245,6 @@ A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
entity types.
In addition, if a type has a ``uuid`` attribute and the blacklist contains
the type entry ``attr:uuid``, CFI checks are suppressed for that type. This
allows all COM types to be easily blacklisted, which is useful as COM types
are typically defined outside of the linked program.
.. code-block:: bash
# Suppress checking for code in a file.
@ -247,8 +254,6 @@ are typically defined outside of the linked program.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
# Ignore all types with a uuid attribute.
type:attr:uuid
.. _cfi-cross-dso:
@ -260,6 +265,11 @@ flow integrity mode, which allows all CFI schemes listed above to
apply across DSO boundaries. As in the regular CFI, each DSO must be
built with ``-flto``.
Normally, CFI checks will only be performed for classes that have hidden LTO
visibility. With this flag enabled, the compiler will emit cross-DSO CFI
checks for all classes, except for those which appear in the CFI blacklist
or which use a ``no_sanitize`` attribute.
Design
======

View File

@ -0,0 +1,111 @@
==============
LTO Visibility
==============
*LTO visibility* is a property of an entity that specifies whether it can be
referenced from outside the current LTO unit. A *linkage unit* is a set of
translation units linked together into an executable or DSO, and a linkage
unit's *LTO unit* is the subset of the linkage unit that is linked together
using link-time optimization; in the case where LTO is not being used, the
linkage unit's LTO unit is empty. Each linkage unit has only a single LTO unit.
The LTO visibility of a class is used by the compiler to determine which
classes the virtual function call optimization and control flow integrity
features apply to. These features use whole-program information, so they
require the entire class hierarchy to be visible in order to work correctly.
If any translation unit in the program uses either of the virtual function
call optimization or control flow integrity features, it is effectively an
ODR violation to define a class with hidden LTO visibility in multiple linkage
units. A class with public LTO visibility may be defined in multiple linkage
units, but the tradeoff is that the virtual function call optimization and
control flow integrity features can only be applied to classes with hidden LTO
visibility. A class's LTO visibility is treated as an ODR-relevant property
of its definition, so it must be consistent between translation units.
In translation units built with LTO, LTO visibility is based on symbol
visibility or, on the Windows platform, the dllimport and dllexport
attributes. When targeting non-Windows platforms, classes with a visibility
other than hidden visibility receive public LTO visibility. When targeting
Windows, classes with dllimport or dllexport attributes receive public LTO
visibility. All other classes receive hidden LTO visibility. Classes with
internal linkage (e.g. classes declared in unnamed namespaces) also receive
hidden LTO visibility.
A class defined in a translation unit built without LTO receives public
LTO visibility regardless of its object file visibility, linkage or other
attributes.
This mechanism will produce the correct result in most cases, but there are
two cases where it may wrongly infer hidden LTO visibility.
1. As a corollary of the above rules, if a linkage unit is produced from a
combination of LTO object files and non-LTO object files, any hidden
visibility class defined in both a translation unit built with LTO and
a translation unit built without LTO must be defined with public LTO
visibility in order to avoid an ODR violation.
2. Some ABIs provide the ability to define an abstract base class without
visibility attributes in multiple linkage units and have virtual calls
to derived classes in other linkage units work correctly. One example of
this is COM on Windows platforms. If the ABI allows this, any base class
used in this way must be defined with public LTO visibility.
Classes that fall into either of these categories can be marked up with the
``[[clang::lto_visibility_public]]`` attribute. To specifically handle the
COM case, classes with the ``__declspec(uuid())`` attribute receive public
LTO visibility. On Windows platforms, clang-cl's ``/MT`` and ``/MTd``
flags statically link the program against a prebuilt standard library;
these flags imply public LTO visibility for every class declared in the
``std`` and ``stdext`` namespaces.
Example
=======
The following example shows how LTO visibility works in practice in several
cases involving two linkage units, ``main`` and ``dso.so``.
.. code-block:: none
+-----------------------------------------------------------+ +----------------------------------------------------+
| main (clang++ -fvisibility=hidden): | | dso.so (clang++ -fvisibility=hidden): |
| | | |
| +-----------------------------------------------------+ | | struct __attribute__((visibility("default"))) C { |
| | LTO unit (clang++ -fvisibility=hidden -flto): | | | virtual void f(); |
| | | | | } |
| | struct A { ... }; | | | void C::f() {} |
| | struct [[clang::lto_visibility_public]] B { ... }; | | | struct D { |
| | struct __attribute__((visibility("default"))) C { | | | virtual void g() = 0; |
| | virtual void f(); | | | }; |
| | }; | | | struct E : D { |
| | struct [[clang::lto_visibility_public]] D { | | | virtual void g() { ... } |
| | virtual void g() = 0; | | | }; |
| | }; | | | __attribute__(visibility("default"))) D *mkE() { |
| | | | | return new E; |
| +-----------------------------------------------------+ | | } |
| | | |
| struct B { ... }; | +----------------------------------------------------+
| |
+-----------------------------------------------------------+
We will now describe the LTO visibility of each of the classes defined in
these linkage units.
Class ``A`` is not defined outside of ``main``'s LTO unit, so it can have
hidden LTO visibility. This is inferred from the object file visibility
specified on the command line.
Class ``B`` is defined in ``main``, both inside and outside its LTO unit. The
definition outside the LTO unit has public LTO visibility, so the definition
inside the LTO unit must also have public LTO visibility in order to avoid
an ODR violation.
Class ``C`` is defined in both ``main`` and ``dso.so`` and therefore must
have public LTO visibility. This is correctly inferred from the ``visibility``
attribute.
Class ``D`` is an abstract base class with a derived class ``E`` defined
in ``dso.so``. This is an example of the COM scenario; the definition of
``D`` in ``main``'s LTO unit must have public LTO visibility in order to be
compatible with the definition of ``D`` in ``dso.so``, which is observable
by calling the function ``mkE``.

View File

@ -1056,17 +1056,8 @@ are listed below.
.. option:: -fwhole-program-vtables
Enable whole-program vtable optimizations, such as single-implementation
devirtualization and virtual constant propagation. Requires ``-flto``.
By default, the compiler will assume that all type hierarchies are
closed except those in the ``std`` namespace, the ``stdext`` namespace
and classes with the ``__declspec(uuid())`` attribute.
.. option:: -fwhole-program-vtables-blacklist=path
Allows the user to specify the path to a list of additional classes to
blacklist from whole-program vtable optimizations. This list is in the
:ref:`CFI blacklist <cfi-blacklist>` format.
devirtualization and virtual constant propagation, for classes with
:doc:`hidden LTO visibility <LTOVisibility>`. Requires ``-flto``.
.. option:: -fno-assume-sane-operator-new

View File

@ -31,6 +31,7 @@ Using Clang as a Compiler
SanitizerStats
SanitizerSpecialCaseList
ControlFlowIntegrity
LTOVisibility
SafeStack
Modules
MSVCCompatibility

View File

@ -1611,6 +1611,12 @@ def WeakRef : InheritableAttr {
let Documentation = [Undocumented];
}
def LTOVisibilityPublic : InheritableAttr {
let Spellings = [CXX11<"clang", "lto_visibility_public">];
let Subjects = SubjectList<[Record]>;
let Documentation = [LTOVisibilityDocs];
}
def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
// NOTE: If you add any additional spellings, ARMInterrupt's,
// MSP430Interrupt's and MipsInterrupt's spellings must match.

View File

@ -2380,3 +2380,10 @@ The ``ifunc`` attribute may only be used on a function declaration. A function
Not all targets support this attribute. ELF targets support this attribute when using binutils v2.20.1 or higher and glibc v2.11.1 or higher. Non-ELF targets currently do not support this attribute.
}];
}
def LTOVisibilityDocs : Documentation {
let Category = DocCatType;
let Content = [{
See :doc:`LTOVisibility`.
}];
}

View File

@ -282,6 +282,9 @@ def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">,
def fprofile_instrument_use_path_EQ :
Joined<["-"], "fprofile-instrument-use-path=">,
HelpText<"Specify the profile path in PGO use compilation">;
def flto_visibility_public_std:
Flag<["-"], "flto-visibility-public-std">,
HelpText<"Use public LTO visibility for classes in std and stdext namespaces">;
//===----------------------------------------------------------------------===//
// Dependency Output Options

View File

@ -1152,9 +1152,6 @@ def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Grou
Flags<[CC1Option]>,
HelpText<"Enables whole-program vtable optimization. Requires -flto">;
def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>;
def fwhole_program_vtables_blacklist_EQ : Joined<["-"], "fwhole-program-vtables-blacklist=">,
Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Path to a blacklist file for whole-program vtable optimization">;
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,

View File

@ -187,6 +187,10 @@ CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
/// vtable optimization.
/// Whether to use public LTO visibility for entities in std and stdext
/// namespaces. This is enabled by clang-cl's /MT and /MTd flags.
CODEGENOPT(LTOVisibilityPublicStd, 1, 0)
/// The user specified number of registers to be used for integral arguments,
/// or 0 if unspecified.
VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)

View File

@ -199,9 +199,6 @@ public:
/// \brief A list of all -fno-builtin-* function names (e.g., memset).
std::vector<std::string> NoBuiltinFuncs;
/// List of blacklist files for the whole-program vtable optimization feature.
std::vector<std::string> WholeProgramVTablesBlacklistFiles;
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)

View File

@ -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);

View File

@ -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(),

View File

@ -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();

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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();

View File

@ -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:

View File

@ -148,16 +148,3 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
VERBATIM)
endif()
endif()
set(src "${CMAKE_CURRENT_SOURCE_DIR}/vtables_blacklist.txt")
set(dst "${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/vtables_blacklist.txt")
add_custom_command(OUTPUT ${dst}
DEPENDS ${src}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
COMMENT "Copying vtables blacklist")
add_custom_target(vtables_blacklist DEPENDS ${dst})
set_target_properties(vtables_blacklist PROPERTIES FOLDER "Misc")
if(TARGET clang)
add_dependencies(clang vtables_blacklist)
endif()
install(FILES ${src} DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})

View File

@ -1,8 +0,0 @@
# Standard library types.
type:std::*
# The stdext namespace contains Microsoft standard library extensions.
type:stdext::*
# Types with a uuid attribute, i.e. COM types.
type:attr:uuid

View File

@ -1,32 +0,0 @@
// RUN: echo "type:attr:uuid" > %t.txt
// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOUUID %s
// RUN: %clang_cc1 -fms-extensions -fwhole-program-vtables -fwhole-program-vtables-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOUUID %s
// RUN: echo "type:std::*" > %t.txt
// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
// RUN: %clang_cc1 -fms-extensions -fwhole-program-vtables -fwhole-program-vtables-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) S1 {
virtual void f();
};
namespace std {
struct S2 {
virtual void f();
};
}
// CHECK: define{{.*}}s1f
// NOSTD: llvm.bitset.test
// NOUUID-NOT: llvm.bitset.test
void s1f(S1 *s1) {
s1->f();
}
// CHECK: define{{.*}}s2f
// NOSTD-NOT: llvm.bitset.test
// NOUUID: llvm.bitset.test
void s2f(std::S2 *s2) {
s2->f();
}

View File

@ -0,0 +1,107 @@
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -std=c++11 -fms-extensions -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-STD %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -flto-visibility-public-std -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-NOSTD %s
struct C1 {
virtual void f();
};
struct __attribute__((visibility("default"))) C2 {
virtual void f();
};
struct __declspec(dllexport) C3 {
virtual void f();
};
struct __declspec(dllimport) C4 {
virtual void f();
};
struct [[clang::lto_visibility_public]] C5 {
virtual void f();
};
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) C6 {
virtual void f();
};
namespace std {
struct C7 {
virtual void f();
struct C8 {
virtual void f();
};
};
}
extern "C++" {
namespace stdext {
struct C9 {
virtual void f();
};
}
}
namespace other {
struct C10 {
virtual void f();
};
}
namespace {
struct C11 {
virtual void f();
};
}
void f(C1 *c1, C2 *c2, C3 *c3, C4 *c4, C5 *c5, C6 *c6, std::C7 *c7,
std::C7::C8 *c8, stdext::C9 *c9, other::C10 *c10) {
// ITANIUM: bitset.test{{.*}}!"_ZTS2C1"
// MS: bitset.test{{.*}}!"?AUC1@@"
c1->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C2"
// MS: bitset.test{{.*}}!"?AUC2@@"
c2->f();
// ITANIUM: bitset.test{{.*}}!"_ZTS2C3"
// MS-NOT: bitset.test{{.*}}!"?AUC3@@"
c3->f();
// ITANIUM: bitset.test{{.*}}!"_ZTS2C4"
// MS-NOT: bitset.test{{.*}}!"?AUC4@@"
c4->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C5"
// MS-NOT: bitset.test{{.*}}!"?AUC5@@"
c5->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C6"
// MS-NOT: bitset.test{{.*}}!"?AUC6@@"
c6->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSSt2C7"
// MS-STD: bitset.test{{.*}}!"?AUC7@std@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC7@std@@"
c7->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSNSt2C72C8E"
// MS-STD: bitset.test{{.*}}!"?AUC8@C7@std@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC8@C7@std@@"
c8->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSN6stdext2C9E"
// MS-STD: bitset.test{{.*}}!"?AUC9@stdext@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC9@stdext@@"
c9->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSN5other3C10E"
// MS: bitset.test{{.*}}!"?AUC10@other@@"
c10->f();
// ITANIUM: bitset.test{{.*}}!{{[0-9]}}
// MS: bitset.test{{.*}}!{{[0-9]}}
C11 *c11;
c11->f();
}

View File

@ -1,12 +1,12 @@
// Tests for the cfi-vcall feature:
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
// Tests for the whole-program-vtables feature:
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
// MS: @[[VTA:[0-9]*]] {{.*}} comdat($"\01??_7A@@6B@")
// MS: @[[VTB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6B0@@")
@ -62,7 +62,7 @@ void D::h() {
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+24]], i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
// ITANIUM: define void @_Z2afP1A
// ITANIUM: define hidden void @_Z2afP1A
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
void af(A *a) {
// ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
@ -155,7 +155,7 @@ struct D : C {
void m_fn1();
};
// ITANIUM: define void @_ZN5test21fEPNS_1DE
// ITANIUM: define hidden void @_ZN5test21fEPNS_1DE
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
void f(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")

View File

@ -0,0 +1,29 @@
// RUN: %clang_cc1 -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
// RUN: echo "type:std::*" > %t.txt
// RUN: %clang_cc1 -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
struct S1 {
virtual void f();
};
namespace std {
struct S2 {
virtual void f();
};
}
// CHECK: define{{.*}}s1f
// NOBL: llvm.bitset.test
// NOSTD: llvm.bitset.test
void s1f(S1 *s1) {
s1->f();
}
// CHECK: define{{.*}}s2f
// NOBL: llvm.bitset.test
// NOSTD-NOT: llvm.bitset.test
void s2f(std::S2 *s2) {
s2->f();
}

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast -fsanitize-trap=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast,cfi-cast-strict -fsanitize-trap=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -std=c++11 -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -std=c++11 -fsanitize=cfi-unrelated-cast -fsanitize-trap=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -std=c++11 -fsanitize=cfi-unrelated-cast,cfi-cast-strict -fsanitize-trap=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s
// In this test the main thing we are searching for is something like
// 'metadata !"1B"' where "1B" is the mangled name of the class we are
@ -17,7 +17,7 @@ struct B : A {
struct C : A {};
// CHECK-DCAST-LABEL: define void @_Z3abpP1A
// CHECK-DCAST-LABEL: define hidden void @_Z3abpP1A
void abp(A *a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -31,7 +31,7 @@ void abp(A *a) {
(void)static_cast<B*>(a);
}
// CHECK-DCAST-LABEL: define void @_Z3abrR1A
// CHECK-DCAST-LABEL: define hidden void @_Z3abrR1A
void abr(A &a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -45,7 +45,7 @@ void abr(A &a) {
(void)static_cast<B&>(a);
}
// CHECK-DCAST-LABEL: define void @_Z4abrrO1A
// CHECK-DCAST-LABEL: define hidden void @_Z4abrrO1A
void abrr(A &&a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -59,7 +59,7 @@ void abrr(A &&a) {
(void)static_cast<B&&>(a);
}
// CHECK-UCAST-LABEL: define void @_Z3vbpPv
// CHECK-UCAST-LABEL: define hidden void @_Z3vbpPv
void vbp(void *p) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -73,7 +73,7 @@ void vbp(void *p) {
(void)static_cast<B*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3vbrRc
// CHECK-UCAST-LABEL: define hidden void @_Z3vbrRc
void vbr(char &r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -87,7 +87,7 @@ void vbr(char &r) {
(void)reinterpret_cast<B&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z4vbrrOc
// CHECK-UCAST-LABEL: define hidden void @_Z4vbrrOc
void vbrr(char &&r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
@ -101,32 +101,32 @@ void vbrr(char &&r) {
(void)reinterpret_cast<B&&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define void @_Z3vcpPv
// CHECK-UCAST-LABEL: define hidden void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3vcpPv
void vcp(void *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(void)static_cast<C*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3bcpP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z3bcpP1B
// CHECK-UCAST-LABEL: define hidden void @_Z3bcpP1B
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3bcpP1B
void bcp(B *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(void)(C *)p;
}
// CHECK-UCAST-LABEL: define void @_Z8bcp_callP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z8bcp_callP1B
// CHECK-UCAST-LABEL: define hidden void @_Z8bcp_callP1B
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z8bcp_callP1B
void bcp_call(B *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
((C *)p)->f();
}
// CHECK-UCAST-LABEL: define i32 @_Z6a_callP1A
// CHECK-UCAST-STRICT-LABEL: define i32 @_Z6a_callP1A
// CHECK-UCAST-LABEL: define hidden i32 @_Z6a_callP1A
// CHECK-UCAST-STRICT-LABEL: define hidden i32 @_Z6a_callP1A
int a_call(A *a) {
// CHECK-UCAST-NOT: @llvm.bitset.test
// CHECK-UCAST-STRICT-NOT: @llvm.bitset.test

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
struct A {
A();

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s
// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s
// RUN: %clang_cc1 -flto -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s
// RUN: %clang_cc1 -flto -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s
struct A {
A();

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall,cfi-cast-strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-nvcall -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-nvcall,cfi-cast-strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
struct A {
virtual void f();

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck %s
// CHECK: [[STATS:@[^ ]*]] = internal global { i8*, i32, [5 x [2 x i8*]] } { i8* null, i32 5, [5 x [2 x i8*]]
// CHECK: {{\[\[}}2 x i8*] zeroinitializer,

View File

@ -13,6 +13,7 @@
// CHECK-MT-NOT: "-D_DEBUG"
// CHECK-MT: "-D_MT"
// CHECK-MT-NOT: "-D_DLL"
// CHECK-MT: "-flto-visibility-public-std"
// CHECK-MT: "--dependent-lib=libcmt"
// CHECK-MT: "--dependent-lib=oldnames"
@ -21,6 +22,7 @@
// CHECK-MTd: "-D_DEBUG"
// CHECK-MTd: "-D_MT"
// CHECK-MTd-NOT: "-D_DLL"
// CHECK-MTd: "-flto-visibility-public-std"
// CHECK-MTd: "--dependent-lib=libcmtd"
// CHECK-MTd: "--dependent-lib=oldnames"

View File

@ -291,21 +291,27 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-derived-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-DCAST
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-unrelated-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL
// RUN: %clang -target x86_64-linux-gnu -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
// RUN: %clang -target x86_64-apple-darwin10 -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
// RUN: %clang -target x86_64-linux-gnu -fvisibility=hidden -fsanitize=cfi-derived-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-DCAST
// RUN: %clang -target x86_64-linux-gnu -fvisibility=hidden -fsanitize=cfi-unrelated-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST
// RUN: %clang -target x86_64-linux-gnu -flto -fvisibility=hidden -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL
// RUN: %clang -target x86_64-linux-gnu -flto -fvisibility=hidden -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL
// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-icall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
// CHECK-CFI-DCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast
// CHECK-CFI-UCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-unrelated-cast
// CHECK-CFI-NVCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-nvcall
// CHECK-CFI-VCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-vcall
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-derived-cast -fno-lto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOLTO
// RUN: %clang -target x86_64-linux-gnu -fvisibility=hidden -flto -fsanitize=cfi-derived-cast -fno-lto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOLTO
// CHECK-CFI-NOLTO: '-fsanitize=cfi-derived-cast' only allowed with '-flto'
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-derived-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOVIS
// CHECK-CFI-NOVIS: '-fsanitize=cfi-derived-cast' only allowed with '-fvisibility='
// RUN: %clang -target x86_64-pc-win32 -flto -fsanitize=cfi-derived-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOVIS-WIN
// CHECK-CFI-NOVIS-WIN-NOT: only allowed with
// RUN: %clang -target mips-unknown-linux -fsanitize=cfi-icall %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-ICALL-MIPS
// CHECK-CFI-ICALL-MIPS: unsupported option '-fsanitize=cfi-icall' for target 'mips-unknown-linux'

View File

@ -1,11 +1,2 @@
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s
// NO-LTO: invalid argument '-fwhole-program-vtables' only allowed with '-flto'
// RUN: %clang -target x86_64-unknown-linux -resource-dir=%S/Inputs/resource_dir -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=BLACKLIST %s
// BLACKLIST: "-fwhole-program-vtables-blacklist={{.*}}vtables_blacklist.txt"
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables-blacklist=nonexistent.txt -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=NON-EXISTENT-BLACKLIST %s
// NON-EXISTENT-BLACKLIST: no such file or directory: 'nonexistent.txt'
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables-blacklist=%S/Inputs/resource_dir/vtables_blacklist.txt -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=CUSTOM-BLACKLIST %s
// CUSTOM-BLACKLIST: "-fwhole-program-vtables-blacklist={{.*}}Inputs/resource_dir/vtables_blacklist.txt"

View File

@ -21,7 +21,7 @@
// RUN: %clang -MD -MF - %s -fsyntax-only -I ./ | FileCheck -check-prefix=CHECK-SIX %s
// CHECK-SIX: {{ }}x.h
// RUN: echo "fun:foo" > %t.blacklist
// RUN: %clang -MD -MF - %s -fsyntax-only -fsanitize=cfi-vcall -flto -fsanitize-blacklist=%t.blacklist -I ./ | FileCheck -check-prefix=CHECK-SEVEN %s
// RUN: %clang -MD -MF - %s -fsyntax-only -fsanitize=cfi-vcall -flto -fvisibility=hidden -fsanitize-blacklist=%t.blacklist -I ./ | FileCheck -check-prefix=CHECK-SEVEN %s
// CHECK-SEVEN: .blacklist
// CHECK-SEVEN: {{ }}x.h
#ifndef INCLUDE_FLAG_TEST

View File

@ -0,0 +1,14 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
int i [[clang::lto_visibility_public]]; // expected-warning {{'lto_visibility_public' attribute only applies to struct, union or class}}
typedef int t [[clang::lto_visibility_public]]; // expected-warning {{'lto_visibility_public' attribute only applies to struct, union or class}}
[[clang::lto_visibility_public]] void f(); // expected-warning {{'lto_visibility_public' attribute only applies to struct, union or class}}
void f() [[clang::lto_visibility_public]]; // expected-error {{'lto_visibility_public' attribute cannot be applied to types}}
struct [[clang::lto_visibility_public]] s1 {
int i [[clang::lto_visibility_public]]; // expected-warning {{'lto_visibility_public' attribute only applies to struct, union or class}}
[[clang::lto_visibility_public]] void f(); // expected-warning {{'lto_visibility_public' attribute only applies to struct, union or class}}
};
struct [[clang::lto_visibility_public(1)]] s2 { // expected-error {{'lto_visibility_public' attribute takes no arguments}}
};

View File

@ -2524,6 +2524,7 @@ static std::string CalculateDiagnostic(const Record &S) {
case ObjCProtocol | ObjCInterface:
return "ExpectedObjectiveCInterfaceOrProtocol";
case Field | Var: return "ExpectedFieldOrGlobalVar";
case GenericRecord | Namespace: return "ExpectedRecordOrNamespace";
}
PrintFatalError(S.getLoc(),