clang 18.0.0git
CheckSecuritySyntaxOnly.cpp
Go to the documentation of this file.
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
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.isOSFreeBSD() ||
31 T.isOSNetBSD() ||
32 T.isOSOpenBSD() ||
33 T.isOSDragonFly();
34}
35
36namespace {
37struct ChecksFilter {
38 bool check_bcmp = false;
39 bool check_bcopy = false;
40 bool check_bzero = false;
41 bool check_gets = false;
42 bool check_getpw = false;
43 bool check_mktemp = false;
44 bool check_mkstemp = false;
45 bool check_strcpy = false;
46 bool check_DeprecatedOrUnsafeBufferHandling = false;
47 bool check_rand = false;
48 bool check_vfork = false;
49 bool check_FloatLoopCounter = false;
50 bool check_UncheckedReturn = false;
51 bool check_decodeValueOfObjCType = false;
52
53 CheckerNameRef checkName_bcmp;
54 CheckerNameRef checkName_bcopy;
55 CheckerNameRef checkName_bzero;
56 CheckerNameRef checkName_gets;
57 CheckerNameRef checkName_getpw;
58 CheckerNameRef checkName_mktemp;
59 CheckerNameRef checkName_mkstemp;
60 CheckerNameRef checkName_strcpy;
61 CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
62 CheckerNameRef checkName_rand;
63 CheckerNameRef checkName_vfork;
64 CheckerNameRef checkName_FloatLoopCounter;
65 CheckerNameRef checkName_UncheckedReturn;
66 CheckerNameRef checkName_decodeValueOfObjCType;
67};
68
69class WalkAST : public StmtVisitor<WalkAST> {
70 BugReporter &BR;
72 enum { num_setids = 6 };
73 IdentifierInfo *II_setid[num_setids];
74
75 const bool CheckRand;
76 const ChecksFilter &filter;
77
78public:
79 WalkAST(BugReporter &br, AnalysisDeclContext* ac,
80 const ChecksFilter &f)
81 : BR(br), AC(ac), II_setid(),
82 CheckRand(isArc4RandomAvailable(BR.getContext())),
83 filter(f) {}
84
85 // Statement visitor methods.
86 void VisitCallExpr(CallExpr *CE);
87 void VisitObjCMessageExpr(ObjCMessageExpr *CE);
88 void VisitForStmt(ForStmt *S);
89 void VisitCompoundStmt (CompoundStmt *S);
90 void VisitStmt(Stmt *S) { VisitChildren(S); }
91
92 void VisitChildren(Stmt *S);
93
94 // Helpers.
95 bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
96
97 typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
98 typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
99
100 // Checker-specific methods.
101 void checkLoopConditionForFloat(const ForStmt *FS);
102 void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
103 void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
104 void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
105 void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
106 void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
107 void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
108 void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
109 void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
110 void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
111 void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
112 const FunctionDecl *FD);
113 void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
114 void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
115 void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
116 void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
117 void checkUncheckedReturnValue(CallExpr *CE);
118};
119} // end anonymous namespace
120
121//===----------------------------------------------------------------------===//
122// AST walking.
123//===----------------------------------------------------------------------===//
124
125void WalkAST::VisitChildren(Stmt *S) {
126 for (Stmt *Child : S->children())
127 if (Child)
128 Visit(Child);
129}
130
131void WalkAST::VisitCallExpr(CallExpr *CE) {
132 // Get the callee.
133 const FunctionDecl *FD = CE->getDirectCallee();
134
135 if (!FD)
136 return;
137
138 // Get the name of the callee. If it's a builtin, strip off the prefix.
139 IdentifierInfo *II = FD->getIdentifier();
140 if (!II) // if no identifier, not a simple C function
141 return;
142 StringRef Name = II->getName();
143 if (Name.startswith("__builtin_"))
144 Name = Name.substr(10);
145
146 // Set the evaluation function by switching on the callee name.
147 FnCheck evalFunction =
148 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", "fprintf",
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);
215
216 // Recurse and check children.
217 VisitChildren(FS);
218}
219
220//===----------------------------------------------------------------------===//
221// Check: floating point variable used as loop counter.
222// Implements: CERT security coding advisory FLP-30.
223//===----------------------------------------------------------------------===//
224
225// Returns either 'x' or 'y', depending on which one of them is incremented
226// in 'expr', or nullptr if none of them is incremented.
227static const DeclRefExpr*
228getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
229 expr = expr->IgnoreParenCasts();
230
231 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
232 if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
233 B->getOpcode() == BO_Comma))
234 return nullptr;
235
236 if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
237 return lhs;
238
239 if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
240 return rhs;
241
242 return nullptr;
243 }
244
245 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
246 const NamedDecl *ND = DR->getDecl();
247 return ND == x || ND == y ? DR : nullptr;
248 }
249
250 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
251 return U->isIncrementDecrementOp()
252 ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
253
254 return nullptr;
255}
256
257/// CheckLoopConditionForFloat - This check looks for 'for' statements that
258/// use a floating point variable as a loop counter.
259/// CERT: FLP30-C, FLP30-CPP.
260///
261void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
262 if (!filter.check_FloatLoopCounter)
263 return;
264
265 // Does the loop have a condition?
266 const Expr *condition = FS->getCond();
267
268 if (!condition)
269 return;
270
271 // Does the loop have an increment?
272 const Expr *increment = FS->getInc();
273
274 if (!increment)
275 return;
276
277 // Strip away '()' and casts.
278 condition = condition->IgnoreParenCasts();
279 increment = increment->IgnoreParenCasts();
280
281 // Is the loop condition a comparison?
282 const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
283
284 if (!B)
285 return;
286
287 // Is this a comparison?
288 if (!(B->isRelationalOp() || B->isEqualityOp()))
289 return;
290
291 // Are we comparing variables?
292 const DeclRefExpr *drLHS =
293 dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
294 const DeclRefExpr *drRHS =
295 dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
296
297 // Does at least one of the variables have a floating point type?
298 drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
299 drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
300
301 if (!drLHS && !drRHS)
302 return;
303
304 const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
305 const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
306
307 if (!vdLHS && !vdRHS)
308 return;
309
310 // Does either variable appear in increment?
311 const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
312 if (!drInc)
313 return;
314
315 const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
316 assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
317
318 // Emit the error. First figure out which DeclRefExpr in the condition
319 // referenced the compared variable.
320 const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
321
323 SmallString<256> sbuf;
324 llvm::raw_svector_ostream os(sbuf);
325
326 os << "Variable '" << drCond->getDecl()->getName()
327 << "' with floating point type '" << drCond->getType()
328 << "' should not be used as a loop counter";
329
330 ranges.push_back(drCond->getSourceRange());
331 ranges.push_back(drInc->getSourceRange());
332
333 const char *bugType = "Floating point variable used as loop counter";
334
336 PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
337 BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
338 bugType, "Security", os.str(),
339 FSLoc, ranges);
340}
341
342//===----------------------------------------------------------------------===//
343// Check: Any use of bcmp.
344// CWE-477: Use of Obsolete Functions
345// bcmp was deprecated in POSIX.1-2008
346//===----------------------------------------------------------------------===//
347
348void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
349 if (!filter.check_bcmp)
350 return;
351
352 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
353 if (!FPT)
354 return;
355
356 // Verify that the function takes three arguments.
357 if (FPT->getNumParams() != 3)
358 return;
359
360 for (int i = 0; i < 2; i++) {
361 // Verify the first and second argument type is void*.
362 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
363 if (!PT)
364 return;
365
366 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
367 return;
368 }
369
370 // Verify the third argument type is integer.
372 return;
373
374 // Issue a warning.
376 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
377 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
378 "Use of deprecated function in call to 'bcmp()'",
379 "Security",
380 "The bcmp() function is obsoleted by memcmp().",
381 CELoc, CE->getCallee()->getSourceRange());
382}
383
384//===----------------------------------------------------------------------===//
385// Check: Any use of bcopy.
386// CWE-477: Use of Obsolete Functions
387// bcopy was deprecated in POSIX.1-2008
388//===----------------------------------------------------------------------===//
389
390void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
391 if (!filter.check_bcopy)
392 return;
393
394 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
395 if (!FPT)
396 return;
397
398 // Verify that the function takes three arguments.
399 if (FPT->getNumParams() != 3)
400 return;
401
402 for (int i = 0; i < 2; i++) {
403 // Verify the first and second argument type is void*.
404 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
405 if (!PT)
406 return;
407
408 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
409 return;
410 }
411
412 // Verify the third argument type is integer.
414 return;
415
416 // Issue a warning.
418 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
419 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
420 "Use of deprecated function in call to 'bcopy()'",
421 "Security",
422 "The bcopy() function is obsoleted by memcpy() "
423 "or memmove().",
424 CELoc, CE->getCallee()->getSourceRange());
425}
426
427//===----------------------------------------------------------------------===//
428// Check: Any use of bzero.
429// CWE-477: Use of Obsolete Functions
430// bzero was deprecated in POSIX.1-2008
431//===----------------------------------------------------------------------===//
432
433void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
434 if (!filter.check_bzero)
435 return;
436
437 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
438 if (!FPT)
439 return;
440
441 // Verify that the function takes two arguments.
442 if (FPT->getNumParams() != 2)
443 return;
444
445 // Verify the first argument type is void*.
446 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
447 if (!PT)
448 return;
449
450 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
451 return;
452
453 // Verify the second argument type is integer.
455 return;
456
457 // Issue a warning.
459 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
460 BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
461 "Use of deprecated function in call to 'bzero()'",
462 "Security",
463 "The bzero() function is obsoleted by memset().",
464 CELoc, CE->getCallee()->getSourceRange());
465}
466
467
468//===----------------------------------------------------------------------===//
469// Check: Any use of 'gets' is insecure. Most man pages literally says this.
470//
471// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
472// CWE-242: Use of Inherently Dangerous Function
473//===----------------------------------------------------------------------===//
474
475void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
476 if (!filter.check_gets)
477 return;
478
479 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
480 if (!FPT)
481 return;
482
483 // Verify that the function takes a single argument.
484 if (FPT->getNumParams() != 1)
485 return;
486
487 // Is the argument a 'char*'?
488 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
489 if (!PT)
490 return;
491
492 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
493 return;
494
495 // Issue a warning.
497 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
498 BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
499 "Potential buffer overflow in call to 'gets'",
500 "Security",
501 "Call to function 'gets' is extremely insecure as it can "
502 "always result in a buffer overflow",
503 CELoc, CE->getCallee()->getSourceRange());
504}
505
506//===----------------------------------------------------------------------===//
507// Check: Any use of 'getpwd' is insecure.
508// CWE-477: Use of Obsolete Functions
509//===----------------------------------------------------------------------===//
510
511void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
512 if (!filter.check_getpw)
513 return;
514
515 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
516 if (!FPT)
517 return;
518
519 // Verify that the function takes two arguments.
520 if (FPT->getNumParams() != 2)
521 return;
522
523 // Verify the first argument type is integer.
525 return;
526
527 // Verify the second argument type is char*.
528 const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
529 if (!PT)
530 return;
531
532 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
533 return;
534
535 // Issue a warning.
537 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
538 BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
539 "Potential buffer overflow in call to 'getpw'",
540 "Security",
541 "The getpw() function is dangerous as it may overflow the "
542 "provided buffer. It is obsoleted by getpwuid().",
543 CELoc, CE->getCallee()->getSourceRange());
544}
545
546//===----------------------------------------------------------------------===//
547// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
548// CWE-377: Insecure Temporary File
549//===----------------------------------------------------------------------===//
550
551void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
552 if (!filter.check_mktemp) {
553 // Fall back to the security check of looking for enough 'X's in the
554 // format string, since that is a less severe warning.
555 checkCall_mkstemp(CE, FD);
556 return;
557 }
558
559 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
560 if(!FPT)
561 return;
562
563 // Verify that the function takes a single argument.
564 if (FPT->getNumParams() != 1)
565 return;
566
567 // Verify that the argument is Pointer Type.
568 const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
569 if (!PT)
570 return;
571
572 // Verify that the argument is a 'char*'.
573 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
574 return;
575
576 // Issue a warning.
578 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
579 BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
580 "Potential insecure temporary file in call 'mktemp'",
581 "Security",
582 "Call to function 'mktemp' is insecure as it always "
583 "creates or uses insecure temporary file. Use 'mkstemp' "
584 "instead",
585 CELoc, CE->getCallee()->getSourceRange());
586}
587
588//===----------------------------------------------------------------------===//
589// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
590//===----------------------------------------------------------------------===//
591
592void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
593 if (!filter.check_mkstemp)
594 return;
595
596 StringRef Name = FD->getIdentifier()->getName();
597 std::pair<signed, signed> ArgSuffix =
598 llvm::StringSwitch<std::pair<signed, signed> >(Name)
599 .Case("mktemp", std::make_pair(0,-1))
600 .Case("mkstemp", std::make_pair(0,-1))
601 .Case("mkdtemp", std::make_pair(0,-1))
602 .Case("mkstemps", std::make_pair(0,1))
603 .Default(std::make_pair(-1, -1));
604
605 assert(ArgSuffix.first >= 0 && "Unsupported function");
606
607 // Check if the number of arguments is consistent with out expectations.
608 unsigned numArgs = CE->getNumArgs();
609 if ((signed) numArgs <= ArgSuffix.first)
610 return;
611
612 const StringLiteral *strArg =
613 dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
615
616 // Currently we only handle string literals. It is possible to do better,
617 // either by looking at references to const variables, or by doing real
618 // flow analysis.
619 if (!strArg || strArg->getCharByteWidth() != 1)
620 return;
621
622 // Count the number of X's, taking into account a possible cutoff suffix.
623 StringRef str = strArg->getString();
624 unsigned numX = 0;
625 unsigned n = str.size();
626
627 // Take into account the suffix.
628 unsigned suffix = 0;
629 if (ArgSuffix.second >= 0) {
630 const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
631 Expr::EvalResult EVResult;
632 if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
633 return;
634 llvm::APSInt Result = EVResult.Val.getInt();
635 // FIXME: Issue a warning.
636 if (Result.isNegative())
637 return;
638 suffix = (unsigned) Result.getZExtValue();
639 n = (n > suffix) ? n - suffix : 0;
640 }
641
642 for (unsigned i = 0; i < n; ++i)
643 if (str[i] == 'X') ++numX;
644
645 if (numX >= 6)
646 return;
647
648 // Issue a warning.
650 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
652 llvm::raw_svector_ostream out(buf);
653 out << "Call to '" << Name << "' should have at least 6 'X's in the"
654 " format string to be secure (" << numX << " 'X'";
655 if (numX != 1)
656 out << 's';
657 out << " seen";
658 if (suffix) {
659 out << ", " << suffix << " character";
660 if (suffix > 1)
661 out << 's';
662 out << " used as a suffix";
663 }
664 out << ')';
665 BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
666 "Insecure temporary file creation", "Security",
667 out.str(), CELoc, strArg->getSourceRange());
668}
669
670//===----------------------------------------------------------------------===//
671// Check: Any use of 'strcpy' is insecure.
672//
673// CWE-119: Improper Restriction of Operations within
674// the Bounds of a Memory Buffer
675//===----------------------------------------------------------------------===//
676
677void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
678 if (!filter.check_strcpy)
679 return;
680
681 if (!checkCall_strCommon(CE, FD))
682 return;
683
684 const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
685 *Source = CE->getArg(1)->IgnoreImpCasts();
686
687 if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
688 uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
689 if (const auto *String = dyn_cast<StringLiteral>(Source)) {
690 if (ArraySize >= String->getLength() + 1)
691 return;
692 }
693 }
694
695 // Issue a warning.
697 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
698 BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
699 "Potential insecure memory buffer bounds restriction in "
700 "call 'strcpy'",
701 "Security",
702 "Call to function 'strcpy' is insecure as it does not "
703 "provide bounding of the memory buffer. Replace "
704 "unbounded copy functions with analogous functions that "
705 "support length arguments such as 'strlcpy'. CWE-119.",
706 CELoc, CE->getCallee()->getSourceRange());
707}
708
709//===----------------------------------------------------------------------===//
710// Check: Any use of 'strcat' is insecure.
711//
712// CWE-119: Improper Restriction of Operations within
713// the Bounds of a Memory Buffer
714//===----------------------------------------------------------------------===//
715
716void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
717 if (!filter.check_strcpy)
718 return;
719
720 if (!checkCall_strCommon(CE, FD))
721 return;
722
723 // Issue a warning.
725 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
726 BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
727 "Potential insecure memory buffer bounds restriction in "
728 "call 'strcat'",
729 "Security",
730 "Call to function 'strcat' is insecure as it does not "
731 "provide bounding of the memory buffer. Replace "
732 "unbounded copy functions with analogous functions that "
733 "support length arguments such as 'strlcat'. CWE-119.",
734 CELoc, CE->getCallee()->getSourceRange());
735}
736
737//===----------------------------------------------------------------------===//
738// Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
739// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
740// 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
741// 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset',
742// 'fprintf' is deprecated since C11.
743//
744// Use of 'sprintf', 'fprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
745// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
746// 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
747// is insecure.
748//
749// CWE-119: Improper Restriction of Operations within
750// the Bounds of a Memory Buffer
751//===----------------------------------------------------------------------===//
752
753void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
754 const FunctionDecl *FD) {
755 if (!filter.check_DeprecatedOrUnsafeBufferHandling)
756 return;
757
758 if (!BR.getContext().getLangOpts().C11)
759 return;
760
761 // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
762 // restrictions).
763 enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
764
765 StringRef Name = FD->getIdentifier()->getName();
766 if (Name.startswith("__builtin_"))
767 Name = Name.substr(10);
768
769 int ArgIndex =
770 llvm::StringSwitch<int>(Name)
771 .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
772 .Cases("fscanf", "fwscanf", "vfscanf", "vfwscanf", "sscanf",
773 "swscanf", "vsscanf", "vswscanf", 1)
774 .Cases("sprintf", "vsprintf", "fprintf", 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");
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 && !FormatString->getString().contains("%s") &&
789 !FormatString->getString().contains("%["))
790 BoundsProvided = true;
791 }
792
793 SmallString<128> Buf1;
794 SmallString<512> Buf2;
795 llvm::raw_svector_ostream Out1(Buf1);
796 llvm::raw_svector_ostream Out2(Buf2);
797
798 Out1 << "Potential insecure memory buffer bounds restriction in call '"
799 << Name << "'";
800 Out2 << "Call to function '" << Name
801 << "' is insecure as it does not provide ";
802
803 if (!BoundsProvided) {
804 Out2 << "bounding of the memory buffer or ";
805 }
806
807 Out2 << "security checks introduced "
808 "in the C11 standard. Replace with analogous functions that "
809 "support length arguments or provides boundary checks such as '"
810 << Name << "_s' in case of C11";
811
813 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
814 BR.EmitBasicReport(AC->getDecl(),
815 filter.checkName_DeprecatedOrUnsafeBufferHandling,
816 Out1.str(), "Security", Out2.str(), CELoc,
817 CE->getCallee()->getSourceRange());
818}
819
820//===----------------------------------------------------------------------===//
821// Common check for str* functions with no bounds parameters.
822//===----------------------------------------------------------------------===//
823
824bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
825 const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
826 if (!FPT)
827 return false;
828
829 // Verify the function takes two arguments, three in the _chk version.
830 int numArgs = FPT->getNumParams();
831 if (numArgs != 2 && numArgs != 3)
832 return false;
833
834 // Verify the type for both arguments.
835 for (int i = 0; i < 2; i++) {
836 // Verify that the arguments are pointers.
837 const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
838 if (!PT)
839 return false;
840
841 // Verify that the argument is a 'char*'.
842 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
843 return false;
844 }
845
846 return true;
847}
848
849//===----------------------------------------------------------------------===//
850// Check: Linear congruent random number generators should not be used,
851// i.e. rand(), random().
852//
853// E. Bach, "Efficient prediction of Marsaglia-Zaman random number generators,"
854// in IEEE Transactions on Information Theory, vol. 44, no. 3, pp. 1253-1257,
855// May 1998, https://doi.org/10.1109/18.669305
856//
857// CWE-338: Use of cryptographically weak prng
858//===----------------------------------------------------------------------===//
859
860void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
861 if (!filter.check_rand || !CheckRand)
862 return;
863
864 const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
865 if (!FTP)
866 return;
867
868 if (FTP->getNumParams() == 1) {
869 // Is the argument an 'unsigned short *'?
870 // (Actually any integer type is allowed.)
871 const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
872 if (!PT)
873 return;
874
876 return;
877 } else if (FTP->getNumParams() != 0)
878 return;
879
880 // Issue a warning.
881 SmallString<256> buf1;
882 llvm::raw_svector_ostream os1(buf1);
883 os1 << '\'' << *FD << "' is a poor random number generator";
884
885 SmallString<256> buf2;
886 llvm::raw_svector_ostream os2(buf2);
887 os2 << "Function '" << *FD
888 << "' is obsolete because it implements a poor random number generator."
889 << " Use 'arc4random' instead";
890
892 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
893 BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
894 "Security", os2.str(), CELoc,
895 CE->getCallee()->getSourceRange());
896}
897
898// See justification for rand().
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.
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.
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
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: The caller should always verify that the privileges
995// were dropped successfully.
996//
997// Some library functions, like setuid() and setgid(), should always be used
998// with a check of the return value to verify that the function completed
999// successfully. If the drop fails, the software will continue to run
1000// with the raised privileges, which might provide additional access
1001// to unprivileged users.
1002//
1003// (Note that this check predates __attribute__((warn_unused_result)).
1004// Do we still need it now that we have a compiler warning for this?
1005// Are these standard functions already annotated this way?)
1006//===----------------------------------------------------------------------===//
1007
1008void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
1009 if (!filter.check_UncheckedReturn)
1010 return;
1011
1012 const FunctionDecl *FD = CE->getDirectCallee();
1013 if (!FD)
1014 return;
1015
1016 if (II_setid[0] == nullptr) {
1017 static const char * const identifiers[num_setids] = {
1018 "setuid", "setgid", "seteuid", "setegid",
1019 "setreuid", "setregid"
1020 };
1021
1022 for (size_t i = 0; i < num_setids; i++)
1023 II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
1024 }
1025
1026 const IdentifierInfo *id = FD->getIdentifier();
1027 size_t identifierid;
1028
1029 for (identifierid = 0; identifierid < num_setids; identifierid++)
1030 if (id == II_setid[identifierid])
1031 break;
1032
1033 if (identifierid >= num_setids)
1034 return;
1035
1036 const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
1037 if (!FTP)
1038 return;
1039
1040 // Verify that the function takes one or two arguments (depending on
1041 // the function).
1042 if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
1043 return;
1044
1045 // The arguments must be integers.
1046 for (unsigned i = 0; i < FTP->getNumParams(); i++)
1048 return;
1049
1050 // Issue a warning.
1051 SmallString<256> buf1;
1052 llvm::raw_svector_ostream os1(buf1);
1053 os1 << "Return value is not checked in call to '" << *FD << '\'';
1054
1055 SmallString<256> buf2;
1056 llvm::raw_svector_ostream os2(buf2);
1057 os2 << "The return value from the call to '" << *FD
1058 << "' is not checked. If an error occurs in '" << *FD
1059 << "', the following code may execute with unexpected privileges";
1060
1062 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
1063 BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
1064 "Security", os2.str(), CELoc,
1065 CE->getCallee()->getSourceRange());
1066}
1067
1068//===----------------------------------------------------------------------===//
1069// SecuritySyntaxChecker
1070//===----------------------------------------------------------------------===//
1071
1072namespace {
1073class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
1074public:
1075 ChecksFilter filter;
1076
1077 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
1078 BugReporter &BR) const {
1079 WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1080 walker.Visit(D->getBody());
1081 }
1082};
1083}
1084
1085void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1086 mgr.registerChecker<SecuritySyntaxChecker>();
1087}
1088
1089bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {
1090 return true;
1091}
1092
1093#define REGISTER_CHECKER(name) \
1094 void ento::register##name(CheckerManager &mgr) { \
1095 SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
1096 checker->filter.check_##name = true; \
1097 checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \
1098 } \
1099 \
1100 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1101
1102REGISTER_CHECKER(bcmp)
1103REGISTER_CHECKER(bcopy)
1104REGISTER_CHECKER(bzero)
1105REGISTER_CHECKER(gets)
1106REGISTER_CHECKER(getpw)
1107REGISTER_CHECKER(mkstemp)
1108REGISTER_CHECKER(mktemp)
1109REGISTER_CHECKER(strcpy)
1110REGISTER_CHECKER(rand)
1111REGISTER_CHECKER(vfork)
1112REGISTER_CHECKER(FloatLoopCounter)
1113REGISTER_CHECKER(UncheckedReturn)
1114REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
1115REGISTER_CHECKER(decodeValueOfObjCType)
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
#define REGISTER_CHECKER(name)
static const DeclRefExpr * getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y)
static bool isArc4RandomAvailable(const ASTContext &Ctx)
APSInt & getInt()
Definition: APValue.h:423
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:749
AnalysisDeclContext contains the context data for the function, method or block under analysis.
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3862
Expr * getLHS() const
Definition: Expr.h:3911
static bool isRelationalOp(Opcode Opc)
Definition: Expr.h:3955
Expr * getRHS() const
Definition: Expr.h:3913
static bool isEqualityOp(Opcode Opc)
Definition: Expr.h:3958
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2847
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3038
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3017
Expr * getCallee()
Definition: Expr.h:2997
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3025
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1602
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1248
ValueDecl * getDecl()
Definition: Expr.h:1316
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1076
This represents one expression.
Definition: Expr.h:110
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:3036
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
Definition: Expr.cpp:3048
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3031
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3011
QualType getType() const
Definition: Expr.h:142
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition: Stmt.h:2775
Represents a function declaration or definition.
Definition: Decl.h:1957
Represents a prototype with parameter type info, e.g.
Definition: Type.h:4160
unsigned getNumParams() const
Definition: Type.h:4377
QualType getParamType(unsigned i) const
Definition: Type.h:4379
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
This represents a decl that may have a name.
Definition: Decl.h:248
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:269
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:275
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:945
Selector getSelector() const
Definition: ExprObjC.cpp:293
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2896
QualType getPointeeType() const
Definition: Type.h:2906
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:6874
std::string getAsString() const
Derive the full selector name (e.g.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:184
Stmt - This represents one statement.
Definition: Stmt.h:84
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:325
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1812
StringRef getString() const
Definition: Expr.h:1889
unsigned getCharByteWidth() const
Definition: Expr.h:1919
Exposes information about the current target.
Definition: TargetInfo.h:212
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1218
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
Definition: TargetInfo.h:1573
bool isIntegralOrUnscopedEnumerationType() const
Determine whether this type is an integral or unscoped enumeration type.
Definition: Type.cpp:2008
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2203
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7558
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2210
QualType getType() const
Definition: Decl.h:715
Represents a variable declaration or definition.
Definition: Decl.h:916
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:584
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Defines the clang::TargetInfo interface.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
unsigned long uint64_t
EvalResult is a struct with detailed info about an evaluated expression.
Definition: Expr.h:629
APValue Val
Val - This is the value the expression can be folded to.
Definition: Expr.h:631