aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
authormodimo <modimo@fb.com>2023-07-13 19:02:52 -0700
committermodimo <modimo@fb.com>2023-09-18 15:51:49 -0700
commit272bd6f9cc86bf6b4dd6bd51e85c46db10e8b86a (patch)
treefd79fdbbbb65537e9e78ac848bfacd045b59f7d1 /llvm/lib/LTO/LTO.cpp
parent4176ce61f156c8daa1e6bf8cc86d5e61e9413149 (diff)
downloadllvm-272bd6f9cc86bf6b4dd6bd51e85c46db10e8b86a.zip
llvm-272bd6f9cc86bf6b4dd6bd51e85c46db10e8b86a.tar.gz
llvm-272bd6f9cc86bf6b4dd6bd51e85c46db10e8b86a.tar.bz2
[WPD][LLD] Add option to validate RTTI is enabled on all native types and prevent devirtualization on types with native RTTI
Discussion about this approach: https://discourse.llvm.org/t/rfc-safer-whole-program-class-hierarchy-analysis/65144/18 When enabling WPD in an environment where native binaries are present, types we want to optimize can be derived from inside these native files and devirtualizing them can lead to correctness issues. RTTI can be used as a way to determine all such types in native files and exclude them from WPD providing a safe checked way to enable WPD. The approach is: 1. In the linker, identify if RTTI is available for all native types. If not, under `--lto-validate-all-vtables-have-type-infos` `--lto-whole-program-visibility` is automatically disabled. This is done by examining all .symtab symbols in object files and .dynsym symbols in DSOs for vtable (_ZTV) and typeinfo (_ZTI) symbols and ensuring there's always a match for every vtable symbol. 2. During thinlink, if `--lto-validate-all-vtables-have-type-infos` is set and RTTI is available for all native types, identify all typename (_ZTS) symbols via their corresponding typeinfo (_ZTI) symbols that are used natively or outside of our summary and exclude them from WPD. Testing: ninja check-all large Meta service that uses boost, glog and libstdc++.so runs successfully with WPD via --lto-whole-program-visibility. Previously, native types in boost caused incorrect devirtualization that led to crashes. Reviewed By: MaskRay, tejohnson Differential Revision: https://reviews.llvm.org/D155659
Diffstat (limited to 'llvm/lib/LTO/LTO.cpp')
-rw-r--r--llvm/lib/LTO/LTO.cpp55
1 files changed, 47 insertions, 8 deletions
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 3e008ed..4a64aa4 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -1270,13 +1270,27 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
updateMemProfAttributes(*RegularLTO.CombinedModule, ThinLTO.CombinedIndex);
+ bool WholeProgramVisibilityEnabledInLTO =
+ Conf.HasWholeProgramVisibility &&
+ // If validation is enabled, upgrade visibility only when all vtables
+ // have typeinfos.
+ (!Conf.ValidateAllVtablesHaveTypeInfos || Conf.AllVtablesHaveTypeInfos);
+
+ // This returns true when the name is local or not defined. Locals are
+ // expected to be handled separately.
+ auto IsVisibleToRegularObj = [&](StringRef name) {
+ auto It = GlobalResolutions.find(name);
+ return (It == GlobalResolutions.end() || It->second.VisibleOutsideSummary);
+ };
+
// If allowed, upgrade public vcall visibility metadata to linkage unit
// visibility before whole program devirtualization in the optimizer.
- updateVCallVisibilityInModule(*RegularLTO.CombinedModule,
- Conf.HasWholeProgramVisibility,
- DynamicExportSymbols);
+ updateVCallVisibilityInModule(
+ *RegularLTO.CombinedModule, WholeProgramVisibilityEnabledInLTO,
+ DynamicExportSymbols, Conf.ValidateAllVtablesHaveTypeInfos,
+ IsVisibleToRegularObj);
updatePublicTypeTestCalls(*RegularLTO.CombinedModule,
- Conf.HasWholeProgramVisibility);
+ WholeProgramVisibilityEnabledInLTO);
if (Conf.PreOptModuleHook &&
!Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
@@ -1683,13 +1697,38 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
std::set<GlobalValue::GUID> ExportedGUIDs;
- if (hasWholeProgramVisibility(Conf.HasWholeProgramVisibility))
+ bool WholeProgramVisibilityEnabledInLTO =
+ Conf.HasWholeProgramVisibility &&
+ // If validation is enabled, upgrade visibility only when all vtables
+ // have typeinfos.
+ (!Conf.ValidateAllVtablesHaveTypeInfos || Conf.AllVtablesHaveTypeInfos);
+ if (hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
ThinLTO.CombinedIndex.setWithWholeProgramVisibility();
+
+ // If we're validating, get the vtable symbols that should not be
+ // upgraded because they correspond to typeIDs outside of index-based
+ // WPD info.
+ DenseSet<GlobalValue::GUID> VisibleToRegularObjSymbols;
+ if (WholeProgramVisibilityEnabledInLTO &&
+ Conf.ValidateAllVtablesHaveTypeInfos) {
+ // This returns true when the name is local or not defined. Locals are
+ // expected to be handled separately.
+ auto IsVisibleToRegularObj = [&](StringRef name) {
+ auto It = GlobalResolutions.find(name);
+ return (It == GlobalResolutions.end() ||
+ It->second.VisibleOutsideSummary);
+ };
+
+ getVisibleToRegularObjVtableGUIDs(ThinLTO.CombinedIndex,
+ VisibleToRegularObjSymbols,
+ IsVisibleToRegularObj);
+ }
+
// If allowed, upgrade public vcall visibility to linkage unit visibility in
// the summaries before whole program devirtualization below.
- updateVCallVisibilityInIndex(ThinLTO.CombinedIndex,
- Conf.HasWholeProgramVisibility,
- DynamicExportSymbols);
+ updateVCallVisibilityInIndex(
+ ThinLTO.CombinedIndex, WholeProgramVisibilityEnabledInLTO,
+ DynamicExportSymbols, VisibleToRegularObjSymbols);
// Perform index-based WPD. This will return immediately if there are
// no index entries in the typeIdMetadata map (e.g. if we are instead