sberg updated this revision to Diff 127899.
sberg added a comment.
(need to call getAs<FunctionProtoType> instead of cast<FunctionProtoType> in
one place, in case the name in the function decl is wrapped in parens, as
happens in HarfBuzz's hb-buffer.cc)
https://reviews.llvm.org/D40720
Files:
clang/lib/CodeGen/CGExpr.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenTypes.cpp
clang/lib/CodeGen/CodeGenTypes.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/test/CodeGenCXX/ubsan-function-noexcept.cpp
compiler-rt/test/ubsan/TestCases/TypeCheck/Function/function.cpp
Index: compiler-rt/test/ubsan/TestCases/TypeCheck/Function/function.cpp
===================================================================
--- compiler-rt/test/ubsan/TestCases/TypeCheck/Function/function.cpp
+++ compiler-rt/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
+// RUN: %clangxx -std=c++17 -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
@@ -23,9 +23,49 @@
reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
}
+void f1(int) {}
+void f2(unsigned int) {}
+void f3(int) noexcept {}
+void f4(unsigned int) noexcept {}
+
+void check_noexcept_calls() {
+ void (*p1)(int);
+ p1 = &f1;
+ p1(0);
+ p1 = reinterpret_cast<void (*)(int)>(&f2);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ p1(0);
+ p1 = &f3;
+ p1(0);
+ p1 = reinterpret_cast<void (*)(int)>(&f4);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ p1(0);
+
+ void (*p2)(int) noexcept;
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f1);
+ // TODO: Unclear whether calling a non-noexcept function through a pointer to
+ // nexcept function should cause an error.
+ // CHECK-NOT: function.cpp:[[@LINE+2]]:3: runtime error: call to function f1(int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM-NOT: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f2);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+ p2 = &f3;
+ p2(0);
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f4);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+}
+
int main(void) {
make_valid_call();
make_invalid_call();
+ check_noexcept_calls();
// Check that no more errors will be printed.
// CHECK-NOT: runtime error: call to function
// NOSYM-NOT: runtime error: call to function
Index: clang/test/CodeGenCXX/ubsan-function-noexcept.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/ubsan-function-noexcept.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++17 -fsanitize=function -emit-llvm -triple x86_64-linux-gnu %s -o - | FileCheck %s
+
+// Check that typeinfo recorded in function prolog doesn't have "Do" noexcept
+// qualifier in its mangled name.
+// CHECK: @[[LABEL:[0-9]+]] = private constant i8* bitcast ({ i8*, i8* }* @_ZTIFvvE to i8*)
+// CHECK: define void @_Z1fv() #{{.*}} prologue <{ i32, i32 }> <{ i32 {{.*}}, i32 trunc (i64 sub (i64 ptrtoint (i8** @[[LABEL]] to i64), i64 ptrtoint (void ()* @_Z1fv to i64)) to i32) }>
+void f() noexcept {}
+
+// CHECK: define void @_Z1gPDoFvvE
+void g(void (*p)() noexcept) {
+ // Check that reference typeinfo at call site doesn't have "Do" noexcept
+ // qualifier in its mangled name, either.
+ // CHECK: icmp eq i8* %{{.*}}, bitcast ({ i8*, i8* }* @_ZTIFvvE to i8*), !nosanitize
+ p();
+}
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3415,7 +3415,7 @@
/// Compute the flags for a __pbase_type_info, and remove the corresponding
/// pieces from \p Type.
-static unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type) {
+static unsigned extractPBaseFlags(CodeGenTypes &CGT, QualType &Type) {
unsigned Flags = 0;
if (Type.isConstQualified())
@@ -3433,11 +3433,9 @@
Flags |= ItaniumRTTIBuilder::PTI_Incomplete;
if (auto *Proto = Type->getAs<FunctionProtoType>()) {
- if (Proto->isNothrow(Ctx)) {
+ if (Proto->isNothrow(CGT.getContext())) {
Flags |= ItaniumRTTIBuilder::PTI_Noexcept;
- Type = Ctx.getFunctionType(
- Proto->getReturnType(), Proto->getParamTypes(),
- Proto->getExtProtoInfo().withExceptionSpec(EST_None));
+ Type = CGT.removeNothrowQualification(Proto);
}
}
@@ -3450,7 +3448,7 @@
// Itanium C++ ABI 2.9.5p7:
// __flags is a flag word describing the cv-qualification and other
// attributes of the type pointed to
- unsigned Flags = extractPBaseFlags(CGM.getContext(), PointeeTy);
+ unsigned Flags = extractPBaseFlags(CGM.getTypes(), PointeeTy);
llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
@@ -3473,7 +3471,7 @@
// Itanium C++ ABI 2.9.5p7:
// __flags is a flag word describing the cv-qualification and other
// attributes of the type pointed to.
- unsigned Flags = extractPBaseFlags(CGM.getContext(), PointeeTy);
+ unsigned Flags = extractPBaseFlags(CGM.getTypes(), PointeeTy);
const RecordType *ClassType = cast<RecordType>(Ty->getClass());
if (IsIncompleteClassType(ClassType))
Index: clang/lib/CodeGen/CodeGenTypes.h
===================================================================
--- clang/lib/CodeGen/CodeGenTypes.h
+++ clang/lib/CodeGen/CodeGenTypes.h
@@ -372,7 +372,10 @@
bool isRecordBeingLaidOut(const Type *Ty) const {
return RecordsBeingLaidOut.count(Ty);
}
-
+
+ /// Return the \arg Proto function type with any (C++17) exception
+ /// specification removed.
+ QualType removeNothrowQualification(const FunctionProtoType *Proto) const;
};
} // end namespace CodeGen
Index: clang/lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenTypes.cpp
+++ clang/lib/CodeGen/CodeGenTypes.cpp
@@ -782,3 +782,9 @@
bool CodeGenTypes::isZeroInitializable(const RecordDecl *RD) {
return getCGRecordLayout(RD).isZeroInitializable();
}
+
+QualType CodeGenTypes::removeNothrowQualification(const FunctionProtoType *Proto) const {
+ return Context.getFunctionType(
+ Proto->getReturnType(), Proto->getParamTypes(),
+ Proto->getExtProtoInfo().withExceptionSpec(EST_None));
+}
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -921,8 +921,12 @@
if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function)) {
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (llvm::Constant *PrologueSig = getPrologueSignature(CGM, FD)) {
+ // Remove any (C++17) exception specifications, to allow calling e.g. a
+ // noexcept function through a non-noexcept pointer.
+ auto ProtoTy =
+ getTypes().removeNothrowQualification(FD->getType()->getAs<FunctionProtoType>());
llvm::Constant *FTRTTIConst =
- CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true);
+ CGM.GetAddrOfRTTIDescriptor(ProtoTy, /*ForEH=*/true);
llvm::Constant *FTRTTIConstEncoded =
EncodeAddrForUseInPrologue(Fn, FTRTTIConst);
llvm::Constant *PrologueStructElems[] = {PrologueSig,
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -4473,8 +4473,12 @@
if (llvm::Constant *PrefixSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
SanitizerScope SanScope(this);
+ // Remove any (C++17) exception specifications, to allow calling e.g. a
+ // noexcept function through a non-noexcept pointer.
+ auto ProtoTy =
+ getTypes().removeNothrowQualification(cast<FunctionProtoType>(FnType));
llvm::Constant *FTRTTIConst =
- CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true);
+ CGM.GetAddrOfRTTIDescriptor(ProtoTy, /*ForEH=*/true);
llvm::Type *PrefixStructTyElems[] = {PrefixSig->getType(), Int32Ty};
llvm::StructType *PrefixStructTy = llvm::StructType::get(
CGM.getLLVMContext(), PrefixStructTyElems, /*isPacked=*/true);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits