Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1403,6 +1403,13 @@ let Documentation = [NoSanitizeMemoryDocs]; } +// Attribute to disable UBSan vptr checks. +def NoSanitizeVptr : InheritableAttr { + let Spellings = [GNU<"no_sanitize_vptr">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSanitizeVptrDocs]; +} + // C/C++ Thread safety attributes (e.g. for deadlock, data race checking) def GuardedVar : InheritableAttr { Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -958,6 +958,15 @@ }]; } +def NoSanitizeVptrDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((no_sanitize_vptr))`` on a function declaration to +specify that dynamic vptr checks (e.g. checks for bad downcasting) should not +be inserted. + }]; +} + def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> { let Content = [{ Clang supports additional attributes to enable checking type safety properties Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -580,7 +580,8 @@ (TCK == TCK_MemberAccess || TCK == TCK_MemberCall || TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference || TCK == TCK_UpcastToVirtualBase) && - RD && RD->hasDefinition() && RD->isDynamicClass()) { + RD && RD->hasDefinition() && RD->isDynamicClass() && + !CurFuncDecl->hasAttr()) { // Compute a hash of the mangled name of the type. // // FIXME: This is not guaranteed to be deterministic! Move to a Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4772,6 +4772,9 @@ case AttributeList::AT_NoSanitizeMemory: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_NoSanitizeVptr: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_GuardedBy: handleGuardedByAttr(S, D, Attr); break; Index: test/CodeGen/no-sanitize-vptr.cpp =================================================================== --- /dev/null +++ test/CodeGen/no-sanitize-vptr.cpp @@ -0,0 +1,23 @@ +// Verify ubsan doesn't emit checks for functions with the no_sanitize_vptr attribute. +// RUN: %clang_cc1 -fsanitize=vptr -emit-llvm %s -o - | FileCheck %s + +class Bar { +public: + virtual ~Bar() {} +}; +class Foo : public Bar {}; + +Bar bar; + +Foo *testfunc1(Bar *bar) { + // CHECK: testfunc1 + // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss + return static_cast(bar); // down-casting + // CHECK: ret +} +__attribute__((no_sanitize_vptr)) Foo *testfunc2(Bar *bar) { + // CHECK: testfunc2 + // CHECK-NOT: call void @__ubsan_handle_dynamic_type_cache_miss + return static_cast(bar); // down-casting + // CHECK: ret +} Index: test/SemaCXX/attr-no-sanitize-vptr.cpp =================================================================== --- /dev/null +++ test/SemaCXX/attr-no-sanitize-vptr.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#define NO_SANITIZE_VPTR __attribute__((no_sanitize_vptr)) + +#if !__has_attribute(no_sanitize_vptr) +#error "Should support no_sanitize_vptr" +#endif + +void noanal_fun() NO_SANITIZE_VPTR; + +void noanal_fun_args() __attribute__((no_sanitize_vptr(1))); // \ + // expected-error {{'no_sanitize_vptr' attribute takes no arguments}} + +int noanal_testfn(int y) NO_SANITIZE_VPTR; + +int noanal_testfn(int y) { + int x NO_SANITIZE_VPTR = y; // \ + // expected-error {{'no_sanitize_vptr' attribute only applies to functions}} + return x; +} + +int noanal_test_var NO_SANITIZE_VPTR; // \ + // expected-error {{'no_sanitize_vptr' attribute only applies to functions}} + +class NoanalFoo { + private: + int test_field NO_SANITIZE_VPTR; // \ + // expected-error {{'no_sanitize_vptr' attribute only applies to functions}} + void test_method() NO_SANITIZE_VPTR; +}; + +class NO_SANITIZE_VPTR NoanalTestClass { // \ + // expected-error {{'no_sanitize_vptr' attribute only applies to functions}} +}; + +void noanal_fun_params(int lvar NO_SANITIZE_VPTR); // \ + // expected-error {{'no_sanitize_vptr' attribute only applies to functions}}