Bug Summary

File:clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
Warning:line 327, column 25
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name CheckSecuritySyntaxOnly.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
1//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a set of flow-insensitive security checks.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14#include "clang/AST/StmtVisitor.h"
15#include "clang/Analysis/AnalysisDeclContext.h"
16#include "clang/Basic/TargetInfo.h"
17#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18#include "clang/StaticAnalyzer/Core/Checker.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/StringSwitch.h"
22#include "llvm/Support/raw_ostream.h"
23
24using namespace clang;
25using namespace ento;
26
27static bool isArc4RandomAvailable(const ASTContext &Ctx) {
28 const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29 return T.getVendor() == llvm::Triple::Apple ||
30 T.getOS() == llvm::Triple::CloudABI ||
31 T.isOSFreeBSD() ||
32 T.isOSNetBSD() ||
33 T.isOSOpenBSD() ||
34 T.isOSDragonFly();
35}
36
37namespace {
38struct ChecksFilter {
39 DefaultBool check_bcmp;
40 DefaultBool check_bcopy;
41 DefaultBool check_bzero;
42 DefaultBool check_gets;
43 DefaultBool check_getpw;
44 DefaultBool check_mktemp;
45 DefaultBool check_mkstemp;
46 DefaultBool check_strcpy;
47 DefaultBool check_DeprecatedOrUnsafeBufferHandling;
48 DefaultBool check_rand;
49 DefaultBool check_vfork;
50 DefaultBool check_FloatLoopCounter;
51 DefaultBool check_UncheckedReturn;
52 DefaultBool check_decodeValueOfObjCType;
53
54 CheckerNameRef checkName_bcmp;
55 CheckerNameRef checkName_bcopy;
56 CheckerNameRef checkName_bzero;
57 CheckerNameRef checkName_gets;
58 CheckerNameRef checkName_getpw;
59 CheckerNameRef checkName_mktemp;
60 CheckerNameRef checkName_mkstemp;
61 CheckerNameRef checkName_strcpy;
62 CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
63 CheckerNameRef checkName_rand;
64 CheckerNameRef checkName_vfork;
65 CheckerNameRef checkName_FloatLoopCounter;
66 CheckerNameRef checkName_UncheckedReturn;
67 CheckerNameRef checkName_decodeValueOfObjCType;
68};
69
70class WalkAST : public StmtVisitor<WalkAST> {
71 BugReporter &BR;
72 AnalysisDeclContext* AC;
73 enum { num_setids = 6 };
74 IdentifierInfo *II_setid[num_setids];
75
76 const bool CheckRand;
77 const ChecksFilter &filter;
78
79public:
80 WalkAST(BugReporter &br, AnalysisDeclContext* ac,
81 const ChecksFilter &f)
82 : BR(br), AC(ac), II_setid(),
83 CheckRand(isArc4RandomAvailable(BR.getContext())),
84 filter(f) {}
85
86 // Statement visitor methods.
87 void VisitCallExpr(CallExpr *CE);
88 void VisitObjCMessageExpr(ObjCMessageExpr *CE);
89 void VisitForStmt(ForStmt *S);
90 void VisitCompoundStmt (CompoundStmt *S);
91 void VisitStmt(Stmt *S) { VisitChildren(S); }
92
93 void VisitChildren(Stmt *S);
94
95 // Helpers.
96 bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
97
98 typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
99 typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
100
101 // Checker-specific methods.
102 void checkLoopConditionForFloat(const ForStmt *FS);
103 void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
104 void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
105 void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
106 void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
107 void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
108 void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
109 void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
110 void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
111 void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
112 void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
113 const FunctionDecl *FD);
114 void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
115 void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
116 void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
117 void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
118 void checkUncheckedReturnValue(CallExpr *CE);
119};
120} // end anonymous namespace
121
122//===----------------------------------------------------------------------===//
123// AST walking.
124//===----------------------------------------------------------------------===//
125
126void WalkAST::VisitChildren(Stmt *S) {
127 for (Stmt *Child : S->children())
128 if (Child)
129 Visit(Child);
130}
131
132void WalkAST::VisitCallExpr(CallExpr *CE) {
133 // Get the callee.
134 const FunctionDecl *FD = CE->getDirectCallee();
135
136 if (!FD)
137 return;
138
139 // Get the name of the callee. If it's a builtin, strip off the prefix.
140 IdentifierInfo *II = FD->getIdentifier();
141 if (!II) // if no identifier, not a simple C function
142 return;
143 StringRef Name = II->getName();
144 if (Name.startswith("__builtin_"))
145 Name = Name.substr(10);
146
147 // Set the evaluation function by switching on the callee name.
148 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
149 .Case("bcmp", &WalkAST::checkCall_bcmp)
150 .Case("bcopy", &WalkAST::checkCall_bcopy)
151 .Case("bzero", &WalkAST::checkCall_bzero)
152 .Case("gets", &WalkAST::checkCall_gets)
153 .Case("getpw", &WalkAST::checkCall_getpw)
154 .Case("mktemp", &WalkAST::checkCall_mktemp)
155 .Case("mkstemp", &WalkAST::checkCall_mkstemp)
156 .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
157 .Case("mkstemps", &WalkAST::checkCall_mkstemp)
158 .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
159 .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
160 .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
161 "vscanf", "vwscanf", "vfscanf", "vfwscanf",
162 &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
163 .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
164 "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
165 &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
166 .Cases("strncpy", "strncat", "memset",
167 &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
168 .Case("drand48", &WalkAST::checkCall_rand)
169 .Case("erand48", &WalkAST::checkCall_rand)
170 .Case("jrand48", &WalkAST::checkCall_rand)
171 .Case("lrand48", &WalkAST::checkCall_rand)
172 .Case("mrand48", &WalkAST::checkCall_rand)
173 .Case("nrand48", &WalkAST::checkCall_rand)
174 .Case("lcong48", &WalkAST::checkCall_rand)
175 .Case("rand", &WalkAST::checkCall_rand)
176 .Case("rand_r", &WalkAST::checkCall_rand)
177 .Case("random", &WalkAST::checkCall_random)
178 .Case("vfork", &WalkAST::checkCall_vfork)
179 .Default(nullptr);
180
181 // If the callee isn't defined, it is not of security concern.
182 // Check and evaluate the call.
183 if (evalFunction)
184 (this->*evalFunction)(CE, FD);
185
186 // Recurse and check children.
187 VisitChildren(CE);
188}
189
190void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
191 MsgCheck evalFunction =
192 llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
193 .Case("decodeValueOfObjCType:at:",
194 &WalkAST::checkMsg_decodeValueOfObjCType)
195 .Default(nullptr);
196
197 if (evalFunction)
198 (this->*evalFunction)(ME);
199
200 // Recurse and check children.
201 VisitChildren(ME);
202}
203
204void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
205 for (Stmt *Child : S->children())
206 if (Child) {
207 if (CallExpr *CE = dyn_cast<CallExpr>(Child))
208 checkUncheckedReturnValue(CE);
209 Visit(Child);
210 }
211}
212
213void WalkAST::VisitForStmt(ForStmt *FS) {
214 checkLoopConditionForFloat(FS);
1
Calling 'WalkAST::checkLoopConditionForFloat'
215
216 // Recurse and check children.
217 VisitChildren(FS);
218}
219
220//===----------------------------------------------------------------------===//
221// Check: floating point variable used as loop counter.
222// Originally: <rdar://problem/6336718>
223// Implements: CERT security coding advisory FLP-30.
224//===----------------------------------------------------------------------===//
225
226// Returns either 'x' or 'y', depending on which one of them is incremented
227// in 'expr', or nullptr if none of them is incremented.
228static const DeclRefExpr*
229getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
230 expr = expr->IgnoreParenCasts();
231
232 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
233 if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
234 B->getOpcode() == BO_Comma))
235 return nullptr;
236
237 if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
238 return lhs;
239
240 if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
241 return rhs;
242
243 return nullptr;
244 }
245
246 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
247 const NamedDecl *ND = DR->getDecl();
248 return ND == x || ND == y ? DR : nullptr;
249 }
250
251 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
252 return U->isIncrementDecrementOp()
253 ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
254
255 return nullptr;
256}
257
258/// CheckLoopConditionForFloat - This check looks for 'for' statements that
259/// use a floating point variable as a loop counter.
260/// CERT: FLP30-C, FLP30-CPP.
261///
262void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
263 if (!filter.check_FloatLoopCounter)
2
Assuming the condition is false
3
Taking false branch
264 return;
265
266 // Does the loop have a condition?
267 const Expr *condition = FS->getCond();
268
269 if (!condition)
4
Assuming 'condition' is non-null
5
Taking false branch
270 return;
271
272 // Does the loop have an increment?
273 const Expr *increment = FS->getInc();
274
275 if (!increment)
6
Assuming 'increment' is non-null
7
Taking false branch
276 return;
277
278 // Strip away '()' and casts.
279 condition = condition->IgnoreParenCasts();
280 increment = increment->IgnoreParenCasts();
281
282 // Is the loop condition a comparison?
283 const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
8
Assuming 'condition' is a 'BinaryOperator'
284
285 if (!B
8.1
'B' is non-null
)
286 return;
287
288 // Is this a comparison?
289 if (!(B->isRelationalOp() || B->isEqualityOp()))
9
Taking false branch
290 return;
291
292 // Are we comparing variables?
293 const DeclRefExpr *drLHS =
294 dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
10
Assuming the object is a 'DeclRefExpr'
295 const DeclRefExpr *drRHS =
296 dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
11
Assuming the object is a 'DeclRefExpr'
297
298 // Does at least one of the variables have a floating point type?
299 drLHS = drLHS
11.1
'drLHS' is non-null
&& drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
12
Assuming the condition is true
13
'?' condition is true
300 drRHS = drRHS
13.1
'drRHS' is non-null
&& drRHS->getType()->isRealFloatingType() ? drRHS : nullptr
;
14
Assuming the condition is false
15
'?' condition is false
16
Null pointer value stored to 'drRHS'
301
302 if (!drLHS
16.1
'drLHS' is non-null
&& !drRHS)
303 return;
304
305 const VarDecl *vdLHS = drLHS
16.2
'drLHS' is non-null
? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
17
'?' condition is true
18
Assuming the object is a 'VarDecl'
306 const VarDecl *vdRHS = drRHS
18.1
'drRHS' is null
? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
19
'?' condition is false
307
308 if (!vdLHS
19.1
'vdLHS' is non-null
&& !vdRHS)
309 return;
310
311 // Does either variable appear in increment?
312 const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
313 if (!drInc)
20
Assuming 'drInc' is non-null
21
Taking false branch
314 return;
315
316 const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
22
The object is a 'VarDecl'
317 assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS))(static_cast<void> (0));
318
319 // Emit the error. First figure out which DeclRefExpr in the condition
320 // referenced the compared variable.
321 const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
23
Assuming 'vdLHS' is not equal to 'vdInc'
24
'?' condition is false
25
'drCond' initialized to a null pointer value
322
323 SmallVector<SourceRange, 2> ranges;
324 SmallString<256> sbuf;
325 llvm::raw_svector_ostream os(sbuf);
326
327 os << "Variable '" << drCond->getDecl()->getName()
26
Called C++ object pointer is null
328 << "' with floating point type '" << drCond->getType().getAsString()
329 << "' should not be used as a loop counter";
330
331 ranges.push_back(drCond->getSourceRange());
332 ranges.push_back(drInc->getSourceRange());
333
334 const char *bugType = "Floating point variable used as loop counter";
335
336 PathDiagnosticLocation FSLoc =
337 PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
338 BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
339 bugType, "Security", os.str(),
340 FSLoc, ranges);
341}
342
343//===----------------------------------------------------------------------===//
344// Check: Any use of bcmp.
345// CWE-477: Use of Obsolete Functions
346// bcmp was deprecated in POSIX.1-2008
347//===----------------------------------------------------------------------===//
348
349void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
350 if (!filter.check_bcmp)
351 return;
352
353 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
354 if (!FPT)
355 return;
356
357 // Verify that the function takes three arguments.
358 if (FPT->getNumParams() != 3)
359 return;
360
361 for (int i = 0; i < 2; i++) {
362 // Verify the first and second argument type is void*.
363 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
364 if (!PT)
365 return;
366
367 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
368 return;
369 }
370
371 // Verify the third argument type is integer.
372 if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
373 return;
374
375 // Issue a warning.
376 PathDiagnosticLocation CELoc =
377 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
378 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
379 "Use of deprecated function in call to 'bcmp()'",
380 "Security",
381 "The bcmp() function is obsoleted by memcmp().",
382 CELoc, CE->getCallee()->getSourceRange());
383}
384
385//===----------------------------------------------------------------------===//
386// Check: Any use of bcopy.
387// CWE-477: Use of Obsolete Functions
388// bcopy was deprecated in POSIX.1-2008
389//===----------------------------------------------------------------------===//
390
391void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
392 if (!filter.check_bcopy)
393 return;
394
395 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
396 if (!FPT)
397 return;
398
399 // Verify that the function takes three arguments.
400 if (FPT->getNumParams() != 3)
401 return;
402
403 for (int i = 0; i < 2; i++) {
404 // Verify the first and second argument type is void*.
405 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
406 if (!PT)
407 return;
408
409 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
410 return;
411 }
412
413 // Verify the third argument type is integer.
414 if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
415 return;
416
417 // Issue a warning.
418 PathDiagnosticLocation CELoc =
419 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
420 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
421 "Use of deprecated function in call to 'bcopy()'",
422 "Security",
423 "The bcopy() function is obsoleted by memcpy() "
424 "or memmove().",
425 CELoc, CE->getCallee()->getSourceRange());
426}
427
428//===----------------------------------------------------------------------===//
429// Check: Any use of bzero.
430// CWE-477: Use of Obsolete Functions
431// bzero was deprecated in POSIX.1-2008
432//===----------------------------------------------------------------------===//
433
434void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
435 if (!filter.check_bzero)
436 return;
437
438 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
439 if (!FPT)
440 return;
441
442 // Verify that the function takes two arguments.
443 if (FPT->getNumParams() != 2)
444 return;
445
446 // Verify the first argument type is void*.
447 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
448 if (!PT)
449 return;
450
451 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
452 return;
453
454 // Verify the second argument type is integer.
455 if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
456 return;
457
458 // Issue a warning.
459 PathDiagnosticLocation CELoc =
460 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
461 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
462 "Use of deprecated function in call to 'bzero()'",
463 "Security",
464 "The bzero() function is obsoleted by memset().",
465 CELoc, CE->getCallee()->getSourceRange());
466}
467
468
469//===----------------------------------------------------------------------===//
470// Check: Any use of 'gets' is insecure.
471// Originally: <rdar://problem/6335715>
472// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
473// CWE-242: Use of Inherently Dangerous Function
474//===----------------------------------------------------------------------===//
475
476void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
477 if (!filter.check_gets)
478 return;
479
480 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
481 if (!FPT)
482 return;
483
484 // Verify that the function takes a single argument.
485 if (FPT->getNumParams() != 1)
486 return;
487
488 // Is the argument a 'char*'?
489 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
490 if (!PT)
491 return;
492
493 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
494 return;
495
496 // Issue a warning.
497 PathDiagnosticLocation CELoc =
498 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
499 BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
500 "Potential buffer overflow in call to 'gets'",
501 "Security",
502 "Call to function 'gets' is extremely insecure as it can "
503 "always result in a buffer overflow",
504 CELoc, CE->getCallee()->getSourceRange());
505}
506
507//===----------------------------------------------------------------------===//
508// Check: Any use of 'getpwd' is insecure.
509// CWE-477: Use of Obsolete Functions
510//===----------------------------------------------------------------------===//
511
512void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
513 if (!filter.check_getpw)
514 return;
515
516 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
517 if (!FPT)
518 return;
519
520 // Verify that the function takes two arguments.
521 if (FPT->getNumParams() != 2)
522 return;
523
524 // Verify the first argument type is integer.
525 if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
526 return;
527
528 // Verify the second argument type is char*.
529 const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
530 if (!PT)
531 return;
532
533 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
534 return;
535
536 // Issue a warning.
537 PathDiagnosticLocation CELoc =
538 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
539 BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
540 "Potential buffer overflow in call to 'getpw'",
541 "Security",
542 "The getpw() function is dangerous as it may overflow the "
543 "provided buffer. It is obsoleted by getpwuid().",
544 CELoc, CE->getCallee()->getSourceRange());
545}
546
547//===----------------------------------------------------------------------===//
548// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
549// CWE-377: Insecure Temporary File
550//===----------------------------------------------------------------------===//
551
552void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
553 if (!filter.check_mktemp) {
554 // Fall back to the security check of looking for enough 'X's in the
555 // format string, since that is a less severe warning.
556 checkCall_mkstemp(CE, FD);
557 return;
558 }
559
560 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
561 if(!FPT)
562 return;
563
564 // Verify that the function takes a single argument.
565 if (FPT->getNumParams() != 1)
566 return;
567
568 // Verify that the argument is Pointer Type.
569 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
570 if (!PT)
571 return;
572
573 // Verify that the argument is a 'char*'.
574 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
575 return;
576
577 // Issue a warning.
578 PathDiagnosticLocation CELoc =
579 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
580 BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
581 "Potential insecure temporary file in call 'mktemp'",
582 "Security",
583 "Call to function 'mktemp' is insecure as it always "
584 "creates or uses insecure temporary file. Use 'mkstemp' "
585 "instead",
586 CELoc, CE->getCallee()->getSourceRange());
587}
588
589//===----------------------------------------------------------------------===//
590// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
591//===----------------------------------------------------------------------===//
592
593void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
594 if (!filter.check_mkstemp)
595 return;
596
597 StringRef Name = FD->getIdentifier()->getName();
598 std::pair<signed, signed> ArgSuffix =
599 llvm::StringSwitch<std::pair<signed, signed> >(Name)
600 .Case("mktemp", std::make_pair(0,-1))
601 .Case("mkstemp", std::make_pair(0,-1))
602 .Case("mkdtemp", std::make_pair(0,-1))
603 .Case("mkstemps", std::make_pair(0,1))
604 .Default(std::make_pair(-1, -1));
605
606 assert(ArgSuffix.first >= 0 && "Unsupported function")(static_cast<void> (0));
607
608 // Check if the number of arguments is consistent with out expectations.
609 unsigned numArgs = CE->getNumArgs();
610 if ((signed) numArgs <= ArgSuffix.first)
611 return;
612
613 const StringLiteral *strArg =
614 dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
615 ->IgnoreParenImpCasts());
616
617 // Currently we only handle string literals. It is possible to do better,
618 // either by looking at references to const variables, or by doing real
619 // flow analysis.
620 if (!strArg || strArg->getCharByteWidth() != 1)
621 return;
622
623 // Count the number of X's, taking into account a possible cutoff suffix.
624 StringRef str = strArg->getString();
625 unsigned numX = 0;
626 unsigned n = str.size();
627
628 // Take into account the suffix.
629 unsigned suffix = 0;
630 if (ArgSuffix.second >= 0) {
631 const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
632 Expr::EvalResult EVResult;
633 if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
634 return;
635 llvm::APSInt Result = EVResult.Val.getInt();
636 // FIXME: Issue a warning.
637 if (Result.isNegative())
638 return;
639 suffix = (unsigned) Result.getZExtValue();
640 n = (n > suffix) ? n - suffix : 0;
641 }
642
643 for (unsigned i = 0; i < n; ++i)
644 if (str[i] == 'X') ++numX;
645
646 if (numX >= 6)
647 return;
648
649 // Issue a warning.
650 PathDiagnosticLocation CELoc =
651 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
652 SmallString<512> buf;
653 llvm::raw_svector_ostream out(buf);
654 out << "Call to '" << Name << "' should have at least 6 'X's in the"
655 " format string to be secure (" << numX << " 'X'";
656 if (numX != 1)
657 out << 's';
658 out << " seen";
659 if (suffix) {
660 out << ", " << suffix << " character";
661 if (suffix > 1)
662 out << 's';
663 out << " used as a suffix";
664 }
665 out << ')';
666 BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
667 "Insecure temporary file creation", "Security",
668 out.str(), CELoc, strArg->getSourceRange());
669}
670
671//===----------------------------------------------------------------------===//
672// Check: Any use of 'strcpy' is insecure.
673//
674// CWE-119: Improper Restriction of Operations within
675// the Bounds of a Memory Buffer
676//===----------------------------------------------------------------------===//
677
678void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
679 if (!filter.check_strcpy)
680 return;
681
682 if (!checkCall_strCommon(CE, FD))
683 return;
684
685 const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
686 *Source = CE->getArg(1)->IgnoreImpCasts();
687
688 if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
689 uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
690 if (const auto *String = dyn_cast<StringLiteral>(Source)) {
691 if (ArraySize >= String->getLength() + 1)
692 return;
693 }
694 }
695
696 // Issue a warning.
697 PathDiagnosticLocation CELoc =
698 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
699 BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
700 "Potential insecure memory buffer bounds restriction in "
701 "call 'strcpy'",
702 "Security",
703 "Call to function 'strcpy' is insecure as it does not "
704 "provide bounding of the memory buffer. Replace "
705 "unbounded copy functions with analogous functions that "
706 "support length arguments such as 'strlcpy'. CWE-119.",
707 CELoc, CE->getCallee()->getSourceRange());
708}
709
710//===----------------------------------------------------------------------===//
711// Check: Any use of 'strcat' is insecure.
712//
713// CWE-119: Improper Restriction of Operations within
714// the Bounds of a Memory Buffer
715//===----------------------------------------------------------------------===//
716
717void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
718 if (!filter.check_strcpy)
719 return;
720
721 if (!checkCall_strCommon(CE, FD))
722 return;
723
724 // Issue a warning.
725 PathDiagnosticLocation CELoc =
726 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
727 BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
728 "Potential insecure memory buffer bounds restriction in "
729 "call 'strcat'",
730 "Security",
731 "Call to function 'strcat' is insecure as it does not "
732 "provide bounding of the memory buffer. Replace "
733 "unbounded copy functions with analogous functions that "
734 "support length arguments such as 'strlcat'. CWE-119.",
735 CELoc, CE->getCallee()->getSourceRange());
736}
737
738//===----------------------------------------------------------------------===//
739// Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
740// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
741// 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
742// 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
743// is deprecated since C11.
744//
745// Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
746// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
747// 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
748// is insecure.
749//
750// CWE-119: Improper Restriction of Operations within
751// the Bounds of a Memory Buffer
752//===----------------------------------------------------------------------===//
753
754void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
755 const FunctionDecl *FD) {
756 if (!filter.check_DeprecatedOrUnsafeBufferHandling)
757 return;
758
759 if (!BR.getContext().getLangOpts().C11)
760 return;
761
762 // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
763 // restrictions).
764 enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
765
766 StringRef Name = FD->getIdentifier()->getName();
767 if (Name.startswith("__builtin_"))
768 Name = Name.substr(10);
769
770 int ArgIndex =
771 llvm::StringSwitch<int>(Name)
772 .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
773 .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
774 "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
775 .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
776 "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
777 .Default(UNKNOWN_CALL);
778
779 assert(ArgIndex != UNKNOWN_CALL && "Unsupported function")(static_cast<void> (0));
780 bool BoundsProvided = ArgIndex == DEPR_ONLY;
781
782 if (!BoundsProvided) {
783 // Currently we only handle (not wide) string literals. It is possible to do
784 // better, either by looking at references to const variables, or by doing
785 // real flow analysis.
786 auto FormatString =
787 dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
788 if (FormatString &&
789 FormatString->getString().find("%s") == StringRef::npos &&
790 FormatString->getString().find("%[") == StringRef::npos)
791 BoundsProvided = true;
792 }
793
794 SmallString<128> Buf1;
795 SmallString<512> Buf2;
796 llvm::raw_svector_ostream Out1(Buf1);
797 llvm::raw_svector_ostream Out2(Buf2);
798
799 Out1 << "Potential insecure memory buffer bounds restriction in call '"
800 << Name << "'";
801 Out2 << "Call to function '" << Name
802 << "' is insecure as it does not provide ";
803
804 if (!BoundsProvided) {
805 Out2 << "bounding of the memory buffer or ";
806 }
807
808 Out2 << "security checks introduced "
809 "in the C11 standard. Replace with analogous functions that "
810 "support length arguments or provides boundary checks such as '"
811 << Name << "_s' in case of C11";
812
813 PathDiagnosticLocation CELoc =
814 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
815 BR.EmitBasicReport(AC->getDecl(),
816 filter.checkName_DeprecatedOrUnsafeBufferHandling,
817 Out1.str(), "Security", Out2.str(), CELoc,
818 CE->getCallee()->getSourceRange());
819}
820
821//===----------------------------------------------------------------------===//
822// Common check for str* functions with no bounds parameters.
823//===----------------------------------------------------------------------===//
824
825bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
826 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
827 if (!FPT)
828 return false;
829
830 // Verify the function takes two arguments, three in the _chk version.
831 int numArgs = FPT->getNumParams();
832 if (numArgs != 2 && numArgs != 3)
833 return false;
834
835 // Verify the type for both arguments.
836 for (int i = 0; i < 2; i++) {
837 // Verify that the arguments are pointers.
838 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
839 if (!PT)
840 return false;
841
842 // Verify that the argument is a 'char*'.
843 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
844 return false;
845 }
846
847 return true;
848}
849
850//===----------------------------------------------------------------------===//
851// Check: Linear congruent random number generators should not be used
852// Originally: <rdar://problem/63371000>
853// CWE-338: Use of cryptographically weak prng
854//===----------------------------------------------------------------------===//
855
856void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
857 if (!filter.check_rand || !CheckRand)
858 return;
859
860 const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
861 if (!FTP)
862 return;
863
864 if (FTP->getNumParams() == 1) {
865 // Is the argument an 'unsigned short *'?
866 // (Actually any integer type is allowed.)
867 const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
868 if (!PT)
869 return;
870
871 if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
872 return;
873 } else if (FTP->getNumParams() != 0)
874 return;
875
876 // Issue a warning.
877 SmallString<256> buf1;
878 llvm::raw_svector_ostream os1(buf1);
879 os1 << '\'' << *FD << "' is a poor random number generator";
880
881 SmallString<256> buf2;
882 llvm::raw_svector_ostream os2(buf2);
883 os2 << "Function '" << *FD
884 << "' is obsolete because it implements a poor random number generator."
885 << " Use 'arc4random' instead";
886
887 PathDiagnosticLocation CELoc =
888 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
889 BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
890 "Security", os2.str(), CELoc,
891 CE->getCallee()->getSourceRange());
892}
893
894//===----------------------------------------------------------------------===//
895// Check: 'random' should not be used
896// Originally: <rdar://problem/63371000>
897//===----------------------------------------------------------------------===//
898
899void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
900 if (!CheckRand || !filter.check_rand)
901 return;
902
903 const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
904 if (!FTP)
905 return;
906
907 // Verify that the function takes no argument.
908 if (FTP->getNumParams() != 0)
909 return;
910
911 // Issue a warning.
912 PathDiagnosticLocation CELoc =
913 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
914 BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
915 "'random' is not a secure random number generator",
916 "Security",
917 "The 'random' function produces a sequence of values that "
918 "an adversary may be able to predict. Use 'arc4random' "
919 "instead", CELoc, CE->getCallee()->getSourceRange());
920}
921
922//===----------------------------------------------------------------------===//
923// Check: 'vfork' should not be used.
924// POS33-C: Do not use vfork().
925//===----------------------------------------------------------------------===//
926
927void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
928 if (!filter.check_vfork)
929 return;
930
931 // All calls to vfork() are insecure, issue a warning.
932 PathDiagnosticLocation CELoc =
933 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
934 BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
935 "Potential insecure implementation-specific behavior in "
936 "call 'vfork'",
937 "Security",
938 "Call to function 'vfork' is insecure as it can lead to "
939 "denial of service situations in the parent process. "
940 "Replace calls to vfork with calls to the safer "
941 "'posix_spawn' function",
942 CELoc, CE->getCallee()->getSourceRange());
943}
944
945//===----------------------------------------------------------------------===//
946// Check: '-decodeValueOfObjCType:at:' should not be used.
947// It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to
948// likelihood of buffer overflows.
949//===----------------------------------------------------------------------===//
950
951void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
952 if (!filter.check_decodeValueOfObjCType)
953 return;
954
955 // Check availability of the secure alternative:
956 // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
957 // FIXME: We probably shouldn't register the check if it's not available.
958 const TargetInfo &TI = AC->getASTContext().getTargetInfo();
959 const llvm::Triple &T = TI.getTriple();
960 const VersionTuple &VT = TI.getPlatformMinVersion();
961 switch (T.getOS()) {
962 case llvm::Triple::IOS:
963 if (VT < VersionTuple(11, 0))
964 return;
965 break;
966 case llvm::Triple::MacOSX:
967 if (VT < VersionTuple(10, 13))
968 return;
969 break;
970 case llvm::Triple::WatchOS:
971 if (VT < VersionTuple(4, 0))
972 return;
973 break;
974 case llvm::Triple::TvOS:
975 if (VT < VersionTuple(11, 0))
976 return;
977 break;
978 default:
979 return;
980 }
981
982 PathDiagnosticLocation MELoc =
983 PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
984 BR.EmitBasicReport(
985 AC->getDecl(), filter.checkName_decodeValueOfObjCType,
986 "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
987 "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
988 "as it can lead to potential buffer overflows. Use the safer "
989 "'-decodeValueOfObjCType:at:size:' method.",
990 MELoc, ME->getSourceRange());
991}
992
993//===----------------------------------------------------------------------===//
994// Check: Should check whether privileges are dropped successfully.
995// Originally: <rdar://problem/6337132>
996//===----------------------------------------------------------------------===//
997
998void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
999 if (!filter.check_UncheckedReturn)
1000 return;
1001
1002 const FunctionDecl *FD = CE->getDirectCallee();
1003 if (!FD)
1004 return;
1005
1006 if (II_setid[0] == nullptr) {
1007 static const char * const identifiers[num_setids] = {
1008 "setuid", "setgid", "seteuid", "setegid",
1009 "setreuid", "setregid"
1010 };
1011
1012 for (size_t i = 0; i < num_setids; i++)
1013 II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
1014 }
1015
1016 const IdentifierInfo *id = FD->getIdentifier();
1017 size_t identifierid;
1018
1019 for (identifierid = 0; identifierid < num_setids; identifierid++)
1020 if (id == II_setid[identifierid])
1021 break;
1022
1023 if (identifierid >= num_setids)
1024 return;
1025
1026 const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
1027 if (!FTP)
1028 return;
1029
1030 // Verify that the function takes one or two arguments (depending on
1031 // the function).
1032 if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
1033 return;
1034
1035 // The arguments must be integers.
1036 for (unsigned i = 0; i < FTP->getNumParams(); i++)
1037 if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
1038 return;
1039
1040 // Issue a warning.
1041 SmallString<256> buf1;
1042 llvm::raw_svector_ostream os1(buf1);
1043 os1 << "Return value is not checked in call to '" << *FD << '\'';
1044
1045 SmallString<256> buf2;
1046 llvm::raw_svector_ostream os2(buf2);
1047 os2 << "The return value from the call to '" << *FD
1048 << "' is not checked. If an error occurs in '" << *FD
1049 << "', the following code may execute with unexpected privileges";
1050
1051 PathDiagnosticLocation CELoc =
1052 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
1053 BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
1054 "Security", os2.str(), CELoc,
1055 CE->getCallee()->getSourceRange());
1056}
1057
1058//===----------------------------------------------------------------------===//
1059// SecuritySyntaxChecker
1060//===----------------------------------------------------------------------===//
1061
1062namespace {
1063class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
1064public:
1065 ChecksFilter filter;
1066
1067 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
1068 BugReporter &BR) const {
1069 WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1070 walker.Visit(D->getBody());
1071 }
1072};
1073}
1074
1075void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1076 mgr.registerChecker<SecuritySyntaxChecker>();
1077}
1078
1079bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {
1080 return true;
1081}
1082
1083#define REGISTER_CHECKER(name)void ento::registername(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_name = true; checker->filter.checkName_name
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistername
(const CheckerManager &mgr) { return true; }
\
1084 void ento::register##name(CheckerManager &mgr) { \
1085 SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
1086 checker->filter.check_##name = true; \
1087 checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \
1088 } \
1089 \
1090 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1091
1092REGISTER_CHECKER(bcmp)void ento::registerbcmp(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_bcmp = true; checker->filter.checkName_bcmp
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterbcmp
(const CheckerManager &mgr) { return true; }
1093REGISTER_CHECKER(bcopy)void ento::registerbcopy(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_bcopy = true; checker->filter.checkName_bcopy
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterbcopy
(const CheckerManager &mgr) { return true; }
1094REGISTER_CHECKER(bzero)void ento::registerbzero(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_bzero = true; checker->filter.checkName_bzero
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterbzero
(const CheckerManager &mgr) { return true; }
1095REGISTER_CHECKER(gets)void ento::registergets(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_gets = true; checker->filter.checkName_gets
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistergets
(const CheckerManager &mgr) { return true; }
1096REGISTER_CHECKER(getpw)void ento::registergetpw(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_getpw = true; checker->filter.checkName_getpw
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistergetpw
(const CheckerManager &mgr) { return true; }
1097REGISTER_CHECKER(mkstemp)void ento::registermkstemp(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_mkstemp = true; checker->filter.checkName_mkstemp
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistermkstemp
(const CheckerManager &mgr) { return true; }
1098REGISTER_CHECKER(mktemp)void ento::registermktemp(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_mktemp = true; checker->filter.checkName_mktemp
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistermktemp
(const CheckerManager &mgr) { return true; }
1099REGISTER_CHECKER(strcpy)void ento::registerstrcpy(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_strcpy = true; checker->filter.checkName_strcpy
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterstrcpy
(const CheckerManager &mgr) { return true; }
1100REGISTER_CHECKER(rand)void ento::registerrand(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_rand = true; checker->filter.checkName_rand
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterrand
(const CheckerManager &mgr) { return true; }
1101REGISTER_CHECKER(vfork)void ento::registervfork(CheckerManager &mgr) { SecuritySyntaxChecker
*checker = mgr.getChecker<SecuritySyntaxChecker>(); checker
->filter.check_vfork = true; checker->filter.checkName_vfork
= mgr.getCurrentCheckerName(); } bool ento::shouldRegistervfork
(const CheckerManager &mgr) { return true; }
1102REGISTER_CHECKER(FloatLoopCounter)void ento::registerFloatLoopCounter(CheckerManager &mgr) {
SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker
>(); checker->filter.check_FloatLoopCounter = true; checker
->filter.checkName_FloatLoopCounter = mgr.getCurrentCheckerName
(); } bool ento::shouldRegisterFloatLoopCounter(const CheckerManager
&mgr) { return true; }
1103REGISTER_CHECKER(UncheckedReturn)void ento::registerUncheckedReturn(CheckerManager &mgr) {
SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker
>(); checker->filter.check_UncheckedReturn = true; checker
->filter.checkName_UncheckedReturn = mgr.getCurrentCheckerName
(); } bool ento::shouldRegisterUncheckedReturn(const CheckerManager
&mgr) { return true; }
1104REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)void ento::registerDeprecatedOrUnsafeBufferHandling(CheckerManager
&mgr) { SecuritySyntaxChecker *checker = mgr.getChecker<
SecuritySyntaxChecker>(); checker->filter.check_DeprecatedOrUnsafeBufferHandling
= true; checker->filter.checkName_DeprecatedOrUnsafeBufferHandling
= mgr.getCurrentCheckerName(); } bool ento::shouldRegisterDeprecatedOrUnsafeBufferHandling
(const CheckerManager &mgr) { return true; }
1105REGISTER_CHECKER(decodeValueOfObjCType)void ento::registerdecodeValueOfObjCType(CheckerManager &
mgr) { SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker
>(); checker->filter.check_decodeValueOfObjCType = true
; checker->filter.checkName_decodeValueOfObjCType = mgr.getCurrentCheckerName
(); } bool ento::shouldRegisterdecodeValueOfObjCType(const CheckerManager
&mgr) { return true; }