forked from OSchip/llvm-project
Implement no_sanitize attribute.
Differential Revision: http://reviews.llvm.org/D9631 llvm-svn: 237463
This commit is contained in:
parent
25e2500ac8
commit
915df9968b
|
@ -930,6 +930,8 @@ number of cases where the compilation environment is tightly controlled
|
|||
and the precompiled header cannot be generated after headers have been
|
||||
installed.
|
||||
|
||||
.. _controlling-code-generation:
|
||||
|
||||
Controlling Code Generation
|
||||
---------------------------
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Sanitizers.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
|
|
@ -144,6 +144,7 @@ class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
|
|||
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
|
||||
class VariadicExprArgument<string name> : Argument<name, 1>;
|
||||
class VariadicStringArgument<string name> : Argument<name, 1>;
|
||||
|
||||
// A version of the form major.minor[.subminor].
|
||||
class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
|
@ -1386,26 +1387,35 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
|
|||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
// Attribute to disable AddressSanitizer (or equivalent) checks.
|
||||
def NoSanitizeAddress : InheritableAttr {
|
||||
def NoSanitize : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">];
|
||||
let Args = [VariadicStringArgument<"Sanitizers">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeDocs];
|
||||
let AdditionalMembers = [{
|
||||
SanitizerMask getMask() const {
|
||||
SanitizerMask Mask = 0;
|
||||
for (auto SanitizerName : sanitizers()) {
|
||||
SanitizerMask ParsedMask =
|
||||
parseSanitizerValue(SanitizerName, /*AllowGroups=*/true);
|
||||
Mask |= expandSanitizerGroups(ParsedMask);
|
||||
}
|
||||
return Mask;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// Attributes to disable a specific sanitizer. No new sanitizers should be added
|
||||
// to this list; the no_sanitize attribute should be extended instead.
|
||||
def NoSanitizeSpecific : InheritableAttr {
|
||||
let Spellings = [GCC<"no_address_safety_analysis">,
|
||||
GCC<"no_sanitize_address">];
|
||||
GCC<"no_sanitize_address">,
|
||||
GCC<"no_sanitize_thread">,
|
||||
GNU<"no_sanitize_memory">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeAddressDocs];
|
||||
}
|
||||
|
||||
// Attribute to disable ThreadSanitizer checks.
|
||||
def NoSanitizeThread : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize_thread">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeThreadDocs];
|
||||
}
|
||||
|
||||
// Attribute to disable MemorySanitizer checks.
|
||||
def NoSanitizeMemory : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize_memory">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeMemoryDocs];
|
||||
let Documentation = [NoSanitizeAddressDocs, NoSanitizeThreadDocs,
|
||||
NoSanitizeMemoryDocs];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
|
||||
|
|
|
@ -920,6 +920,22 @@ This attribute accepts a single parameter that must be one of the following:
|
|||
}];
|
||||
}
|
||||
|
||||
def NoSanitizeDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Use the ``no_sanitize`` attribute on a function declaration to specify
|
||||
that a particular instrumentation or set of instrumentations should not be
|
||||
applied to that function. The attribute takes a list of string literals,
|
||||
which have the same meaning as values accepted by the ``-fno-sanitize=``
|
||||
flag. For example, ``__attribute__((no_sanitize("address", "thread")))``
|
||||
specifies that AddressSanitizer and ThreadSanitizer should not be applied
|
||||
to the function.
|
||||
|
||||
See :ref:`Controlling Code Generation <controlling-code-generation>` for a
|
||||
full list of supported sanitizer flags.
|
||||
}];
|
||||
}
|
||||
|
||||
def NoSanitizeAddressDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
// This function has multiple distinct spellings, and so it requires a custom
|
||||
|
@ -936,6 +952,7 @@ not be applied to that function.
|
|||
|
||||
def NoSanitizeThreadDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "no_sanitize_thread";
|
||||
let Content = [{
|
||||
.. _langext-thread_sanitizer:
|
||||
|
||||
|
@ -948,6 +965,7 @@ tool to avoid false positives and provide meaningful stack traces.
|
|||
|
||||
def NoSanitizeMemoryDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "no_sanitize_memory";
|
||||
let Content = [{
|
||||
.. _langext-memory_sanitizer:
|
||||
|
||||
|
|
|
@ -401,6 +401,7 @@ def UnknownAttributes : DiagGroup<"unknown-attributes">;
|
|||
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
|
||||
def Attributes : DiagGroup<"attributes", [UnknownAttributes,
|
||||
IgnoredAttributes]>;
|
||||
def UnknownSanitizers : DiagGroup<"unknown-sanitizers">;
|
||||
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
|
||||
[CXX98CompatUnnamedTypeTemplateArgs]>;
|
||||
def UnsupportedFriend : DiagGroup<"unsupported-friend">;
|
||||
|
|
|
@ -2519,6 +2519,10 @@ def warn_param_typestate_mismatch : Warning<
|
|||
"argument not in expected state; expected '%0', observed '%1'">,
|
||||
InGroup<Consumed>, DefaultIgnore;
|
||||
|
||||
// no_sanitize attribute
|
||||
def warn_unknown_sanitizer_ignored : Warning<
|
||||
"unknown sanitizer '%0' ignored">, InGroup<UnknownSanitizers>;
|
||||
|
||||
def warn_impcast_vector_scalar : Warning<
|
||||
"implicit conversion turns vector to scalar: %0 to %1">,
|
||||
InGroup<Conversion>, DefaultIgnore;
|
||||
|
|
|
@ -608,6 +608,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
|
|||
if (CGM.isInSanitizerBlacklist(Fn, Loc))
|
||||
SanOpts.clear();
|
||||
|
||||
if (D) {
|
||||
// Apply the no_sanitize* attributes to SanOpts.
|
||||
for (auto Attr : D->specific_attrs<NoSanitizeAttr>())
|
||||
SanOpts.Mask &= ~Attr->getMask();
|
||||
}
|
||||
|
||||
// Apply sanitizer attributes to the function.
|
||||
if (SanOpts.has(SanitizerKind::Address))
|
||||
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
|
||||
if (SanOpts.has(SanitizerKind::Thread))
|
||||
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
|
||||
if (SanOpts.has(SanitizerKind::Memory))
|
||||
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
|
||||
|
||||
// Pass inline keyword to optimizer if it appears explicitly on any
|
||||
// declaration. Also, in the case of -fno-inline attach NoInline
|
||||
// attribute to all function that are not marked AlwaysInline.
|
||||
|
|
|
@ -752,23 +752,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
|
|||
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
|
||||
B.addAttribute(llvm::Attribute::StackProtectReq);
|
||||
|
||||
// Add sanitizer attributes if function is not blacklisted.
|
||||
if (!isInSanitizerBlacklist(F, D->getLocation())) {
|
||||
// When AddressSanitizer is enabled, set SanitizeAddress attribute
|
||||
// unless __attribute__((no_sanitize_address)) is used.
|
||||
if (LangOpts.Sanitize.has(SanitizerKind::Address) &&
|
||||
!D->hasAttr<NoSanitizeAddressAttr>())
|
||||
B.addAttribute(llvm::Attribute::SanitizeAddress);
|
||||
// Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
|
||||
if (LangOpts.Sanitize.has(SanitizerKind::Thread) &&
|
||||
!D->hasAttr<NoSanitizeThreadAttr>())
|
||||
B.addAttribute(llvm::Attribute::SanitizeThread);
|
||||
// Same for MemorySanitizer and __attribute__((no_sanitize_memory))
|
||||
if (LangOpts.Sanitize.has(SanitizerKind::Memory) &&
|
||||
!D->hasAttr<NoSanitizeMemoryAttr>())
|
||||
B.addAttribute(llvm::Attribute::SanitizeMemory);
|
||||
}
|
||||
|
||||
F->addAttributes(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::AttributeSet::get(
|
||||
F->getContext(), llvm::AttributeSet::FunctionIndex, B));
|
||||
|
|
|
@ -4354,6 +4354,45 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
|
||||
}
|
||||
|
||||
static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
|
||||
return;
|
||||
|
||||
std::vector<std::string> Sanitizers;
|
||||
|
||||
for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
|
||||
StringRef SanitizerName;
|
||||
SourceLocation LiteralLoc;
|
||||
|
||||
if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc))
|
||||
return;
|
||||
|
||||
if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0)
|
||||
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
|
||||
|
||||
Sanitizers.push_back(SanitizerName);
|
||||
}
|
||||
|
||||
D->addAttr(::new (S.Context) NoSanitizeAttr(
|
||||
Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(),
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
|
||||
const AttributeList &Attr) {
|
||||
std::string SanitizerName =
|
||||
llvm::StringSwitch<const char *>(Attr.getName()->getName())
|
||||
.Case("no_address_safety_analysis", "address")
|
||||
.Case("no_sanitize_address", "address")
|
||||
.Case("no_sanitize_thread", "thread")
|
||||
.Case("no_sanitize_memory", "memory")
|
||||
.Default("");
|
||||
assert(!SanitizerName.empty());
|
||||
D->addAttr(::new (S.Context)
|
||||
NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
/// Handles semantic checking for features that are common to all attributes,
|
||||
/// such as checking whether a parameter was properly specified, or the correct
|
||||
/// number of arguments were passed, etc.
|
||||
|
@ -4822,18 +4861,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case AttributeList::AT_ScopedLockable:
|
||||
handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_NoSanitizeAddress:
|
||||
handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr);
|
||||
case AttributeList::AT_NoSanitize:
|
||||
handleNoSanitizeAttr(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_NoSanitizeSpecific:
|
||||
handleNoSanitizeSpecificAttr(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_NoThreadSafetyAnalysis:
|
||||
handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_NoSanitizeThread:
|
||||
handleSimpleAttribute<NoSanitizeThreadAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_NoSanitizeMemory:
|
||||
handleSimpleAttribute<NoSanitizeMemoryAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_GuardedBy:
|
||||
handleGuardedByAttr(S, D, Attr);
|
||||
break;
|
||||
|
|
|
@ -3,14 +3,14 @@ int DefinedInDifferentFile(int *a);
|
|||
// RUN: echo "struct S { S(){} ~S(){} };" >> %t.extra-source.cpp
|
||||
// RUN: echo "S glob_array[5];" >> %t.extra-source.cpp
|
||||
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
|
||||
|
||||
// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
|
||||
|
||||
// RUN: echo "src:%s" > %t.file.blacklist
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
|
||||
|
||||
// FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
|
||||
// REQUIRES: shell
|
||||
|
@ -52,6 +52,36 @@ __attribute__((no_sanitize_address))
|
|||
int NoAddressSafety2(int *a);
|
||||
int NoAddressSafety2(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: NoAddressSafety3{{.*}}) [[NOATTR]]
|
||||
// BLFILE: NoAddressSafety3{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: NoAddressSafety3{{.*}}) [[NOATTR]]
|
||||
// ASAN: NoAddressSafety3{{.*}}) [[NOATTR]]
|
||||
[[gnu::no_sanitize_address]]
|
||||
int NoAddressSafety3(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: NoAddressSafety4{{.*}}) [[NOATTR]]
|
||||
// BLFILE: NoAddressSafety4{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: NoAddressSafety4{{.*}}) [[NOATTR]]
|
||||
// ASAN: NoAddressSafety4{{.*}}) [[NOATTR]]
|
||||
[[gnu::no_sanitize_address]]
|
||||
int NoAddressSafety4(int *a);
|
||||
int NoAddressSafety4(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: NoAddressSafety5{{.*}}) [[NOATTR]]
|
||||
// BLFILE: NoAddressSafety5{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: NoAddressSafety5{{.*}}) [[NOATTR]]
|
||||
// ASAN: NoAddressSafety5{{.*}}) [[NOATTR]]
|
||||
__attribute__((no_sanitize("address")))
|
||||
int NoAddressSafety5(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: NoAddressSafety6{{.*}}) [[NOATTR]]
|
||||
// BLFILE: NoAddressSafety6{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: NoAddressSafety6{{.*}}) [[NOATTR]]
|
||||
// ASAN: NoAddressSafety6{{.*}}) [[NOATTR]]
|
||||
__attribute__((no_sanitize("address")))
|
||||
int NoAddressSafety6(int *a);
|
||||
int NoAddressSafety6(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
|
||||
// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: AddressSafetyOk{{.*}}) [[WITH]]
|
||||
|
@ -86,16 +116,25 @@ int GENERATE_NAME(Function)(int *a) { return *a; }
|
|||
template<int i>
|
||||
int TemplateAddressSafetyOk() { return i; }
|
||||
|
||||
// WITHOUT: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
|
||||
// BLFILE: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
|
||||
// ASAN: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
|
||||
// WITHOUT: TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
|
||||
// BLFILE: TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
|
||||
// ASAN: TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
|
||||
template<int i>
|
||||
__attribute__((no_sanitize_address))
|
||||
int TemplateNoAddressSafety() { return i; }
|
||||
int TemplateNoAddressSafety1() { return i; }
|
||||
|
||||
// WITHOUT: TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
|
||||
// BLFILE: TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
|
||||
// BLFUNC: TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
|
||||
// ASAN: TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
|
||||
template<int i>
|
||||
__attribute__((no_sanitize("address")))
|
||||
int TemplateNoAddressSafety2() { return i; }
|
||||
|
||||
int force_instance = TemplateAddressSafetyOk<42>()
|
||||
+ TemplateNoAddressSafety<42>();
|
||||
+ TemplateNoAddressSafety1<42>()
|
||||
+ TemplateNoAddressSafety2<42>();
|
||||
|
||||
// Check that __cxx_global_var_init* get the sanitize_address attribute.
|
||||
int global1 = 0;
|
||||
|
|
|
@ -22,6 +22,12 @@ __attribute__((no_sanitize_thread))
|
|||
int NoTSAN2(int *a);
|
||||
int NoTSAN2(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
|
||||
// BL: NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
|
||||
// TSAN: NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
|
||||
__attribute__((no_sanitize("thread")))
|
||||
int NoTSAN3(int *a) { return *a; }
|
||||
|
||||
// WITHOUT: TSANOk{{.*}}) [[NOATTR]]
|
||||
// BL: TSANOk{{.*}}) [[NOATTR]]
|
||||
// TSAN: TSANOk{{.*}}) [[WITH:#[0-9]+]]
|
||||
|
|
|
@ -47,16 +47,32 @@ void af(A *a) {
|
|||
a->f();
|
||||
}
|
||||
|
||||
// CHECK: define internal void @_Z2dfPN12_GLOBAL__N_11DE
|
||||
void df(D *d) {
|
||||
// CHECK: define internal void @_Z3df1PN12_GLOBAL__N_11DE
|
||||
void df1(D *d) {
|
||||
// CHECK: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE")
|
||||
d->f();
|
||||
}
|
||||
|
||||
// CHECK: define internal void @_Z3df2PN12_GLOBAL__N_11DE
|
||||
__attribute__((no_sanitize("cfi")))
|
||||
void df2(D *d) {
|
||||
// CHECK-NOT: call i1 @llvm.bitset.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
// CHECK: define internal void @_Z3df3PN12_GLOBAL__N_11DE
|
||||
__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
|
||||
void df3(D *d) {
|
||||
// CHECK-NOT: call i1 @llvm.bitset.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
D d;
|
||||
|
||||
void foo() {
|
||||
df(&d);
|
||||
df1(&d);
|
||||
df2(&d);
|
||||
df3(&d);
|
||||
}
|
||||
|
||||
// CHECK-DAG: !{!"1A", [3 x i8*]* @_ZTV1A, i64 16}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: %clang_cc1 %s -emit-llvm -fsanitize=address -o - | FileCheck %s
|
||||
|
||||
@interface I0 @end
|
||||
@implementation I0
|
||||
// CHECK-NOT: sanitize_address
|
||||
- (void) im0: (int) a0 __attribute__((no_sanitize("address"))) {
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
// RUN: not %clang_cc1 -std=c++11 -ast-dump %s 2>&1 | FileCheck --check-prefix=DUMP %s
|
||||
// RUN: not %clang_cc1 -std=c++11 -ast-print %s 2>&1 | FileCheck --check-prefix=PRINT %s
|
||||
|
||||
int v1 __attribute__((no_sanitize("address"))); // expected-error{{'no_sanitize' attribute only applies to functions and methods}}
|
||||
|
||||
int f1() __attribute__((no_sanitize)); // expected-error{{'no_sanitize' attribute takes at least 1 argument}}
|
||||
|
||||
int f2() __attribute__((no_sanitize(1))); // expected-error{{'no_sanitize' attribute requires a string}}
|
||||
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} f3
|
||||
// DUMP: NoSanitizeAttr {{.*}} address
|
||||
// PRINT: int f3() __attribute__((no_sanitize("address")))
|
||||
int f3() __attribute__((no_sanitize("address")));
|
||||
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} f4
|
||||
// DUMP: NoSanitizeAttr {{.*}} thread
|
||||
// PRINT: int f4() {{\[\[}}clang::no_sanitize("thread")]]
|
||||
[[clang::no_sanitize("thread")]] int f4();
|
||||
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} f5
|
||||
// DUMP: NoSanitizeAttr {{.*}} address thread
|
||||
// PRINT: int f5() __attribute__((no_sanitize("address", "thread")))
|
||||
int f5() __attribute__((no_sanitize("address", "thread")));
|
||||
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} f6
|
||||
// DUMP: NoSanitizeAttr {{.*}} unknown
|
||||
// PRINT: int f6() __attribute__((no_sanitize("unknown")))
|
||||
int f6() __attribute__((no_sanitize("unknown"))); // expected-warning{{unknown sanitizer 'unknown' ignored}}
|
|
@ -82,6 +82,7 @@ static std::string ReadPCHRecord(StringRef type) {
|
|||
.Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
|
||||
.Case("Expr *", "ReadExpr(F)")
|
||||
.Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
|
||||
.Case("std::string", "ReadString(Record, Idx)")
|
||||
.Default("Record[Idx++]");
|
||||
}
|
||||
|
||||
|
@ -95,6 +96,7 @@ static std::string WritePCHRecord(StringRef type, StringRef name) {
|
|||
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
|
||||
.Case("IdentifierInfo *",
|
||||
"AddIdentifierRef(" + std::string(name) + ", Record);\n")
|
||||
.Case("std::string", "AddString(" + std::string(name) + ", Record);\n")
|
||||
.Default("Record.push_back(" + std::string(name) + ");\n");
|
||||
}
|
||||
|
||||
|
@ -983,6 +985,16 @@ namespace {
|
|||
}
|
||||
};
|
||||
|
||||
class VariadicStringArgument : public VariadicArgument {
|
||||
public:
|
||||
VariadicStringArgument(const Record &Arg, StringRef Attr)
|
||||
: VariadicArgument(Arg, Attr, "std::string")
|
||||
{}
|
||||
void writeValueImpl(raw_ostream &OS) const override {
|
||||
OS << " OS << \"\\\"\" << Val << \"\\\"\";\n";
|
||||
}
|
||||
};
|
||||
|
||||
class TypeArgument : public SimpleArgument {
|
||||
public:
|
||||
TypeArgument(const Record &Arg, StringRef Attr)
|
||||
|
@ -1044,6 +1056,8 @@ createArgument(const Record &Arg, StringRef Attr,
|
|||
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
|
||||
else if (ArgName == "VariadicUnsignedArgument")
|
||||
Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
|
||||
else if (ArgName == "VariadicStringArgument")
|
||||
Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr);
|
||||
else if (ArgName == "VariadicEnumArgument")
|
||||
Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
|
||||
else if (ArgName == "VariadicExprArgument")
|
||||
|
|
Loading…
Reference in New Issue