Unify clang/llvm attributes for asan/tsan/msan (Clang part)

These are two related changes (one in llvm, one in clang).
LLVM: 
- rename address_safety => sanitize_address (the enum value is the same, so we preserve binary compatibility with old bitcode)
- rename thread_safety => sanitize_thread
- rename no_uninitialized_checks -> sanitize_memory

CLANG: 
- add __attribute__((no_sanitize_address)) as a synonym for __attribute__((no_address_safety_analysis))
- add __attribute__((no_sanitize_thread))
- add __attribute__((no_sanitize_memory))

for S in address thread memory
If -fsanitize=S is present and __attribute__((no_sanitize_S)) is not
set llvm attribute sanitize_S

llvm-svn: 176076
This commit is contained in:
Kostya Serebryany 2013-02-26 06:58:27 +00:00
parent cf880b9443
commit 4c0fc9931e
14 changed files with 320 additions and 33 deletions

View File

@ -105,12 +105,13 @@ this purpose.
# endif
#endif
``__attribute__((no_address_safety_analysis))``
``__attribute__((no_sanitize_address))``
-----------------------------------------------
Some code should not be instrumented by AddressSanitizer. One may use the
function attribute
:ref:`no_address_safety_analysis <langext-address_sanitizer>`
:ref:`no_sanitize_address <langext-address_sanitizer>`
(or a deprecated synonym `no_address_safety_analysis`)
to disable instrumentation of a particular function. This attribute may not be
supported by other compilers, so we suggest to use it together with
``__has_feature(address_sanitizer)``. Note: currently, this attribute will be

View File

@ -1616,10 +1616,38 @@ AddressSanitizer
Use ``__has_feature(address_sanitizer)`` to check if the code is being built
with :doc:`AddressSanitizer`.
Use ``__attribute__((no_address_safety_analysis))`` on a function declaration
Use ``__attribute__((no_sanitize_address))``
on a function declaration
to specify that address safety instrumentation (e.g. AddressSanitizer) should
not be applied to that function.
.. _langext-thread_sanitizer:
ThreadSanitizer
----------------
Use ``__has_feature(thread_sanitizer)`` to check if the code is being built
with :doc:`ThreadSanitizer`.
Use ``__attribute__((no_sanitize_thread))`` on a function declaration
to specify that checks for data races on plain (non-atomic) memory accesses
should not be inserted by ThreadSanitizer.
The function may still be instrumented by the tool
to avoid false positives in other places.
.. _langext-memory_sanitizer:
MemorySanitizer
----------------
Use ``__has_feature(memory_sanitizer)`` to check if the code is being built
with :doc:`MemorySanitizer`.
Use ``__attribute__((no_sanitize_memory))`` on a function declaration
to specify that checks for uninitialized memory should not be inserted
(e.g. by MemorySanitizer). The function may still be instrumented by the tool
to avoid false positives in other places.
Thread-Safety Annotation Checking
=================================

View File

@ -80,6 +80,19 @@ whether MemorySanitizer is enabled. :ref:`\_\_has\_feature
# endif
#endif
``__attribute__((no_sanitize_memory))``
-----------------------------------------------
Some code should not be checked by MemorySanitizer.
One may use the function attribute
:ref:`no_sanitize_memory <langext-memory_sanitizer>`
to disable uninitialized checks in a particular function.
MemorySanitizer may still instrument such functions to avoid false positives.
This attribute may not be
supported by other compilers, so we suggest to use it together with
``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be
lost if the function is inlined.
Origin Tracking
===============

View File

@ -78,10 +78,25 @@ this purpose.
.. code-block:: c
#if defined(__has_feature) && __has_feature(thread_sanitizer)
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
// code that builds only under ThreadSanitizer
# endif
#endif
``__attribute__((no_sanitize_thread))``
-----------------------------------------------
Some code should not be instrumented by ThreadSanitizer.
One may use the function attribute
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
ThreadSanitizer may still instrument such functions to avoid false positives.
This attribute may not be
supported by other compilers, so we suggest to use it together with
``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be
lost if the function is inlined.
Limitations
-----------

View File

@ -767,9 +767,20 @@ def X86ForceAlignArgPointer : InheritableAttr {
let Spellings = [];
}
// AddressSafety attribute (e.g. for AddressSanitizer)
def NoAddressSafetyAnalysis : InheritableAttr {
let Spellings = [GNU<"no_address_safety_analysis">];
// Attribute to disable AddressSanitizer (or equivalent) checks.
def NoSanitizeAddress : InheritableAttr {
let Spellings = [GNU<"no_address_safety_analysis">,
GNU<"no_sanitize_address">];
}
// Attribute to disable ThreadSanitizer checks.
def NoSanitizeThread : InheritableAttr {
let Spellings = [GNU<"no_sanitize_thread">];
}
// Attribute to disable MemorySanitizer checks.
def NoSanitizeMemory : InheritableAttr {
let Spellings = [GNU<"no_sanitize_memory">];
}
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)

View File

@ -233,7 +233,11 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
Fn->setDoesNotThrow();
if (CGM.getSanOpts().Address)
Fn->addFnAttr(llvm::Attribute::AddressSafety);
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (CGM.getSanOpts().Thread)
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
if (CGM.getSanOpts().Memory)
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
return Fn;
}

View File

@ -617,12 +617,16 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
if (SanOpts.Address) {
// When AddressSanitizer is enabled, set AddressSafety attribute
// unless __attribute__((no_address_safety_analysis)) is used.
if (!D->hasAttr<NoAddressSafetyAnalysisAttr>())
F->addFnAttr(llvm::Attribute::AddressSafety);
}
// When AddressSanitizer is enabled, set SanitizeAddress attribute
// unless __attribute__((no_sanitize_address)) is used.
if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
F->addFnAttr(llvm::Attribute::SanitizeAddress);
// Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>())
F->addFnAttr(llvm::Attribute::SanitizeThread);
// Same for MemorySanitizer and __attribute__((no_sanitize_memory))
if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
F->addFnAttr(llvm::Attribute::SanitizeMemory);
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)

View File

@ -610,8 +610,8 @@ static void handleScopedLockableAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
@ -627,7 +627,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
S.Context));
}
static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
@ -635,14 +635,48 @@ static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
D->addAttr(::new (S.Context)
NoAddressSafetyAnalysisAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
NoSanitizeAddressAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleNoSanitizeMemory(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
D->addAttr(::new (S.Context) NoSanitizeMemoryAttr(Attr.getRange(),
S.Context));
}
static void handleNoSanitizeThread(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
D->addAttr(::new (S.Context) NoSanitizeThreadAttr(Attr.getRange(),
S.Context));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
@ -4817,11 +4851,17 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ScopedLockable:
handleScopedLockableAttr(S, D, Attr);
break;
case AttributeList::AT_NoAddressSafetyAnalysis:
handleNoAddressSafetyAttr(S, D, Attr);
case AttributeList::AT_NoSanitizeAddress:
handleNoSanitizeAddressAttr(S, D, Attr);
break;
case AttributeList::AT_NoThreadSafetyAnalysis:
handleNoThreadSafetyAttr(S, D, Attr);
handleNoThreadSafetyAnalysis(S, D, Attr);
break;
case AttributeList::AT_NoSanitizeThread:
handleNoSanitizeThread(S, D, Attr);
break;
case AttributeList::AT_NoSanitizeMemory:
handleNoSanitizeMemory(S, D, Attr);
break;
case AttributeList::AT_Lockable:
handleLockableAttr(S, D, Attr);

View File

@ -6,20 +6,20 @@
// FIXME: %t is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
// REQUIRES: shell
// The address_safety attribute should be attached to functions
// when AddressSanitizer is enabled, unless no_address_safety_analysis attribute
// The sanitize_address attribute should be attached to functions
// when AddressSanitizer is enabled, unless no_sanitize_address attribute
// is present.
// WITHOUT: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
// BL: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
// ASAN: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
__attribute__((no_address_safety_analysis))
__attribute__((no_sanitize_address))
int NoAddressSafety1(int *a) { return *a; }
// WITHOUT: NoAddressSafety2{{.*}}) #[[NOATTR]]
// BL: NoAddressSafety2{{.*}}) #[[NOATTR]]
// ASAN: NoAddressSafety2{{.*}}) #[[NOATTR]]
__attribute__((no_address_safety_analysis))
__attribute__((no_sanitize_address))
int NoAddressSafety2(int *a);
int NoAddressSafety2(int *a) { return *a; }
@ -38,13 +38,13 @@ int TemplateAddressSafetyOk() { return i; }
// BL: TemplateNoAddressSafety{{.*}}) #[[NOATTR]]
// ASAN: TemplateNoAddressSafety{{.*}}) #[[NOATTR]]
template<int i>
__attribute__((no_address_safety_analysis))
__attribute__((no_sanitize_address))
int TemplateNoAddressSafety() { return i; }
int force_instance = TemplateAddressSafetyOk<42>()
+ TemplateNoAddressSafety<42>();
// Check that __cxx_global_var_init* get the address_safety attribute.
// Check that __cxx_global_var_init* get the sanitize_address attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
// WITHOUT: @__cxx_global_var_init{{.*}}#[[GVI:[0-9]+]]
@ -57,5 +57,5 @@ int global2 = *(int*)((char*)&global1+1);
// BL: attributes #[[GVI]] = { nounwind{{.*}} }
// ASAN: attributes #[[NOATTR]] = { nounwind{{.*}} }
// ASAN: attributes #[[WITH]] = { address_safety nounwind{{.*}} }
// ASAN: attributes #[[GVI]] = { address_safety nounwind{{.*}} }
// ASAN: attributes #[[WITH]] = {{.*}}sanitize_address
// ASAN: attributes #[[GVI]] = {{.*}}sanitize_address

View File

@ -0,0 +1,60 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefix=TSAN %s
// RUN: echo "src:%s" > %t
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s
// REQUIRES: shell
// The sanitize_thread attribute should be attached to functions
// when ThreadSanitizer is enabled, unless no_sanitize_thread attribute
// is present.
// WITHOUT: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
// BL: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
// TSAN: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
__attribute__((no_sanitize_thread))
int NoTSAN1(int *a) { return *a; }
// WITHOUT: NoTSAN2{{.*}}) #[[NOATTR]]
// BL: NoTSAN2{{.*}}) #[[NOATTR]]
// TSAN: NoTSAN2{{.*}}) #[[NOATTR]]
__attribute__((no_sanitize_thread))
int NoTSAN2(int *a);
int NoTSAN2(int *a) { return *a; }
// WITHOUT: TSANOk{{.*}}) #[[NOATTR]]
// BL: TSANOk{{.*}}) #[[NOATTR]]
// TSAN: TSANOk{{.*}}) #[[WITH:[0-9]+]]
int TSANOk(int *a) { return *a; }
// WITHOUT: TemplateTSANOk{{.*}}) #[[NOATTR]]
// BL: TemplateTSANOk{{.*}}) #[[NOATTR]]
// TSAN: TemplateTSANOk{{.*}}) #[[WITH]]
template<int i>
int TemplateTSANOk() { return i; }
// WITHOUT: TemplateNoTSAN{{.*}}) #[[NOATTR]]
// BL: TemplateNoTSAN{{.*}}) #[[NOATTR]]
// TSAN: TemplateNoTSAN{{.*}}) #[[NOATTR]]
template<int i>
__attribute__((no_sanitize_thread))
int TemplateNoTSAN() { return i; }
int force_instance = TemplateTSANOk<42>()
+ TemplateNoTSAN<42>();
// Check that __cxx_global_var_init* get the sanitize_thread attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
// WITHOUT: @__cxx_global_var_init{{.*}}#[[GVI:[0-9]+]]
// BL: @__cxx_global_var_init{{.*}}#[[GVI:[0-9]+]]
// TSAN: @__cxx_global_var_init{{.*}}#[[GVI:[0-9]+]]
// WITHOUT: attributes #[[NOATTR]] = { nounwind{{.*}} }
// WITHOUT: attributes #[[GVI]] = { nounwind{{.*}} }
// BL: attributes #[[NOATTR]] = { nounwind{{.*}} }
// BL: attributes #[[GVI]] = { nounwind{{.*}} }
// TSAN: attributes #[[NOATTR]] = { nounwind{{.*}} }
// TSAN: attributes #[[WITH]] = { nounwind{{.*}} sanitize_thread
// TSAN: attributes #[[GVI]] = { nounwind{{.*}} sanitize_thread

View File

@ -17,5 +17,5 @@
@end
// WITHOUT: attributes #0 = { nounwind{{.*}} }
// ASAN: attributes #0 = { address_safety nounwind{{.*}} }
// ASAN: attributes #0 = {{.*}}sanitize_address
// WITHOUT-NOT: attributes #0 = {{.*}}sanitize_address

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#if !__has_attribute(no_sanitize_address)
#error "Should support no_sanitize_address"
#endif
void noanal_fun() NO_SANITIZE_ADDRESS;
void noanal_fun_args() __attribute__((no_sanitize_address(1))); // \
// expected-error {{attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_ADDRESS;
int noanal_testfn(int y) {
int x NO_SANITIZE_ADDRESS = y; // \
// expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
return x;
}
int noanal_test_var NO_SANITIZE_ADDRESS; // \
// expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
class NoanalFoo {
private:
int test_field NO_SANITIZE_ADDRESS; // \
// expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
void test_method() NO_SANITIZE_ADDRESS;
};
class NO_SANITIZE_ADDRESS NoanalTestClass { // \
// expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
};
void noanal_fun_params(int lvar NO_SANITIZE_ADDRESS); // \
// expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#if !__has_attribute(no_sanitize_memory)
#error "Should support no_sanitize_memory"
#endif
void noanal_fun() NO_SANITIZE_MEMORY;
void noanal_fun_args() __attribute__((no_sanitize_memory(1))); // \
// expected-error {{attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_MEMORY;
int noanal_testfn(int y) {
int x NO_SANITIZE_MEMORY = y; // \
// expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
return x;
}
int noanal_test_var NO_SANITIZE_MEMORY; // \
// expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
class NoanalFoo {
private:
int test_field NO_SANITIZE_MEMORY; // \
// expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
void test_method() NO_SANITIZE_MEMORY;
};
class NO_SANITIZE_MEMORY NoanalTestClass { // \
// expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
};
void noanal_fun_params(int lvar NO_SANITIZE_MEMORY); // \
// expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#if !__has_attribute(no_sanitize_thread)
#error "Should support no_sanitize_thread"
#endif
void noanal_fun() NO_SANITIZE_THREAD;
void noanal_fun_args() __attribute__((no_sanitize_thread(1))); // \
// expected-error {{attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_THREAD;
int noanal_testfn(int y) {
int x NO_SANITIZE_THREAD = y; // \
// expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
return x;
}
int noanal_test_var NO_SANITIZE_THREAD; // \
// expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
class NoanalFoo {
private:
int test_field NO_SANITIZE_THREAD; // \
// expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
void test_method() NO_SANITIZE_THREAD;
};
class NO_SANITIZE_THREAD NoanalTestClass { // \
// expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
};
void noanal_fun_params(int lvar NO_SANITIZE_THREAD); // \
// expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}