Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -389,6 +389,9 @@ def UncheckedReturn : Checker<"UncheckedReturn">, HelpText<"Warn on uses of functions whose return values must be always checked">, DescFile<"CheckSecuritySyntaxOnly.cpp">; + def DeprecatedOrUnsafeBufferHandling : Checker<"DeprecatedOrUnsafeBufferHandling">, + HelpText<"Warn on uses of unsecure or deprecated buffer manipulating functions">, + DescFile<"CheckSecuritySyntaxOnly.cpp">; } let ParentPackage = Security in { def FloatLoopCounter : Checker<"FloatLoopCounter">, Index: lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -42,6 +42,7 @@ DefaultBool check_mktemp; DefaultBool check_mkstemp; DefaultBool check_strcpy; + DefaultBool check_DeprecatedOrUnsafeBufferHandling; DefaultBool check_rand; DefaultBool check_vfork; DefaultBool check_FloatLoopCounter; @@ -52,6 +53,7 @@ CheckName checkName_mktemp; CheckName checkName_mkstemp; CheckName checkName_strcpy; + CheckName checkName_DeprecatedOrUnsafeBufferHandling; CheckName checkName_rand; CheckName checkName_vfork; CheckName checkName_FloatLoopCounter; @@ -60,7 +62,7 @@ class WalkAST : public StmtVisitor { BugReporter &BR; - AnalysisDeclContext* AC; + AnalysisDeclContext *AC; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; @@ -68,16 +70,14 @@ const ChecksFilter &filter; public: - WalkAST(BugReporter &br, AnalysisDeclContext* ac, - const ChecksFilter &f) - : BR(br), AC(ac), II_setid(), - CheckRand(isArc4RandomAvailable(BR.getContext())), - filter(f) {} + WalkAST(BugReporter &br, AnalysisDeclContext *ac, const ChecksFilter &f) + : BR(br), AC(ac), II_setid(), + CheckRand(isArc4RandomAvailable(BR.getContext())), filter(f) {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); void VisitForStmt(ForStmt *S); - void VisitCompoundStmt (CompoundStmt *S); + void VisitCompoundStmt(CompoundStmt *S); void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitChildren(Stmt *S); @@ -95,6 +95,8 @@ void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD); void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD); void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD); + void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, + const FunctionDecl *FD); void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD); void checkCall_random(const CallExpr *CE, const FunctionDecl *FD); void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD); @@ -121,34 +123,43 @@ // Get the name of the callee. If it's a builtin, strip off the prefix. IdentifierInfo *II = FD->getIdentifier(); - if (!II) // if no identifier, not a simple C function + if (!II) // if no identifier, not a simple C function return; StringRef Name = II->getName(); if (Name.startswith("__builtin_")) Name = Name.substr(10); // Set the evaluation function by switching on the callee name. - FnCheck evalFunction = llvm::StringSwitch(Name) - .Case("gets", &WalkAST::checkCall_gets) - .Case("getpw", &WalkAST::checkCall_getpw) - .Case("mktemp", &WalkAST::checkCall_mktemp) - .Case("mkstemp", &WalkAST::checkCall_mkstemp) - .Case("mkdtemp", &WalkAST::checkCall_mkstemp) - .Case("mkstemps", &WalkAST::checkCall_mkstemp) - .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy) - .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat) - .Case("drand48", &WalkAST::checkCall_rand) - .Case("erand48", &WalkAST::checkCall_rand) - .Case("jrand48", &WalkAST::checkCall_rand) - .Case("lrand48", &WalkAST::checkCall_rand) - .Case("mrand48", &WalkAST::checkCall_rand) - .Case("nrand48", &WalkAST::checkCall_rand) - .Case("lcong48", &WalkAST::checkCall_rand) - .Case("rand", &WalkAST::checkCall_rand) - .Case("rand_r", &WalkAST::checkCall_rand) - .Case("random", &WalkAST::checkCall_random) - .Case("vfork", &WalkAST::checkCall_vfork) - .Default(nullptr); + FnCheck evalFunction = + llvm::StringSwitch(Name) + .Case("gets", &WalkAST::checkCall_gets) + .Case("getpw", &WalkAST::checkCall_getpw) + .Case("mktemp", &WalkAST::checkCall_mktemp) + .Case("mkstemp", &WalkAST::checkCall_mkstemp) + .Case("mkdtemp", &WalkAST::checkCall_mkstemp) + .Case("mkstemps", &WalkAST::checkCall_mkstemp) + .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy) + .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat) + .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf", + "vscanf", "vwscanf", "vfscanf", "vfwscanf", + &WalkAST::checkDeprecatedOrUnsafeBufferHandling) + .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf", + "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove", + &WalkAST::checkDeprecatedOrUnsafeBufferHandling) + .Cases("strncpy", "strncat", "memset", + &WalkAST::checkDeprecatedOrUnsafeBufferHandling) + .Case("drand48", &WalkAST::checkCall_rand) + .Case("erand48", &WalkAST::checkCall_rand) + .Case("jrand48", &WalkAST::checkCall_rand) + .Case("lrand48", &WalkAST::checkCall_rand) + .Case("mrand48", &WalkAST::checkCall_rand) + .Case("nrand48", &WalkAST::checkCall_rand) + .Case("lcong48", &WalkAST::checkCall_rand) + .Case("rand", &WalkAST::checkCall_rand) + .Case("rand_r", &WalkAST::checkCall_rand) + .Case("random", &WalkAST::checkCall_random) + .Case("vfork", &WalkAST::checkCall_vfork) + .Default(nullptr); // If the callee isn't defined, it is not of security concern. // Check and evaluate the call. @@ -181,8 +192,8 @@ // Implements: CERT security coding advisory FLP-30. //===----------------------------------------------------------------------===// -static const DeclRefExpr* -getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { +static const DeclRefExpr *getIncrementedVar(const Expr *expr, const VarDecl *x, + const VarDecl *y) { expr = expr->IgnoreParenCasts(); if (const BinaryOperator *B = dyn_cast(expr)) { @@ -206,7 +217,8 @@ if (const UnaryOperator *U = dyn_cast(expr)) return U->isIncrementDecrementOp() - ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr; + ? getIncrementedVar(U->getSubExpr(), x, y) + : nullptr; return nullptr; } @@ -247,9 +259,9 @@ // Are we comparing variables? const DeclRefExpr *drLHS = - dyn_cast(B->getLHS()->IgnoreParenLValueCasts()); + dyn_cast(B->getLHS()->IgnoreParenLValueCasts()); const DeclRefExpr *drRHS = - dyn_cast(B->getRHS()->IgnoreParenLValueCasts()); + dyn_cast(B->getRHS()->IgnoreParenLValueCasts()); // Does at least one of the variables have a floating point type? drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr; @@ -289,10 +301,9 @@ const char *bugType = "Floating point variable used as loop counter"; PathDiagnosticLocation FSLoc = - PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter, - bugType, "Security", os.str(), - FSLoc, ranges); + PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC); + BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter, bugType, + "Security", os.str(), FSLoc, ranges); } //===----------------------------------------------------------------------===// @@ -324,10 +335,9 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets, - "Potential buffer overflow in call to 'gets'", - "Security", + "Potential buffer overflow in call to 'gets'", "Security", "Call to function 'gets' is extremely insecure as it can " "always result in a buffer overflow", CELoc, CE->getCallee()->getSourceRange()); @@ -364,10 +374,9 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw, - "Potential buffer overflow in call to 'getpw'", - "Security", + "Potential buffer overflow in call to 'getpw'", "Security", "The getpw() function is dangerous as it may overflow the " "provided buffer. It is obsoleted by getpwuid().", CELoc, CE->getCallee()->getSourceRange()); @@ -387,7 +396,7 @@ } const FunctionProtoType *FPT = FD->getType()->getAs(); - if(!FPT) + if (!FPT) return; // Verify that the function takes a single argument. @@ -405,7 +414,7 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp, "Potential insecure temporary file in call 'mktemp'", "Security", @@ -415,7 +424,6 @@ CELoc, CE->getCallee()->getSourceRange()); } - //===----------------------------------------------------------------------===// // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's. //===----------------------------------------------------------------------===// @@ -426,23 +434,22 @@ StringRef Name = FD->getIdentifier()->getName(); std::pair ArgSuffix = - llvm::StringSwitch >(Name) - .Case("mktemp", std::make_pair(0,-1)) - .Case("mkstemp", std::make_pair(0,-1)) - .Case("mkdtemp", std::make_pair(0,-1)) - .Case("mkstemps", std::make_pair(0,1)) - .Default(std::make_pair(-1, -1)); + llvm::StringSwitch>(Name) + .Case("mktemp", std::make_pair(0, -1)) + .Case("mkstemp", std::make_pair(0, -1)) + .Case("mkdtemp", std::make_pair(0, -1)) + .Case("mkstemps", std::make_pair(0, 1)) + .Default(std::make_pair(-1, -1)); assert(ArgSuffix.first >= 0 && "Unsupported function"); // Check if the number of arguments is consistent with out expectations. unsigned numArgs = CE->getNumArgs(); - if ((signed) numArgs <= ArgSuffix.first) + if ((signed)numArgs <= ArgSuffix.first) return; - const StringLiteral *strArg = - dyn_cast(CE->getArg((unsigned)ArgSuffix.first) - ->IgnoreParenImpCasts()); + const StringLiteral *strArg = dyn_cast( + CE->getArg((unsigned)ArgSuffix.first)->IgnoreParenImpCasts()); // Currently we only handle string literals. It is possible to do better, // either by looking at references to const variables, or by doing real @@ -465,23 +472,26 @@ // FIXME: Issue a warning. if (Result.isNegative()) return; - suffix = (unsigned) Result.getZExtValue(); + suffix = (unsigned)Result.getZExtValue(); n = (n > suffix) ? n - suffix : 0; } for (unsigned i = 0; i < n; ++i) - if (str[i] == 'X') ++numX; + if (str[i] == 'X') + ++numX; if (numX >= 6) return; // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); SmallString<512> buf; llvm::raw_svector_ostream out(buf); - out << "Call to '" << Name << "' should have at least 6 'X's in the" - " format string to be secure (" << numX << " 'X'"; + out << "Call to '" << Name + << "' should have at least 6 'X's in the" + " format string to be secure (" + << numX << " 'X'"; if (numX != 1) out << 's'; out << " seen"; @@ -493,8 +503,8 @@ } out << ')'; BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp, - "Insecure temporary file creation", "Security", - out.str(), CELoc, strArg->getSourceRange()); + "Insecure temporary file creation", "Security", out.str(), + CELoc, strArg->getSourceRange()); } //===----------------------------------------------------------------------===// @@ -523,7 +533,7 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy, "Potential insecure memory buffer bounds restriction in " "call 'strcpy'", @@ -550,7 +560,7 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy, "Potential insecure memory buffer bounds restriction in " "call 'strcat'", @@ -563,6 +573,85 @@ } //===----------------------------------------------------------------------===// +// Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf', +// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf', +// 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf', +// 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset' +// is deprecated since C11. +// +// Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', +//'fscanf', +// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf', +// 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations +// is insecure. +// +// CWE-119: Improper Restriction of Operations within +// the Bounds of a Memory Buffer +//===----------------------------------------------------------------------===// +void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, + const FunctionDecl *FD) { + if (!filter.check_DeprecatedOrUnsafeBufferHandling) + return; + + if (!BR.getContext().getLangOpts().C11) + return; + + // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size + // restrictions). + enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 }; + StringRef Name = FD->getIdentifier()->getName(); + int ArgIndex = + llvm::StringSwitch(Name) + .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0) + .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf", + "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1) + .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy", + "memmove", "memset", "strncpy", "strncat", DEPR_ONLY) + .Default(UNKNOWN_CALL); + + assert(ArgIndex != UNKNOWN_CALL && "Unsupported function"); + bool BoundsProvided = ArgIndex == DEPR_ONLY; + + if (!BoundsProvided) { + // Currently we only handle (not wide) string literals. It is possible to do + // better, either by looking at references to const variables, or by doing + // real flow analysis. + auto FormatString = + dyn_cast(CE->getArg(ArgIndex)->IgnoreParenImpCasts()); + if (FormatString && + FormatString->getString().find("%s") == StringRef::npos && + FormatString->getString().find("%[") == StringRef::npos) + BoundsProvided = true; + } + + SmallString<128> buf1; + SmallString<512> buf2; + llvm::raw_svector_ostream out1(buf1); + llvm::raw_svector_ostream out2(buf2); + + out1 << "Potential insecure memory buffer bounds restriction in call '" + << Name << "'"; + out2 << "Call to function '" << Name + << "' is insecure as it does not provide "; + + if (!BoundsProvided) { + out2 << "bounding of the memory buffer or "; + } + + out2 << "security checks introduced " + "in the C11 standard. Replace with analogous functions that " + "support length arguments or provides boundary checks such as '" + << Name << "_s' in case of C11"; + + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + BR.EmitBasicReport(AC->getDecl(), + filter.checkName_DeprecatedOrUnsafeBufferHandling, + out1.str(), "Security", out2.str(), CELoc, + CE->getCallee()->getSourceRange()); +} + +//===----------------------------------------------------------------------===// // Common check for str* functions with no bounds parameters. //===----------------------------------------------------------------------===// bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) { @@ -595,7 +684,6 @@ // Originally: // CWE-338: Use of cryptographically weak prng //===----------------------------------------------------------------------===// - void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { if (!filter.check_rand || !CheckRand) return; @@ -611,7 +699,7 @@ if (!PT) return; - if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType()) + if (!PT->getPointeeType()->isIntegralOrUnscopedEnumerationType()) return; } else if (FTP->getNumParams() != 0) return; @@ -628,7 +716,7 @@ << " Use 'arc4random' instead"; PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(), "Security", os2.str(), CELoc, CE->getCallee()->getSourceRange()); @@ -653,13 +741,14 @@ // Issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, "'random' is not a secure random number generator", "Security", "The 'random' function produces a sequence of values that " "an adversary may be able to predict. Use 'arc4random' " - "instead", CELoc, CE->getCallee()->getSourceRange()); + "instead", + CELoc, CE->getCallee()->getSourceRange()); } //===----------------------------------------------------------------------===// @@ -673,7 +762,7 @@ // All calls to vfork() are insecure, issue a warning. PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork, "Potential insecure implementation-specific behavior in " "call 'vfork'", @@ -699,10 +788,8 @@ return; if (II_setid[0] == nullptr) { - static const char * const identifiers[num_setids] = { - "setuid", "setgid", "seteuid", "setegid", - "setreuid", "setregid" - }; + static const char *const identifiers[num_setids] = { + "setuid", "setgid", "seteuid", "setegid", "setreuid", "setregid"}; for (size_t i = 0; i < num_setids; i++) II_setid[i] = &BR.getContext().Idents.get(identifiers[i]); @@ -744,7 +831,7 @@ << "', the following code may execute with unexpected privileges"; PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(), "Security", os2.str(), CELoc, CE->getCallee()->getSourceRange()); @@ -759,13 +846,13 @@ public: ChecksFilter filter; - void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, + void checkASTCodeBody(const Decl *D, AnalysisManager &mgr, BugReporter &BR) const { WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter); walker.Visit(D->getBody()); } }; -} +} // namespace #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ @@ -784,5 +871,4 @@ REGISTER_CHECKER(vfork) REGISTER_CHECKER(FloatLoopCounter) REGISTER_CHECKER(UncheckedReturn) - - +REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling) Index: test/Analysis/security-syntax-checks.m =================================================================== --- test/Analysis/security-syntax-checks.m +++ test/Analysis/security-syntax-checks.m @@ -13,6 +13,9 @@ # define BUILTIN(f) f #endif /* USE_BUILTINS */ +#include "Inputs/system-header-simulator-for-valist.h" +#include "Inputs/system-header-simulator-for-simple-stream.h" + typedef typeof(sizeof(int)) size_t; @@ -212,3 +215,83 @@ mkdtemp("XXXXXX"); } + +//===----------------------------------------------------------------------=== +// deprecated or unsafe buffer handling +//===----------------------------------------------------------------------=== +typedef int wchar_t; + +int sprintf(char *str, const char *format, ...); +//int vsprintf (char *s, const char *format, va_list arg); +int scanf(const char *format, ...); +int wscanf(const wchar_t *format, ...); +int fscanf(FILE *stream, const char *format, ...); +int fwscanf(FILE *stream, const wchar_t *format, ...); +int vscanf(const char *format, va_list arg); +int vwscanf(const wchar_t *format, va_list arg); +int vfscanf(FILE *stream, const char *format, va_list arg); +int vfwscanf(FILE *stream, const wchar_t *format, va_list arg); +int sscanf(const char *s, const char *format, ...); +int swscanf(const wchar_t *ws, const wchar_t *format, ...); +int vsscanf(const char *s, const char *format, va_list arg); +int vswscanf(const wchar_t *ws, const wchar_t *format, va_list arg); +int swprintf(wchar_t *ws, size_t len, const wchar_t *format, ...); +int snprintf(char *s, size_t n, const char *format, ...); +int vswprintf(wchar_t *ws, size_t len, const wchar_t *format, va_list arg); +int vsnprintf(char *s, size_t n, const char *format, va_list arg); +void *memcpy(void *destination, const void *source, size_t num); +void *memmove(void *destination, const void *source, size_t num); +char *strncpy(char *destination, const char *source, size_t num); +char *strncat(char *destination, const char *source, size_t num); +void *memset(void *ptr, int value, size_t num); + +void test_deprecated_or_unsafe_buffer_handling_1() { + char buf [5]; + wchar_t wbuf [5]; + int a; + FILE *file; + sprintf(buf, "a"); // expected-warning{{Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11}} + scanf("%d", &a); // expected-warning{{Call to function 'scanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'scanf_s' in case of C11}} + scanf("%s", buf); // expected-warning{{Call to function 'scanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'scanf_s' in case of C11}} + scanf("%4s", buf); // expected-warning{{Call to function 'scanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'scanf_s' in case of C11}} + wscanf((const wchar_t*) L"%s", buf); // expected-warning{{Call to function 'wscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'wscanf_s' in case of C11}} + fscanf(file, "%d", &a); // expected-warning{{Call to function 'fscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fscanf_s' in case of C11}} + fscanf(file, "%s", buf); // expected-warning{{Call to function 'fscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fscanf_s' in case of C11}} + fscanf(file, "%4s", buf); // expected-warning{{Call to function 'fscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fscanf_s' in case of C11}} + fwscanf(file, (const wchar_t*) L"%s", wbuf); // expected-warning{{Call to function 'fwscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fwscanf_s' in case of C11}} + sscanf("5", "%d", &a); // expected-warning{{Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11}} + sscanf("5", "%s", buf); // expected-warning{{Call to function 'sscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11}} + sscanf("5", "%4s", buf); // expected-warning{{Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11}} + swscanf(L"5", (const wchar_t*) L"%s", wbuf); // expected-warning{{Call to function 'swscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'swscanf_s' in case of C11}} + swprintf(L"5", 1, (const wchar_t*) L"%s", wbuf); // expected-warning{{Call to function 'swprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'swprintf_s' in case of C11}} + snprintf("5", 1, "%s", buf); // expected-warning{{Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11}} + memcpy(buf, wbuf, 1); // expected-warning{{Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11}} + memmove(buf, wbuf, 1); // expected-warning{{Call to function 'memmove' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memmove_s' in case of C11}} + strncpy(buf, "a", 1); // expected-warning{{Call to function 'strncpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'strncpy_s' in case of C11}} + strncat(buf, "a", 1); // expected-warning{{Call to function 'strncat' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'strncat_s' in case of C11}} + memset(buf, 'a', 1); // expected-warning{{Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11}} +} + +void test_deprecated_or_unsafe_buffer_handling_2(const char *format, ...) { + char buf [5]; + FILE *file; + va_list args; + va_start(args, format); + vsprintf(buf, format, args); // expected-warning{{Call to function 'vsprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vsprintf_s' in case of C11}} + vscanf(format, args); // expected-warning{{Call to function 'vscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vscanf_s' in case of C11}} + vfscanf(file, format, args); // expected-warning{{Call to function 'vfscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vfscanf_s' in case of C11}} + vsscanf("a", format, args); // expected-warning{{Call to function 'vsscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vsscanf_s' in case of C11}} + vsnprintf("a", 1, format, args); // expected-warning{{Call to function 'vsnprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vsnprintf_s' in case of C11}} +} + +void test_deprecated_or_unsafe_buffer_handling_3(const wchar_t *format, ...) { + wchar_t wbuf [5]; + FILE *file; + va_list args; + va_start(args, format); + vwscanf(format, args); // expected-warning{{Call to function 'vwscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vwscanf_s' in case of C11}} + vfwscanf(file, format, args); // expected-warning{{Call to function 'vfwscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vfwscanf_s' in case of C11}} + vswscanf(L"a", format, args); // expected-warning{{Call to function 'vswscanf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vswscanf_s' in case of C11}} + vswprintf(L"a", 1, format, args); // expected-warning{{Call to function 'vswprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'vswprintf_s' in case of C11}} +} +