diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index f64e29be3205f..271fb831406fb 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -681,7 +681,7 @@ class ASTContext : public RefCountedBase { bool containsAddressDiscriminatedPointerAuth(QualType T) const { if (!isPointerAuthenticationAvailable()) return false; - return findPointerAuthContent(T) != PointerAuthContent::None; + return (findPointerAuthContent(T) & PointerAuthContent::ContainsAddressDiscriminatedData) != PointerAuthContent::ContainsNone; } /// Examines a given type, and returns whether the type itself @@ -692,7 +692,18 @@ class ASTContext : public RefCountedBase { bool containsNonRelocatablePointerAuth(QualType T) { if (!isPointerAuthenticationAvailable()) return false; - return findPointerAuthContent(T) != PointerAuthContent::None; + return (findPointerAuthContent(T) & PointerAuthContent::ContainsAddressDiscriminatedData) != PointerAuthContent::ContainsNone; + } + + bool containsDefaultAuthenticatedFunctionPointer(QualType T) { + if (!isPointerAuthenticationAvailable()) + return false; + return (findPointerAuthContent(T) & PointerAuthContent::ContainsDefaultAuthenticatedFunction) != PointerAuthContent::ContainsNone; + } + + // A simple helper function to short circuit pointer auth checks. + bool isPointerAuthenticationAvailable() const { + return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; } private: @@ -701,15 +712,14 @@ class ASTContext : public RefCountedBase { // FIXME: store in RecordDeclBitfields in future? enum class PointerAuthContent : uint8_t { - None, - AddressDiscriminatedVTable, - AddressDiscriminatedData + ContainsNone = 0, + ContainsAddressDiscriminatedVTable = 1 << 0, + ContainsAddressDiscriminatedData = 1 << 1, + ContainsDefaultAuthenticatedFunction = 1 << 2, + ContainsAllFlags = ContainsAddressDiscriminatedVTable | ContainsAddressDiscriminatedData | ContainsDefaultAuthenticatedFunction, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ContainsDefaultAuthenticatedFunction) }; - // A simple helper function to short circuit pointer auth checks. - bool isPointerAuthenticationAvailable() const { - return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; - } PointerAuthContent findPointerAuthContent(QualType T) const; mutable llvm::DenseMap RecordContainsAddressDiscriminatedPointerAuth; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e1dba0195f470..7a9aa80a48148 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1081,6 +1081,7 @@ def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">; def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments", [VariadicMacroArgumentsOmitted]>; def MisleadingIndentation : DiagGroup<"misleading-indentation">; def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">; +def PtrAuthWeakGlobalSchema : DiagGroup<"ptrauth-weak-global-schema">; // This covers both the deprecated case (in C++98) // and the extension case (in C++11 onwards). diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 381d1fb063eba..c5326cf3cf717 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1018,6 +1018,9 @@ def err_ptrauth_string_not_literal : Error< def err_ptrauth_type_disc_undiscriminated : Error< "cannot pass undiscriminated type %0 to " "'__builtin_ptrauth_type_discriminator'">; +def warn_ptrauth_weak_global_function_pointer : + Warning<"global variable %0 uses the default pointer authentication schema">, + InGroup; def note_ptrauth_virtual_function_pointer_incomplete_arg_ret : Note<"cannot take an address of a virtual member function if its return or " diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f4aadeceb4bb7..e1e6f5015cf68 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1640,23 +1640,27 @@ ASTContext::findPointerAuthContent(QualType T) const { T = T.getCanonicalType(); if (T->isDependentType()) - return PointerAuthContent::None; + return PointerAuthContent::ContainsNone; + PointerAuthContent Result = PointerAuthContent::ContainsNone; if (T.hasAddressDiscriminatedPointerAuth()) - return PointerAuthContent::AddressDiscriminatedData; + Result = Result | PointerAuthContent::ContainsAddressDiscriminatedData; + if (T->isFunctionPointerType()) { + PointerAuthQualifier ExplicitQualifier = T.getPointerAuth(); + if (!ExplicitQualifier.isPresent() || !ExplicitQualifier.isAddressDiscriminated()) + Result = Result | PointerAuthContent::ContainsDefaultAuthenticatedFunction; + } const RecordDecl *RD = T->getAsRecordDecl(); if (!RD) - return PointerAuthContent::None; + return Result; if (RD->isInvalidDecl()) - return PointerAuthContent::None; + return PointerAuthContent::ContainsNone; if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD); Existing != RecordContainsAddressDiscriminatedPointerAuth.end()) return Existing->second; - PointerAuthContent Result = PointerAuthContent::None; - auto SaveResultAndReturn = [&]() -> PointerAuthContent { auto [ResultIter, DidAdd] = RecordContainsAddressDiscriminatedPointerAuth.try_emplace(RD, Result); @@ -1665,19 +1669,16 @@ ASTContext::findPointerAuthContent(QualType T) const { assert(DidAdd); return Result; }; - auto ShouldContinueAfterUpdate = [&](PointerAuthContent NewResult) { - static_assert(PointerAuthContent::None < - PointerAuthContent::AddressDiscriminatedVTable); - static_assert(PointerAuthContent::AddressDiscriminatedVTable < - PointerAuthContent::AddressDiscriminatedData); - if (NewResult > Result) - Result = NewResult; - return Result != PointerAuthContent::AddressDiscriminatedData; + auto ShouldContinueAfterUpdate = [&](PointerAuthContent NewFlag) { + Result = Result | NewFlag; + if ((NewFlag & PointerAuthContent::ContainsAddressDiscriminatedVTable) != PointerAuthContent::ContainsNone) + Result = Result | PointerAuthContent::ContainsAddressDiscriminatedData; + return Result != PointerAuthContent::ContainsAllFlags; }; if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (primaryBaseHaseAddressDiscriminatedVTableAuthentication(*this, CXXRD) && !ShouldContinueAfterUpdate( - PointerAuthContent::AddressDiscriminatedVTable)) + PointerAuthContent::ContainsAddressDiscriminatedVTable)) return SaveResultAndReturn(); for (auto Base : CXXRD->bases()) { if (!ShouldContinueAfterUpdate(findPointerAuthContent(Base.getType()))) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d32d7b960288d..dabcd1596252f 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -994,6 +994,10 @@ void Sema::getUndefinedButUsed( } } +static void checkQuestionableGlobalFunctionPointers(Sema &S) { + +} + /// checkUndefinedButUsed - Check for undefined objects with internal linkage /// or that are inline. static void checkUndefinedButUsed(Sema &S) { @@ -1624,6 +1628,7 @@ void Sema::ActOnEndOfTranslationUnit() { TUScope = nullptr; checkExposure(Context.getTranslationUnitDecl()); + checkQuestionableGlobalFunctionPointers(*this); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 47bd7295e93f6..051245630f854 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15053,6 +15053,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Build the bindings if this is a structured binding declaration. if (auto *DD = dyn_cast(var)) CheckCompleteDecompositionDeclaration(DD); + + if (GlobalStorage && Context.isPointerAuthenticationAvailable() && + !Diags.isIgnored(diag::warn_ptrauth_weak_global_function_pointer, var->getLocation())) { + if (Context.containsDefaultAuthenticatedFunctionPointer(var->getType())) { + Diag(var->getLocation(), diag::warn_ptrauth_weak_global_function_pointer) << var << var->getSourceRange(); + } + } } void Sema::CheckStaticLocalForDllExport(VarDecl *VD) { diff --git a/clang/test/SemaCXX/ptrauth-type-traits.cpp b/clang/test/SemaCXX/ptrauth-type-traits.cpp index a81ef1cce25b6..f4e33802e36f8 100644 --- a/clang/test/SemaCXX/ptrauth-type-traits.cpp +++ b/clang/test/SemaCXX/ptrauth-type-traits.cpp @@ -427,7 +427,15 @@ namespace GH159505 { static_assert(PTRAUTH_ENABLED != __is_trivially_copyable(Ptr)); } - auto f = test; + auto * __ptrauth(1,1,1) f = test; + void (*__ptrauth(1,0,0) f1)() = test; + void (*__ptrauth(1,1,0) f2)() = test; + void (*__ptrauth(1,1,1) f3)() = test; + + struct Foo { + void (*field)(); + }; + Foo object; static_assert(!__is_trivially_copyable(B<1>)); static_assert(PTRAUTH_ENABLED != __is_trivially_copyable(C<1>));