Skip to content

Commit a8b2f7c

Browse files
committed
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
1 parent 60c4e6a commit a8b2f7c

36 files changed

+432
-209
lines changed

clang/docs/ControlFlowIntegrity.rst

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,25 @@ As currently implemented, all schemes rely on link-time optimization (LTO);
2525
so it is required to specify ``-flto``, and the linker used must support LTO,
2626
for example via the `gold plugin`_.
2727

28-
To allow the checks to be implemented efficiently, the program must be
29-
structured such that certain object files are compiled with CFI
28+
To allow the checks to be implemented efficiently, the program must
29+
be structured such that certain object files are compiled with CFI
3030
enabled, and are statically linked into the program. This may preclude
31-
the use of shared libraries in some cases. Experimental support for
32-
:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
33-
does not have these requirements. This cross-DSO support has unstable
34-
ABI at this time.
31+
the use of shared libraries in some cases.
32+
33+
The compiler will only produce CFI checks for a class if it can infer hidden
34+
LTO visibility for that class. LTO visibility is a property of a class that
35+
is inferred from flags and attributes. For more details, see the documentation
36+
for :doc:`LTO visibility <LTOVisibility>`.
37+
38+
The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
39+
require that a ``-fvisibility=`` flag also be specified. This is because the
40+
default visibility setting is ``-fvisibility=default``, which would disable
41+
CFI checks for classes without visibility attributes. Most users will want
42+
to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
43+
44+
Experimental support for :ref:`cross-DSO control flow integrity
45+
<cfi-cross-dso>` exists that does not require classes to have hidden LTO
46+
visibility. This cross-DSO support has unstable ABI at this time.
3547

3648
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
3749

@@ -233,11 +245,6 @@ A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
233245
source files, functions and types using the ``src``, ``fun`` and ``type``
234246
entity types.
235247

236-
In addition, if a type has a ``uuid`` attribute and the blacklist contains
237-
the type entry ``attr:uuid``, CFI checks are suppressed for that type. This
238-
allows all COM types to be easily blacklisted, which is useful as COM types
239-
are typically defined outside of the linked program.
240-
241248
.. code-block:: bash
242249
243250
# Suppress checking for code in a file.
@@ -247,8 +254,6 @@ are typically defined outside of the linked program.
247254
fun:*MyFooBar*
248255
# Ignore all types in the standard library.
249256
type:std::*
250-
# Ignore all types with a uuid attribute.
251-
type:attr:uuid
252257
253258
.. _cfi-cross-dso:
254259

@@ -260,6 +265,11 @@ flow integrity mode, which allows all CFI schemes listed above to
260265
apply across DSO boundaries. As in the regular CFI, each DSO must be
261266
built with ``-flto``.
262267

268+
Normally, CFI checks will only be performed for classes that have hidden LTO
269+
visibility. With this flag enabled, the compiler will emit cross-DSO CFI
270+
checks for all classes, except for those which appear in the CFI blacklist
271+
or which use a ``no_sanitize`` attribute.
272+
263273
Design
264274
======
265275

clang/docs/LTOVisibility.rst

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
==============
2+
LTO Visibility
3+
==============
4+
5+
*LTO visibility* is a property of an entity that specifies whether it can be
6+
referenced from outside the current LTO unit. A *linkage unit* is a set of
7+
translation units linked together into an executable or DSO, and a linkage
8+
unit's *LTO unit* is the subset of the linkage unit that is linked together
9+
using link-time optimization; in the case where LTO is not being used, the
10+
linkage unit's LTO unit is empty. Each linkage unit has only a single LTO unit.
11+
12+
The LTO visibility of a class is used by the compiler to determine which
13+
classes the virtual function call optimization and control flow integrity
14+
features apply to. These features use whole-program information, so they
15+
require the entire class hierarchy to be visible in order to work correctly.
16+
17+
If any translation unit in the program uses either of the virtual function
18+
call optimization or control flow integrity features, it is effectively an
19+
ODR violation to define a class with hidden LTO visibility in multiple linkage
20+
units. A class with public LTO visibility may be defined in multiple linkage
21+
units, but the tradeoff is that the virtual function call optimization and
22+
control flow integrity features can only be applied to classes with hidden LTO
23+
visibility. A class's LTO visibility is treated as an ODR-relevant property
24+
of its definition, so it must be consistent between translation units.
25+
26+
In translation units built with LTO, LTO visibility is based on symbol
27+
visibility or, on the Windows platform, the dllimport and dllexport
28+
attributes. When targeting non-Windows platforms, classes with a visibility
29+
other than hidden visibility receive public LTO visibility. When targeting
30+
Windows, classes with dllimport or dllexport attributes receive public LTO
31+
visibility. All other classes receive hidden LTO visibility. Classes with
32+
internal linkage (e.g. classes declared in unnamed namespaces) also receive
33+
hidden LTO visibility.
34+
35+
A class defined in a translation unit built without LTO receives public
36+
LTO visibility regardless of its object file visibility, linkage or other
37+
attributes.
38+
39+
This mechanism will produce the correct result in most cases, but there are
40+
two cases where it may wrongly infer hidden LTO visibility.
41+
42+
1. As a corollary of the above rules, if a linkage unit is produced from a
43+
combination of LTO object files and non-LTO object files, any hidden
44+
visibility class defined in both a translation unit built with LTO and
45+
a translation unit built without LTO must be defined with public LTO
46+
visibility in order to avoid an ODR violation.
47+
48+
2. Some ABIs provide the ability to define an abstract base class without
49+
visibility attributes in multiple linkage units and have virtual calls
50+
to derived classes in other linkage units work correctly. One example of
51+
this is COM on Windows platforms. If the ABI allows this, any base class
52+
used in this way must be defined with public LTO visibility.
53+
54+
Classes that fall into either of these categories can be marked up with the
55+
``[[clang::lto_visibility_public]]`` attribute. To specifically handle the
56+
COM case, classes with the ``__declspec(uuid())`` attribute receive public
57+
LTO visibility. On Windows platforms, clang-cl's ``/MT`` and ``/MTd``
58+
flags statically link the program against a prebuilt standard library;
59+
these flags imply public LTO visibility for every class declared in the
60+
``std`` and ``stdext`` namespaces.
61+
62+
Example
63+
=======
64+
65+
The following example shows how LTO visibility works in practice in several
66+
cases involving two linkage units, ``main`` and ``dso.so``.
67+
68+
.. code-block:: none
69+
70+
+-----------------------------------------------------------+ +----------------------------------------------------+
71+
| main (clang++ -fvisibility=hidden): | | dso.so (clang++ -fvisibility=hidden): |
72+
| | | |
73+
| +-----------------------------------------------------+ | | struct __attribute__((visibility("default"))) C { |
74+
| | LTO unit (clang++ -fvisibility=hidden -flto): | | | virtual void f(); |
75+
| | | | | } |
76+
| | struct A { ... }; | | | void C::f() {} |
77+
| | struct [[clang::lto_visibility_public]] B { ... }; | | | struct D { |
78+
| | struct __attribute__((visibility("default"))) C { | | | virtual void g() = 0; |
79+
| | virtual void f(); | | | }; |
80+
| | }; | | | struct E : D { |
81+
| | struct [[clang::lto_visibility_public]] D { | | | virtual void g() { ... } |
82+
| | virtual void g() = 0; | | | }; |
83+
| | }; | | | __attribute__(visibility("default"))) D *mkE() { |
84+
| | | | | return new E; |
85+
| +-----------------------------------------------------+ | | } |
86+
| | | |
87+
| struct B { ... }; | +----------------------------------------------------+
88+
| |
89+
+-----------------------------------------------------------+
90+
91+
We will now describe the LTO visibility of each of the classes defined in
92+
these linkage units.
93+
94+
Class ``A`` is not defined outside of ``main``'s LTO unit, so it can have
95+
hidden LTO visibility. This is inferred from the object file visibility
96+
specified on the command line.
97+
98+
Class ``B`` is defined in ``main``, both inside and outside its LTO unit. The
99+
definition outside the LTO unit has public LTO visibility, so the definition
100+
inside the LTO unit must also have public LTO visibility in order to avoid
101+
an ODR violation.
102+
103+
Class ``C`` is defined in both ``main`` and ``dso.so`` and therefore must
104+
have public LTO visibility. This is correctly inferred from the ``visibility``
105+
attribute.
106+
107+
Class ``D`` is an abstract base class with a derived class ``E`` defined
108+
in ``dso.so``. This is an example of the COM scenario; the definition of
109+
``D`` in ``main``'s LTO unit must have public LTO visibility in order to be
110+
compatible with the definition of ``D`` in ``dso.so``, which is observable
111+
by calling the function ``mkE``.

clang/docs/UsersManual.rst

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,17 +1056,8 @@ are listed below.
10561056
.. option:: -fwhole-program-vtables
10571057

10581058
Enable whole-program vtable optimizations, such as single-implementation
1059-
devirtualization and virtual constant propagation. Requires ``-flto``.
1060-
1061-
By default, the compiler will assume that all type hierarchies are
1062-
closed except those in the ``std`` namespace, the ``stdext`` namespace
1063-
and classes with the ``__declspec(uuid())`` attribute.
1064-
1065-
.. option:: -fwhole-program-vtables-blacklist=path
1066-
1067-
Allows the user to specify the path to a list of additional classes to
1068-
blacklist from whole-program vtable optimizations. This list is in the
1069-
:ref:`CFI blacklist <cfi-blacklist>` format.
1059+
devirtualization and virtual constant propagation, for classes with
1060+
:doc:`hidden LTO visibility <LTOVisibility>`. Requires ``-flto``.
10701061

10711062
.. option:: -fno-assume-sane-operator-new
10721063

clang/docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Using Clang as a Compiler
3131
SanitizerStats
3232
SanitizerSpecialCaseList
3333
ControlFlowIntegrity
34+
LTOVisibility
3435
SafeStack
3536
Modules
3637
MSVCCompatibility

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,12 @@ def WeakRef : InheritableAttr {
16111611
let Documentation = [Undocumented];
16121612
}
16131613

1614+
def LTOVisibilityPublic : InheritableAttr {
1615+
let Spellings = [CXX11<"clang", "lto_visibility_public">];
1616+
let Subjects = SubjectList<[Record]>;
1617+
let Documentation = [LTOVisibilityDocs];
1618+
}
1619+
16141620
def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
16151621
// NOTE: If you add any additional spellings, ARMInterrupt's,
16161622
// MSP430Interrupt's and MipsInterrupt's spellings must match.

clang/include/clang/Basic/AttrDocs.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2380,3 +2380,10 @@ The ``ifunc`` attribute may only be used on a function declaration. A function
23802380
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.
23812381
}];
23822382
}
2383+
2384+
def LTOVisibilityDocs : Documentation {
2385+
let Category = DocCatType;
2386+
let Content = [{
2387+
See :doc:`LTOVisibility`.
2388+
}];
2389+
}

clang/include/clang/Driver/CC1Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">,
282282
def fprofile_instrument_use_path_EQ :
283283
Joined<["-"], "fprofile-instrument-use-path=">,
284284
HelpText<"Specify the profile path in PGO use compilation">;
285+
def flto_visibility_public_std:
286+
Flag<["-"], "flto-visibility-public-std">,
287+
HelpText<"Use public LTO visibility for classes in std and stdext namespaces">;
285288

286289
//===----------------------------------------------------------------------===//
287290
// Dependency Output Options

clang/include/clang/Driver/Options.td

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,9 +1152,6 @@ def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Grou
11521152
Flags<[CC1Option]>,
11531153
HelpText<"Enables whole-program vtable optimization. Requires -flto">;
11541154
def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>;
1155-
def fwhole_program_vtables_blacklist_EQ : Joined<["-"], "fwhole-program-vtables-blacklist=">,
1156-
Group<f_Group>, Flags<[CC1Option]>,
1157-
HelpText<"Path to a blacklist file for whole-program vtable optimization">;
11581155
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
11591156
HelpText<"Treat signed integer overflow as two's complement">;
11601157
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,

clang/include/clang/Frontend/CodeGenOptions.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
187187
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
188188
/// vtable optimization.
189189

190+
/// Whether to use public LTO visibility for entities in std and stdext
191+
/// namespaces. This is enabled by clang-cl's /MT and /MTd flags.
192+
CODEGENOPT(LTOVisibilityPublicStd, 1, 0)
193+
190194
/// The user specified number of registers to be used for integral arguments,
191195
/// or 0 if unspecified.
192196
VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)

clang/include/clang/Frontend/CodeGenOptions.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,6 @@ class CodeGenOptions : public CodeGenOptionsBase {
199199
/// \brief A list of all -fno-builtin-* function names (e.g., memset).
200200
std::vector<std::string> NoBuiltinFuncs;
201201

202-
/// List of blacklist files for the whole-program vtable optimization feature.
203-
std::vector<std::string> WholeProgramVTablesBlacklistFiles;
204-
205202
public:
206203
// Define accessors/mutators for code generation options of enumeration type.
207204
#define CODEGENOPT(Name, Bits, Default)

0 commit comments

Comments
 (0)