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,14 @@ }]; } +def NoSanitizeVptrDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((no_sanitize_vptr))`` on a function declaration to +specify that dynamic vptr checks for 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 @@ -593,7 +593,8 @@ // Blacklist based on the mangled type. if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType( - Out.str())) { + Out.str()) && + !CurFuncDecl->hasAttr()) { llvm::hash_code TypeHash = hash_value(Out.str()); // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). 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-vtpr.cpp =================================================================== --- /dev/null +++ test/CodeGen/no-sanitize-vtpr.cpp @@ -0,0 +1,26 @@ +// 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 + +// REQUIRES: shell + +class Bar { +public: + virtual ~Bar() {} +}; +class Foo : public Bar {}; + +Bar bar; + +__attribute__((no_sanitize_vptr)) void testfunc() { + // CHECK: testfunc + // CHECK-NOT: call void @__ubsan_handle_dynamic_type_cache_miss + Foo* foo = static_cast(&bar); // down-casting + // CHECK: ret void +} + +void testfunc2() { + // CHECK: testfunc2 + // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss + Foo* foo = static_cast(&bar); // down-casting + // CHECK: ret void +} 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}}