-
Notifications
You must be signed in to change notification settings - Fork 14.4k
Add pointer field protection feature. #133538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/pcc/spr/main.add-pointer-field-protection-feature
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -379,6 +379,17 @@ class LangOptionsBase { | |
BKey | ||
}; | ||
|
||
enum class PointerFieldProtectionKind { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I like this being solely a global decision - it makes custom allocators much harder, and it makes it hard for allocators that have different policies, e.g struct ImportantStruct {
void *operator new(size_t) { /*tagged allocator*/ }
};
struct BoringStruct {
...
};
struct SomeOtherStruct {
ImportantStruct *important; // should be tagged pointer
BoringString *lessImportant; // should be a non tagged pointer
}; This would again require a struct attribute to indicate the pointer policy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that allowing this level of customization should be implemented as part of the separate opt-in solution (e.g. it may be a property of the qualifier). It is generally a reasonable assumption that operator new is the same for all types. In the unlikely case that it isn't, we aren't really doing anything wrong by using the malloc-derived decision here. It just means that we lose some entropy from the type or the pointer tag. |
||
/// Pointer field protection disabled | ||
None, | ||
/// Pointer field protection enabled, allocator does not tag heap | ||
/// allocations. | ||
Untagged, | ||
/// Pointer field protection enabled, allocator is expected to tag heap | ||
/// allocations. | ||
Tagged, | ||
}; | ||
|
||
enum class ThreadModelKind { | ||
/// POSIX Threads. | ||
POSIX, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3033,6 +3033,12 @@ defm experimental_omit_vtable_rtti : BoolFOption<"experimental-omit-vtable-rtti" | |
NegFlag<SetFalse, [], [CC1Option], "Do not omit">, | ||
BothFlags<[], [CC1Option], " the RTTI component from virtual tables">>; | ||
|
||
def experimental_pointer_field_protection_EQ : Joined<["-"], "fexperimental-pointer-field-protection=">, Group<f_Group>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above, not super sure that I like this being a global compile time setting, but maybe it makes sense to be. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (See other reply.) |
||
Visibility<[ClangOption, CC1Option]>, | ||
Values<"none,untagged,tagged">, NormalizedValuesScope<"LangOptions::PointerFieldProtectionKind">, | ||
NormalizedValues<["None", "Untagged", "Tagged"]>, | ||
MarshallingInfoEnum<LangOpts<"PointerFieldProtection">, "None">; | ||
|
||
def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">, | ||
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>, | ||
HelpText<"C++ ABI to use. This will override the target C++ ABI.">; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This an ABI break so I don't think it can reasonably an on by default for all structs - we can already see annotations in libc++, and they would be needed on every single struct field.
We can imagine a new platform where this would be the platform ABI, but for every other case it is functionally unusable.
I would recommend attributes to permit opt in and opt out on a per-struct basis, and CLI flags to select the default behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are numerous circumstances where the C++ ABI is distinct from the platform ABI and is allowed to change. For example, most Chromium-based web browsers ship with a statically linked libc++, and the same is true for many Android apps and server-side software at Google. In the intended usage model, all of libc++ would be built with a
-fexperimental-pointer-field-protection=
flag consistent with the rest of the program.The libc++abi opt-outs that I added are only for opting out pointer fields of RTTI structs that are generated by the compiler. In principle, we could teach the compiler to sign those pointer fields which would let us remove the opt-outs, but there is a lower ROI for subjecting those fields to PFP because the RTTI structs are not typically dynamically allocated.
We may consider adding an attribute to allow opting in in the case where the flag is not passed. But I think we should do that in a followup. We would need to carefully consider how that would interact with the other aspects of the opt-in solution, such as the pointer qualifiers.