diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index fd0b304cba0df..8cb4f7ae285de 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1768,6 +1768,13 @@ security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C) strncpy(buf, "a", 1); // warn } +The ``AllowWithoutC11`` option allows reporting warnings for these functions even when not compiling with C11 standard. These functions are deprecated in C11, but may still be problematic in earlier C standards. + +To enable this option, use: +``-analyzer-config security.insecureAPI.DeprecatedOrUnsafeBufferHandling:AllowWithoutC11=true``. + +By default, this option is set to *false*. + .. _security-MmapWriteExec: security.MmapWriteExec (C) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index ffae3b9310979..310dac5340a18 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -901,12 +901,21 @@ def UncheckedReturn : Checker<"UncheckedReturn">, Dependencies<[SecuritySyntaxChecker]>, Documentation; -def DeprecatedOrUnsafeBufferHandling : - Checker<"DeprecatedOrUnsafeBufferHandling">, - HelpText<"Warn on uses of unsecure or deprecated buffer manipulating " - "functions">, - Dependencies<[SecuritySyntaxChecker]>, - Documentation; +def DeprecatedOrUnsafeBufferHandling + : Checker<"DeprecatedOrUnsafeBufferHandling">, + HelpText<"Warn on uses of unsecure or deprecated buffer manipulating " + "functions">, + Dependencies<[SecuritySyntaxChecker]>, + CheckerOptions< + [CmdLineOption< + Boolean, "AllowWithoutC11", + "Allow reporting deprecated or unsafe buffer handling " + "functions even when not compiling with C11 standard. " + "These functions are deprecated in C11, but may still be " + "problematic in earlier C standards.", + "false", Released>, +]>, + Documentation; def decodeValueOfObjCType : Checker<"decodeValueOfObjCType">, HelpText<"Warn on uses of the '-decodeValueOfObjCType:at:' method">, diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 5e75c1c4a3abd..e07c9dcbad9fe 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -50,6 +50,8 @@ struct ChecksFilter { bool check_UncheckedReturn = false; bool check_decodeValueOfObjCType = false; + bool allowDeprecatedOrUnsafeBufferHandlingWithoutC11 = false; + CheckerNameRef checkName_bcmp; CheckerNameRef checkName_bcopy; CheckerNameRef checkName_bzero; @@ -754,7 +756,8 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, if (!filter.check_DeprecatedOrUnsafeBufferHandling) return; - if (!BR.getContext().getLangOpts().C11) + if (!(BR.getContext().getLangOpts().C11 || + filter.allowDeprecatedOrUnsafeBufferHandlingWithoutC11)) return; // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size @@ -1113,5 +1116,20 @@ REGISTER_CHECKER(rand) REGISTER_CHECKER(vfork) REGISTER_CHECKER(FloatLoopCounter) REGISTER_CHECKER(UncheckedReturn) -REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling) + +void ento::registerDeprecatedOrUnsafeBufferHandling(CheckerManager &mgr) { + SecuritySyntaxChecker *checker = mgr.getChecker(); + checker->filter.check_DeprecatedOrUnsafeBufferHandling = true; + checker->filter.checkName_DeprecatedOrUnsafeBufferHandling = + mgr.getCurrentCheckerName(); + checker->filter.allowDeprecatedOrUnsafeBufferHandlingWithoutC11 = + mgr.getAnalyzerOptions().getCheckerBooleanOption( + mgr.getCurrentCheckerName(), "AllowWithoutC11"); +} + +bool ento::shouldRegisterDeprecatedOrUnsafeBufferHandling( + const CheckerManager &mgr) { + return true; +} + REGISTER_CHECKER(decodeValueOfObjCType) diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h index fadc09f65d536..e048a6a892c48 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator.h +++ b/clang/test/Analysis/Inputs/system-header-simulator.h @@ -82,6 +82,7 @@ char *strcpy(char *restrict, const char *restrict); char *strncpy(char *restrict dst, const char *restrict src, size_t n); char *strsep(char **restrict stringp, const char *restrict delim); void *memcpy(void *restrict dst, const void *restrict src, size_t n); +void *memmove(void *dst, const void *src, size_t n); void *memset(void *s, int c, size_t n); typedef unsigned long __darwin_pthread_key_t; diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 7936273415ad4..60ca162fb3f24 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -121,6 +121,7 @@ // CHECK-NEXT: region-store-small-struct-limit = 2 // CHECK-NEXT: report-in-main-source-file = false // CHECK-NEXT: security.cert.env.InvalidPtr:InvalidatingGetEnv = false +// CHECK-NEXT: security.insecureAPI.DeprecatedOrUnsafeBufferHandling:AllowWithoutC11 = false // CHECK-NEXT: serialize-stats = false // CHECK-NEXT: silence-checkers = "" // CHECK-NEXT: stable-report-filename = false diff --git a/clang/test/Analysis/security-deprecated-buffer-handling-allow-without-c11.c b/clang/test/Analysis/security-deprecated-buffer-handling-allow-without-c11.c new file mode 100644 index 0000000000000..880e4bbf81302 --- /dev/null +++ b/clang/test/Analysis/security-deprecated-buffer-handling-allow-without-c11.c @@ -0,0 +1,48 @@ +// Test 1: Without C11 and without flag - should NOT warn +// RUN: %clang_analyze_cc1 %s -verify -std=gnu99 \ +// RUN: -analyzer-checker=security.insecureAPI.DeprecatedOrUnsafeBufferHandling \ +// RUN: -DEXPECT_NO_WARNINGS + +// Test 2: Without C11 but with flag enabled - should warn +// RUN: %clang_analyze_cc1 %s -verify -std=gnu99 \ +// RUN: -analyzer-checker=security.insecureAPI.DeprecatedOrUnsafeBufferHandling \ +// RUN: -analyzer-config security.insecureAPI.DeprecatedOrUnsafeBufferHandling:AllowWithoutC11=true \ +// RUN: -DEXPECT_WARNINGS + +// Test 3: With C11 - should warn (existing behavior) +// RUN: %clang_analyze_cc1 %s -verify -std=gnu11 \ +// RUN: -analyzer-checker=security.insecureAPI.DeprecatedOrUnsafeBufferHandling \ +// RUN: -DEXPECT_WARNINGS + +#include "Inputs/system-header-simulator.h" + +extern char buf[128]; +extern char src[128]; + +void test_memcpy(void) { + memcpy(buf, src, 10); +#ifdef EXPECT_WARNINGS + // expected-warning@-2{{Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard}} +#else + // expected-no-diagnostics +#endif +} + +void test_memset(void) { + memset(buf, 0, 10); +#ifdef EXPECT_WARNINGS + // expected-warning@-2{{Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard}} +#else + // expected-no-diagnostics +#endif +} + +void test_memmove(void) { + memmove(buf, src, 10); +#ifdef EXPECT_WARNINGS + // expected-warning@-2{{Call to function 'memmove' is insecure as it does not provide security checks introduced in the C11 standard}} +#else + // expected-no-diagnostics +#endif +} +