blob: 0b75bd0bb2547c5192dc5d9b8df075f2dce20f5c [file] [log] [blame]
Ted Kremenekdbfb5f82009-07-23 01:07:19 +00001//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a set of flow-insensitive security checks.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Analysis/PathSensitive/BugReporter.h"
15#include "clang/Analysis/LocalCheckers.h"
16#include "clang/AST/StmtVisitor.h"
Ted Kremenek8baf86d2009-07-23 21:34:35 +000017#include "llvm/Support/raw_ostream.h"
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000018
19using namespace clang;
20
21namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000022class WalkAST : public StmtVisitor<WalkAST> {
Mike Stump1eb44332009-09-09 15:08:12 +000023 BugReporter &BR;
Ted Kremenek65a81a92009-08-28 00:08:09 +000024 IdentifierInfo *II_gets;
Zhongxing Xubd842e32009-11-09 12:19:26 +000025 IdentifierInfo *II_getpw;
Ted Kremenek24650472009-09-02 02:47:41 +000026 enum { num_rands = 9 };
27 IdentifierInfo *II_rand[num_rands];
28 IdentifierInfo *II_random;
29 enum { num_setids = 6 };
30 IdentifierInfo *II_setid[num_setids];
Mike Stump1eb44332009-09-09 15:08:12 +000031
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000032public:
Ted Kremenekefcbb152009-07-23 22:29:41 +000033 WalkAST(BugReporter &br) : BR(br),
Zhongxing Xubd842e32009-11-09 12:19:26 +000034 II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {}
Mike Stump1eb44332009-09-09 15:08:12 +000035
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000036 // Statement visitor methods.
Ted Kremenekefcbb152009-07-23 22:29:41 +000037 void VisitCallExpr(CallExpr *CE);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000038 void VisitForStmt(ForStmt *S);
Ted Kremenek65a81a92009-08-28 00:08:09 +000039 void VisitCompoundStmt (CompoundStmt *S);
Ted Kremenek8baf86d2009-07-23 21:34:35 +000040 void VisitStmt(Stmt *S) { VisitChildren(S); }
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000041
42 void VisitChildren(Stmt *S);
Mike Stump1eb44332009-09-09 15:08:12 +000043
Ted Kremenekefcbb152009-07-23 22:29:41 +000044 // Helpers.
45 IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
Mike Stump1eb44332009-09-09 15:08:12 +000046
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000047 // Checker-specific methods.
Ted Kremenek8baf86d2009-07-23 21:34:35 +000048 void CheckLoopConditionForFloat(const ForStmt *FS);
Ted Kremenekefcbb152009-07-23 22:29:41 +000049 void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
Zhongxing Xubd842e32009-11-09 12:19:26 +000050 void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
Ted Kremenek24650472009-09-02 02:47:41 +000051 void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
52 void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
Ted Kremenek65a81a92009-08-28 00:08:09 +000053 void CheckUncheckedReturnValue(CallExpr *CE);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000054};
55} // end anonymous namespace
56
57//===----------------------------------------------------------------------===//
Ted Kremenekefcbb152009-07-23 22:29:41 +000058// Helper methods.
59//===----------------------------------------------------------------------===//
60
61IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
62 if (!II)
63 II = &BR.getContext().Idents.get(str);
Mike Stump1eb44332009-09-09 15:08:12 +000064
65 return II;
Ted Kremenekefcbb152009-07-23 22:29:41 +000066}
67
68//===----------------------------------------------------------------------===//
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000069// AST walking.
70//===----------------------------------------------------------------------===//
71
72void WalkAST::VisitChildren(Stmt *S) {
73 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
74 if (Stmt *child = *I)
75 Visit(child);
76}
77
Ted Kremenekefcbb152009-07-23 22:29:41 +000078void WalkAST::VisitCallExpr(CallExpr *CE) {
79 if (const FunctionDecl *FD = CE->getDirectCallee()) {
Ted Kremenek24650472009-09-02 02:47:41 +000080 CheckCall_gets(CE, FD);
Zhongxing Xubd842e32009-11-09 12:19:26 +000081 CheckCall_getpw(CE, FD);
Ted Kremenek24650472009-09-02 02:47:41 +000082 CheckCall_rand(CE, FD);
83 CheckCall_random(CE, FD);
Ted Kremenekefcbb152009-07-23 22:29:41 +000084 }
Mike Stump1eb44332009-09-09 15:08:12 +000085
Ted Kremenekefcbb152009-07-23 22:29:41 +000086 // Recurse and check children.
87 VisitChildren(CE);
88}
89
Ted Kremenek65a81a92009-08-28 00:08:09 +000090void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
91 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
Mike Stump1eb44332009-09-09 15:08:12 +000092 if (Stmt *child = *I) {
93 if (CallExpr *CE = dyn_cast<CallExpr>(child))
94 CheckUncheckedReturnValue(CE);
95 Visit(child);
96 }
Ted Kremenek65a81a92009-08-28 00:08:09 +000097}
98
Ted Kremenek8baf86d2009-07-23 21:34:35 +000099void WalkAST::VisitForStmt(ForStmt *FS) {
Mike Stump1eb44332009-09-09 15:08:12 +0000100 CheckLoopConditionForFloat(FS);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000101
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000102 // Recurse and check children.
103 VisitChildren(FS);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000104}
105
106//===----------------------------------------------------------------------===//
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000107// Check: floating poing variable used as loop counter.
Ted Kremenek5abeb522009-07-23 21:44:18 +0000108// Originally: <rdar://problem/6336718>
109// Implements: CERT security coding advisory FLP-30.
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000110//===----------------------------------------------------------------------===//
111
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000112static const DeclRefExpr*
113GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
114 expr = expr->IgnoreParenCasts();
Mike Stump1eb44332009-09-09 15:08:12 +0000115
116 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000117 if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
118 B->getOpcode() == BinaryOperator::Comma))
119 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000120
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000121 if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
122 return lhs;
Mike Stump1eb44332009-09-09 15:08:12 +0000123
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000124 if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
125 return rhs;
Mike Stump1eb44332009-09-09 15:08:12 +0000126
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000127 return NULL;
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000128 }
Mike Stump1eb44332009-09-09 15:08:12 +0000129
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000130 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
131 const NamedDecl *ND = DR->getDecl();
132 return ND == x || ND == y ? DR : NULL;
133 }
Mike Stump1eb44332009-09-09 15:08:12 +0000134
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000135 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
136 return U->isIncrementDecrementOp()
137 ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
138
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000139 return NULL;
140}
141
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000142/// CheckLoopConditionForFloat - This check looks for 'for' statements that
143/// use a floating point variable as a loop counter.
144/// CERT: FLP30-C, FLP30-CPP.
145///
146void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
147 // Does the loop have a condition?
148 const Expr *condition = FS->getCond();
Mike Stump1eb44332009-09-09 15:08:12 +0000149
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000150 if (!condition)
151 return;
152
153 // Does the loop have an increment?
154 const Expr *increment = FS->getInc();
Mike Stump1eb44332009-09-09 15:08:12 +0000155
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000156 if (!increment)
157 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000158
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000159 // Strip away '()' and casts.
160 condition = condition->IgnoreParenCasts();
161 increment = increment->IgnoreParenCasts();
Mike Stump1eb44332009-09-09 15:08:12 +0000162
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000163 // Is the loop condition a comparison?
164 const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
165
166 if (!B)
167 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000168
Ted Kremenekcad9f412009-07-24 20:26:31 +0000169 // Is this a comparison?
170 if (!(B->isRelationalOp() || B->isEqualityOp()))
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000171 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000172
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000173 // Are we comparing variables?
174 const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
175 const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());
Mike Stump1eb44332009-09-09 15:08:12 +0000176
Ted Kremenekcad9f412009-07-24 20:26:31 +0000177 // Does at least one of the variables have a floating point type?
178 drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL;
179 drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000180
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000181 if (!drLHS && !drRHS)
182 return;
183
184 const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
185 const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000186
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000187 if (!vdLHS && !vdRHS)
Mike Stump1eb44332009-09-09 15:08:12 +0000188 return;
189
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000190 // Does either variable appear in increment?
191 const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
Mike Stump1eb44332009-09-09 15:08:12 +0000192
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000193 if (!drInc)
194 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000195
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000196 // Emit the error. First figure out which DeclRefExpr in the condition
197 // referenced the compared variable.
198 const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
199
Mike Stump1eb44332009-09-09 15:08:12 +0000200 llvm::SmallVector<SourceRange, 2> ranges;
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000201 std::string sbuf;
202 llvm::raw_string_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000203
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000204 os << "Variable '" << drCond->getDecl()->getNameAsCString()
205 << "' with floating point type '" << drCond->getType().getAsString()
206 << "' should not be used as a loop counter";
207
208 ranges.push_back(drCond->getSourceRange());
209 ranges.push_back(drInc->getSourceRange());
Mike Stump1eb44332009-09-09 15:08:12 +0000210
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000211 const char *bugType = "Floating point variable used as loop counter";
212 BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
213 FS->getLocStart(), ranges.data(), ranges.size());
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000214}
215
216//===----------------------------------------------------------------------===//
Ted Kremenekefcbb152009-07-23 22:29:41 +0000217// Check: Any use of 'gets' is insecure.
218// Originally: <rdar://problem/6335715>
219// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
Zhongxing Xuaa30b3b2009-11-09 08:13:04 +0000220// CWE-242: Use of Inherently Dangerous Function
Ted Kremenekefcbb152009-07-23 22:29:41 +0000221//===----------------------------------------------------------------------===//
222
223void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
224 if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
225 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000226
Zhongxing Xubd842e32009-11-09 12:19:26 +0000227 const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
228 if (!FPT)
Ted Kremenekefcbb152009-07-23 22:29:41 +0000229 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000230
Ted Kremenekefcbb152009-07-23 22:29:41 +0000231 // Verify that the function takes a single argument.
Zhongxing Xubd842e32009-11-09 12:19:26 +0000232 if (FPT->getNumArgs() != 1)
Ted Kremenekefcbb152009-07-23 22:29:41 +0000233 return;
234
235 // Is the argument a 'char*'?
Zhongxing Xubd842e32009-11-09 12:19:26 +0000236 const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
Ted Kremenekefcbb152009-07-23 22:29:41 +0000237 if (!PT)
238 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000239
Ted Kremenekefcbb152009-07-23 22:29:41 +0000240 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
241 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000242
Ted Kremenekefcbb152009-07-23 22:29:41 +0000243 // Issue a warning.
244 SourceRange R = CE->getCallee()->getSourceRange();
245 BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
246 "Security",
247 "Call to function 'gets' is extremely insecure as it can "
248 "always result in a buffer overflow",
249 CE->getLocStart(), &R, 1);
250}
251
252//===----------------------------------------------------------------------===//
Zhongxing Xubd842e32009-11-09 12:19:26 +0000253// Check: Any use of 'getpwd' is insecure.
254// CWE-477: Use of Obsolete Functions
255//===----------------------------------------------------------------------===//
256
257void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
258 if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
259 return;
260
261 const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
262 if (!FPT)
263 return;
264
265 // Verify that the function takes two arguments.
266 if (FPT->getNumArgs() != 2)
267 return;
268
269 // Verify the first argument type is integer.
270 if (!FPT->getArgType(0)->isIntegerType())
271 return;
272
273 // Verify the second argument type is char*.
274 const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
275 if (!PT)
276 return;
277
278 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
279 return;
280
281 // Issue a warning.
282 SourceRange R = CE->getCallee()->getSourceRange();
283 BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
284 "Security",
285 "The getpw() function is dangerous as it may overflow the "
286 "provided buffer. It is obsoleted by getpwuid().",
287 CE->getLocStart(), &R, 1);
288}
289
290//===----------------------------------------------------------------------===//
Ted Kremenek24650472009-09-02 02:47:41 +0000291// Check: Linear congruent random number generators should not be used
292// Originally: <rdar://problem/63371000>
293// CWE-338: Use of cryptographically weak prng
294//===----------------------------------------------------------------------===//
295
296void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
297 if (II_rand[0] == NULL) {
298 // This check applies to these functions
299 static const char * const identifiers[num_rands] = {
300 "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
301 "lcong48",
302 "rand", "rand_r"
303 };
Mike Stump1eb44332009-09-09 15:08:12 +0000304
Ted Kremenek24650472009-09-02 02:47:41 +0000305 for (size_t i = 0; i < num_rands; i++)
Mike Stump1eb44332009-09-09 15:08:12 +0000306 II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
Ted Kremenek24650472009-09-02 02:47:41 +0000307 }
Mike Stump1eb44332009-09-09 15:08:12 +0000308
Ted Kremenek24650472009-09-02 02:47:41 +0000309 const IdentifierInfo *id = FD->getIdentifier();
310 size_t identifierid;
311
312 for (identifierid = 0; identifierid < num_rands; identifierid++)
313 if (id == II_rand[identifierid])
314 break;
315
316 if (identifierid >= num_rands)
317 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000318
Ted Kremenek24650472009-09-02 02:47:41 +0000319 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
320 if (!FTP)
321 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000322
Ted Kremenek24650472009-09-02 02:47:41 +0000323 if (FTP->getNumArgs() == 1) {
324 // Is the argument an 'unsigned short *'?
325 // (Actually any integer type is allowed.)
326 const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
327 if (!PT)
328 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000329
Ted Kremenek24650472009-09-02 02:47:41 +0000330 if (! PT->getPointeeType()->isIntegerType())
331 return;
332 }
Mike Stump1eb44332009-09-09 15:08:12 +0000333 else if (FTP->getNumArgs() != 0)
Ted Kremenek24650472009-09-02 02:47:41 +0000334 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000335
Ted Kremenek24650472009-09-02 02:47:41 +0000336 // Issue a warning.
337 std::string buf1;
338 llvm::raw_string_ostream os1(buf1);
339 os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
340
341 std::string buf2;
342 llvm::raw_string_ostream os2(buf2);
343 os2 << "Function '" << FD->getNameAsString()
344 << "' is obsolete because it implements a poor random number generator."
345 << " Use 'arc4random' instead";
346
347 SourceRange R = CE->getCallee()->getSourceRange();
Mike Stump1eb44332009-09-09 15:08:12 +0000348
Ted Kremenek24650472009-09-02 02:47:41 +0000349 BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
350 CE->getLocStart(), &R, 1);
351}
352
353//===----------------------------------------------------------------------===//
354// Check: 'random' should not be used
355// Originally: <rdar://problem/63371000>
356//===----------------------------------------------------------------------===//
357
358void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
359 if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
360 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000361
Ted Kremenek24650472009-09-02 02:47:41 +0000362 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
363 if (!FTP)
364 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000365
Ted Kremenek24650472009-09-02 02:47:41 +0000366 // Verify that the function takes no argument.
367 if (FTP->getNumArgs() != 0)
368 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000369
Ted Kremenek24650472009-09-02 02:47:41 +0000370 // Issue a warning.
371 SourceRange R = CE->getCallee()->getSourceRange();
372 BR.EmitBasicReport("'random' is not a secure random number generator",
373 "Security",
374 "The 'random' function produces a sequence of values that "
375 "an adversary may be able to predict. Use 'arc4random' "
376 "instead",
377 CE->getLocStart(), &R, 1);
378}
379
380//===----------------------------------------------------------------------===//
Ted Kremenek65a81a92009-08-28 00:08:09 +0000381// Check: Should check whether privileges are dropped successfully.
382// Originally: <rdar://problem/6337132>
383//===----------------------------------------------------------------------===//
384
385void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
386 const FunctionDecl *FD = CE->getDirectCallee();
387 if (!FD)
388 return;
389
390 if (II_setid[0] == NULL) {
Ted Kremenek24650472009-09-02 02:47:41 +0000391 static const char * const identifiers[num_setids] = {
Ted Kremenek65a81a92009-08-28 00:08:09 +0000392 "setuid", "setgid", "seteuid", "setegid",
393 "setreuid", "setregid"
394 };
Mike Stump1eb44332009-09-09 15:08:12 +0000395
Ted Kremenek24650472009-09-02 02:47:41 +0000396 for (size_t i = 0; i < num_setids; i++)
Mike Stump1eb44332009-09-09 15:08:12 +0000397 II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
Ted Kremenek65a81a92009-08-28 00:08:09 +0000398 }
Mike Stump1eb44332009-09-09 15:08:12 +0000399
Ted Kremenek65a81a92009-08-28 00:08:09 +0000400 const IdentifierInfo *id = FD->getIdentifier();
401 size_t identifierid;
402
Ted Kremenek24650472009-09-02 02:47:41 +0000403 for (identifierid = 0; identifierid < num_setids; identifierid++)
Ted Kremenek65a81a92009-08-28 00:08:09 +0000404 if (id == II_setid[identifierid])
405 break;
406
Ted Kremenek24650472009-09-02 02:47:41 +0000407 if (identifierid >= num_setids)
Ted Kremenek65a81a92009-08-28 00:08:09 +0000408 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000409
Ted Kremenek65a81a92009-08-28 00:08:09 +0000410 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
411 if (!FTP)
412 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000413
Ted Kremeneka8187832009-08-28 00:24:55 +0000414 // Verify that the function takes one or two arguments (depending on
415 // the function).
Ted Kremenek65a81a92009-08-28 00:08:09 +0000416 if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
417 return;
418
419 // The arguments must be integers.
420 for (unsigned i = 0; i < FTP->getNumArgs(); i++)
421 if (! FTP->getArgType(i)->isIntegerType())
422 return;
423
424 // Issue a warning.
425 std::string buf1;
426 llvm::raw_string_ostream os1(buf1);
427 os1 << "Return value is not checked in call to '" << FD->getNameAsString()
428 << "'";
429
430 std::string buf2;
431 llvm::raw_string_ostream os2(buf2);
432 os2 << "The return value from the call to '" << FD->getNameAsString()
433 << "' is not checked. If an error occurs in '"
434 << FD->getNameAsString()
435 << "', the following code may execute with unexpected privileges";
436
437 SourceRange R = CE->getCallee()->getSourceRange();
Mike Stump1eb44332009-09-09 15:08:12 +0000438
Ted Kremenek65a81a92009-08-28 00:08:09 +0000439 BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
440 CE->getLocStart(), &R, 1);
441}
442
443//===----------------------------------------------------------------------===//
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000444// Entry point for check.
445//===----------------------------------------------------------------------===//
446
Mike Stump1eb44332009-09-09 15:08:12 +0000447void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000448 WalkAST walker(BR);
Mike Stump1eb44332009-09-09 15:08:12 +0000449 walker.Visit(D->getBody());
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000450}