Index: include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- include/clang/Basic/DiagnosticFrontendKinds.td +++ include/clang/Basic/DiagnosticFrontendKinds.td @@ -224,4 +224,12 @@ def warn_option_invalid_ocl_version : Warning< "OpenCL version %0 does not support the option '%1'">, InGroup; + +def remark_ssp_applied_reason + : Remark<"Stack protector applied to function due to %select{a call to " + "alloca or use of a variable length array|a stack allocated " + "buffer or struct containing a buffer|the address of a local " + "variable being taken|a function attribute|use of " + "-fstack-protector-all}0">, + InGroup; } Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -905,3 +905,6 @@ // A warning group for warnings about code that clang accepts when // compiling OpenCL C/C++ but which is not compatible with the SPIR spec. def SpirCompat : DiagGroup<"spir-compat">; + +// A remark group for remarks about stack protection +def StackProtectorRemark : DiagGroup<"stack-protector">; Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -22,6 +22,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/CodeGen/StackProtector.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -307,6 +308,9 @@ const llvm::OptimizationRemarkAnalysisAliasing &D); void OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D); + + /// \brief Specialized handler for Stack Protector remark diagnostics. + void SSPRemarkHandler(const DiagnosticInfoSSP &D); }; void BackendConsumer::anchor() {} @@ -631,6 +635,23 @@ EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure); } +void BackendConsumer::SSPRemarkHandler(const DiagnosticInfoSSP &D) { + StringRef Filename; + unsigned Line, Column; + bool BadDebugInfo = false; + FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, + Line, Column); + unsigned int Reason = D.Reason(); + if (Reason == DiagnosticInfoSSP::Attribute && + LangOpts.getStackProtector() == LangOptions::SSPReq) { + // The function has the attribute because -fstack-protector-all was + // specified on the command-line + Reason = DiagnosticInfoSSP::LastUsedValue + 1; + } + + Diags.Report(Loc, diag::remark_ssp_applied_reason) << Reason; +} + /// \brief This function is invoked when the backend needs /// to report something to the user. void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { @@ -688,6 +709,9 @@ case llvm::DK_Unsupported: UnsupportedDiagHandler(cast(DI)); return; + case llvm::DK_SSPReason: + SSPRemarkHandler(cast(DI)); + return; default: // Plugin IDs are not bound to any value as they are set dynamically. ComputeDiagRemarkID(Severity, backend_plugin, DiagID); Index: test/CodeGen/stack-protector-remarks.c =================================================================== --- test/CodeGen/stack-protector-remarks.c +++ test/CodeGen/stack-protector-remarks.c @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -emit-obj %s -Rstack-protector -stack-protector 2 -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK1 +// CHECK1-NOT: no_ssp +// CHECK1: call to alloca or use of a variable length array +// CHECK1-NEXT: alloca_ssp() +// CHECK1: call to alloca or use of a variable length array +// CHECK1-NEXT: vla_ssp() +// CHECK1: stack allocated buffer or struct +// CHECK1-NEXT: buffer_ssp() +// CHECK1: stack allocated buffer or struct +// CHECK1-NEXT: struct_ssp() +// CHECK1: address of a local variable +// CHECK1-NEXT: address_ssp() +// CHECK1: stack allocated buffer or struct +// CHECK1-NEXT: multiple_ssp +// CHECK1: stack allocated buffer or struct +// CHECK1: address of a local variable +// CHECK1: call to alloca or use of a variable length array +// CHECK1: call to alloca or use of a variable length array + +// RUN: %clang_cc1 -emit-obj %s -Rstack-protector -stack-protector 3 -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK2 +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: no_ssp +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: alloca_ssp() +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: vla_ssp() +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: buffer_ssp() +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: struct_ssp() +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: address_ssp() +// CHECK2: use of -fstack-protector-all +// CHECK2-NEXT: multiple_ssp + +void no_ssp() { +} + +void alloca_ssp() { + __builtin_alloca(2); +} + +void vla_ssp() { + int n = 10; + int x[n]; +} + +void buffer_ssp() { + int x[64]; +} + +struct X { + int x[64]; +}; +void struct_ssp() { + struct X x; +} + +void address_ssp() { + int x = 32; + int * y = &x; +} + +void multiple_ssp() { + struct X x; + int y[64]; + __builtin_alloca(2); + int a = 32; + int * b = &a; + int c[a]; +}