diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3493,7 +3493,7 @@ def CFGuard : InheritableAttr { // Currently only the __declspec(guard(nocf)) modifier is supported. In future // we might also want to support __declspec(guard(suppress)). - let Spellings = [Declspec<"guard">]; + let Spellings = [Declspec<"guard">, GCC<"guard">]; let Subjects = SubjectList<[Function]>; let Args = [EnumArgument<"Guard", "GuardArg", ["nocf"], ["nocf"]>]; let Documentation = [CFGuardDocs]; diff --git a/clang/test/CodeGen/guard_nocf_mingw.c b/clang/test/CodeGen/guard_nocf_mingw.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/guard_nocf_mingw.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -O2 -o - %s | FileCheck %s + +void target_func(void); +void (*func_ptr)(void) = &target_func; + +// The "guard_nocf" attribute must be added. +__attribute((guard(nocf))) void nocf0(void) { + (*func_ptr)(); +} +// CHECK-LABEL: nocf0 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// The "guard_nocf" attribute must *not* be added. +void cf0(void) { + (*func_ptr)(); +} +// CHECK-LABEL: cf0 +// CHECK: call{{.*}}[[CF:#[0-9]+]] + +// If the modifier is present on either the function declaration or definition, +// the "guard_nocf" attribute must be added. +__attribute__((guard(nocf))) void nocf1(void); +void nocf1(void) { + (*func_ptr)(); +} +// CHECK-LABEL: nocf1 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +void nocf2(void); +__attribute__((guard(nocf))) void nocf2(void) { + (*func_ptr)(); +} +// CHECK-LABEL: nocf2 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// When inlining a function, the "guard_nocf" attribute on indirect calls must +// be preserved. +void nocf3(void) { + nocf0(); +} +// CHECK-LABEL: nocf3 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// When inlining into a function marked as __attribute__((guard(nocf))), the +// "guard_nocf" attribute must *not* be added to the inlined calls. +__attribute__((guard(nocf))) void cf1(void) { + cf0(); +} +// CHECK-LABEL: cf1 +// CHECK: call{{.*}}[[CF:#[0-9]+]] + +// CHECK: attributes [[NOCF]] = { {{.*}}"guard_nocf"{{.*}} } +// CHECK-NOT: attributes [[CF]] = { {{.*}}"guard_nocf"{{.*}} } diff --git a/clang/test/CodeGenCXX/guard_nocf_mingw.cpp b/clang/test/CodeGenCXX/guard_nocf_mingw.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/guard_nocf_mingw.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -emit-llvm -O2 -o - %s | FileCheck %s + +void target_func(); +void (*func_ptr)() = &target_func; + +// The "guard_nocf" attribute must be added. +__attribute__((guard(nocf))) void nocf0() { + (*func_ptr)(); +} +// CHECK-LABEL: nocf0 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// The "guard_nocf" attribute must *not* be added. +void cf0() { + (*func_ptr)(); +} +// CHECK-LABEL: cf0 +// CHECK: call{{.*}}[[CF:#[0-9]+]] + +// If the modifier is present on either the function declaration or definition, +// the "guard_nocf" attribute must be added. +__attribute__((guard(nocf))) void nocf1(); +void nocf1() { + (*func_ptr)(); +} +// CHECK-LABEL: nocf1 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +void nocf2(); +__attribute__((guard(nocf))) void nocf2() { + (*func_ptr)(); +} +// CHECK-LABEL: nocf2 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// When inlining a function, the "guard_nocf" attribute on indirect calls must +// be preserved. +void nocf3() { + nocf0(); +} +// CHECK-LABEL: nocf3 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// When inlining into a function marked as __attribute__((guard(nocf))), the +// "guard_nocf" attribute must *not* be added to the inlined calls. +__attribute__((guard(nocf))) void cf1() { + cf0(); +} +// CHECK-LABEL: cf1 +// CHECK: call{{.*}}[[CF:#[0-9]+]] + +// When the __attribute__((guard(nocf))) modifier is present on an override +// function, the "guard_nocf" attribute must be added. +struct Base { + virtual void nocf4(); +}; + +struct Derived : Base { + __attribute__((guard(nocf))) void nocf4() override { + (*func_ptr)(); + } +}; +Derived d; +// CHECK-LABEL: nocf4 +// CHECK: call{{.*}}[[NOCF:#[0-9]+]] + +// When the modifier is not present on an override function, the "guard_nocf" +// attribute must *not* be added, even if the modifier is present on the virtual +// function. +struct Base1 { + __attribute__((guard(nocf))) virtual void cf2(); +}; + +struct Derived1 : Base1 { + void cf2() override { + (*func_ptr)(); + } +}; +Derived1 d1; +// CHECK-LABEL: cf2 +// CHECK: call{{.*}}[[CF:#[0-9]+]] + +// CHECK: attributes [[NOCF]] = { {{.*}}"guard_nocf"{{.*}} } +// CHECK-NOT: attributes [[CF]] = { {{.*}}"guard_nocf"{{.*}} } diff --git a/clang/test/Sema/attr-guard_nocf_mingw.c b/clang/test/Sema/attr-guard_nocf_mingw.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-guard_nocf_mingw.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -verify -std=c++11 -fsyntax-only -x c++ %s + +// Function definition. +__attribute__((guard(nocf))) void testGuardNoCF(void) { // no warning +} + +// Can not be used on variable, parameter, or function pointer declarations. +int __attribute__((guard(nocf))) i; // expected-warning {{'guard' attribute only applies to functions}} +void testGuardNoCFFuncParam(double __attribute__((guard(nocf))) i) {} // expected-warning {{'guard' attribute only applies to functions}} +__attribute__((guard(nocf))) typedef void (*FuncPtrWithGuardNoCF)(void); // expected-warning {{'guard' attribute only applies to functions}} + +// 'guard' Attribute requries an argument. +__attribute__((guard)) void testGuardNoCFParams(void) { // expected-error {{'guard' attribute takes one argument}} +} + +// 'guard' Attribute requries an identifier as argument. +__attribute__((guard(1))) void testGuardNoCFParamType(void) { // expected-error {{'guard' attribute requires an identifier}} +} + +// 'guard' Attribute only takes a single argument. +__attribute__((guard(nocf, nocf))) void testGuardNoCFTooManyParams(void) { // expected-error {{use of undeclared identifier 'nocf'}} +} + +// 'guard' Attribute argument must be a supported identifier. +__attribute__((guard(cf))) void testGuardNoCFInvalidParam(void) { // expected-warning {{'guard' attribute argument not supported: 'cf'}} +} diff --git a/llvm/test/CodeGen/AArch64/cfguard-checks.ll b/llvm/test/CodeGen/AArch64/cfguard-checks.ll --- a/llvm/test/CodeGen/AArch64/cfguard-checks.ll +++ b/llvm/test/CodeGen/AArch64/cfguard-checks.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=aarch64-pc-windows-msvc | FileCheck %s +; RUN: llc < %s -mtriple=aarch64-pc-windows-gnu | FileCheck %s ; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required. diff --git a/llvm/test/CodeGen/ARM/cfguard-checks.ll b/llvm/test/CodeGen/ARM/cfguard-checks.ll --- a/llvm/test/CodeGen/ARM/cfguard-checks.ll +++ b/llvm/test/CodeGen/ARM/cfguard-checks.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=arm-pc-windows-msvc | FileCheck %s +; RUN: llc < %s -mtriple=arm-pc-windows-gnu | FileCheck %s ; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required. diff --git a/llvm/test/CodeGen/X86/cfguard-checks.ll b/llvm/test/CodeGen/X86/cfguard-checks.ll --- a/llvm/test/CodeGen/X86/cfguard-checks.ll +++ b/llvm/test/CodeGen/X86/cfguard-checks.ll @@ -1,5 +1,7 @@ ; RUN: llc < %s -mtriple=i686-pc-windows-msvc | FileCheck %s -check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s -check-prefix=X64 +; RUN: llc < %s -mtriple=i686-pc-windows-gnu | FileCheck %s -check-prefix=X32 +; RUN: llc < %s -mtriple=x86_64-pc-windows-gnu | FileCheck %s -check-prefix=X64 ; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required.