blob: 2ccb519891f3778df5a2e9703eb6f0551c7c5ae6 [file] [log] [blame]
Ted Kremenekd55522f2010-02-25 00:20:35 +00001//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Ted Kremenekd55522f2010-02-25 00:20:35 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This defines UnixAPIChecker, which is an assortment of checks on calls
10// to various, widely used UNIX/Posix functions.
11//
12//===----------------------------------------------------------------------===//
13
Kristof Umann76a21502018-12-15 16:23:51 +000014#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000015#include "clang/Basic/TargetInfo.h"
16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000019#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek26984fb2010-04-09 20:26:58 +000020#include "llvm/ADT/Optional.h"
Benjamin Kramer3307c5082012-02-04 12:31:12 +000021#include "llvm/ADT/STLExtras.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000022#include "llvm/ADT/SmallString.h"
Benjamin Kramer444a1302012-12-01 17:12:56 +000023#include "llvm/Support/raw_ostream.h"
Ted Kremenekd55522f2010-02-25 00:20:35 +000024
25using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000026using namespace ento;
Ted Kremenekd55522f2010-02-25 00:20:35 +000027
Devin Coughlin74810142016-12-16 23:31:56 +000028enum class OpenVariant {
29 /// The standard open() call:
30 /// int open(const char *path, int oflag, ...);
31 Open,
32
33 /// The variant taking a directory file descriptor and a relative path:
34 /// int openat(int fd, const char *path, int oflag, ...);
35 OpenAt
36};
37
Ted Kremenekd55522f2010-02-25 00:20:35 +000038namespace {
Kristof Umannf52f4f62019-01-26 15:56:40 +000039
40class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
41 mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000042 mutable Optional<uint64_t> Val_O_CREAT;
Ted Kremenek212182d2010-04-08 22:15:34 +000043
44public:
Artem Dergachev7caff0e2017-06-27 11:14:39 +000045 DefaultBool CheckMisuse, CheckPortability;
46
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000047 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Jordy Rosef3dd00a2011-07-15 06:28:59 +000048
49 void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
Devin Coughlin74810142016-12-16 23:31:56 +000050 void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
Jordy Rosef3dd00a2011-07-15 06:28:59 +000051 void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
Kristof Umannf52f4f62019-01-26 15:56:40 +000052
53 void CheckOpenVariant(CheckerContext &C,
54 const CallExpr *CE, OpenVariant Variant) const;
55
56 void ReportOpenBug(CheckerContext &C,
57 ProgramStateRef State,
58 const char *Msg,
59 SourceRange SR) const;
60
61};
62
63class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
64public:
65 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
66
67private:
68 mutable std::unique_ptr<BugType> BT_mallocZero;
69
Ted Kremenek134a83a2012-01-03 23:43:13 +000070 void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
Jordy Rosef3dd00a2011-07-15 06:28:59 +000071 void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
Ted Kremenek134a83a2012-01-03 23:43:13 +000072 void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
Jordan Rose9e068aa2012-10-30 01:37:16 +000073 void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
Ted Kremenek940e00f2012-01-11 08:13:21 +000074 void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
David Majnemer51169932016-10-31 05:37:48 +000075 void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
Ted Kremenek940e00f2012-01-11 08:13:21 +000076 void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
Jordy Rosef3dd00a2011-07-15 06:28:59 +000077
Ted Kremenek134a83a2012-01-03 23:43:13 +000078 bool ReportZeroByteAllocation(CheckerContext &C,
Ted Kremenek49b1e382012-01-26 21:29:00 +000079 ProgramStateRef falseState,
Ted Kremenek134a83a2012-01-03 23:43:13 +000080 const Expr *arg,
81 const char *fn_name) const;
Ted Kremenek940e00f2012-01-11 08:13:21 +000082 void BasicAllocationCheck(CheckerContext &C,
83 const CallExpr *CE,
84 const unsigned numArgs,
85 const unsigned sizeArg,
86 const char *fn) const;
Ted Kremenekd55522f2010-02-25 00:20:35 +000087};
Kristof Umannf52f4f62019-01-26 15:56:40 +000088
Ted Kremenekd55522f2010-02-25 00:20:35 +000089} //end anonymous namespace
90
Kristof Umannf52f4f62019-01-26 15:56:40 +000091static void LazyInitialize(const CheckerBase *Checker,
92 std::unique_ptr<BugType> &BT,
93 const char *name) {
94 if (BT)
95 return;
96 BT.reset(new BugType(Checker, name, categories::UnixAPI));
97}
98
Ted Kremenekd55522f2010-02-25 00:20:35 +000099//===----------------------------------------------------------------------===//
Ted Kremenekd55522f2010-02-25 00:20:35 +0000100// "open" (man 2 open)
Kristof Umannf52f4f62019-01-26 15:56:40 +0000101//===----------------------------------------------------------------------===/
Ted Kremenekd55522f2010-02-25 00:20:35 +0000102
Kristof Umannf52f4f62019-01-26 15:56:40 +0000103void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
104 CheckerContext &C) const {
105 const FunctionDecl *FD = C.getCalleeDecl(CE);
106 if (!FD || FD->getKind() != Decl::Function)
107 return;
108
109 // Don't treat functions in namespaces with the same name a Unix function
110 // as a call to the Unix function.
111 const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
112 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
113 return;
114
115 StringRef FName = C.getCalleeName(FD);
116 if (FName.empty())
117 return;
118
119 if (FName == "open")
120 CheckOpen(C, CE);
121
122 else if (FName == "openat")
123 CheckOpenAt(C, CE);
124
125 else if (FName == "pthread_once")
126 CheckPthreadOnce(C, CE);
127}
128void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
129 ProgramStateRef State,
130 const char *Msg,
131 SourceRange SR) const {
Devin Coughline39bd402015-09-16 22:03:05 +0000132 ExplodedNode *N = C.generateErrorNode(State);
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000133 if (!N)
134 return;
135
Kristof Umannf52f4f62019-01-26 15:56:40 +0000136 LazyInitialize(this, BT_open, "Improper use of 'open'");
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000137
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000138 auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000139 Report->addRange(SR);
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000140 C.emitReport(std::move(Report));
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000141}
142
Kristof Umannf52f4f62019-01-26 15:56:40 +0000143void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
144 const CallExpr *CE) const {
Devin Coughlin74810142016-12-16 23:31:56 +0000145 CheckOpenVariant(C, CE, OpenVariant::Open);
146}
147
Kristof Umannf52f4f62019-01-26 15:56:40 +0000148void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
149 const CallExpr *CE) const {
Devin Coughlin74810142016-12-16 23:31:56 +0000150 CheckOpenVariant(C, CE, OpenVariant::OpenAt);
151}
152
Kristof Umannf52f4f62019-01-26 15:56:40 +0000153void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
154 const CallExpr *CE,
155 OpenVariant Variant) const {
Devin Coughlin74810142016-12-16 23:31:56 +0000156 // The index of the argument taking the flags open flags (O_RDONLY,
157 // O_WRONLY, O_CREAT, etc.),
158 unsigned int FlagsArgIndex;
159 const char *VariantName;
160 switch (Variant) {
161 case OpenVariant::Open:
162 FlagsArgIndex = 1;
163 VariantName = "open";
164 break;
165 case OpenVariant::OpenAt:
166 FlagsArgIndex = 2;
167 VariantName = "openat";
168 break;
169 };
170
171 // All calls should at least provide arguments up to the 'flags' parameter.
172 unsigned int MinArgCount = FlagsArgIndex + 1;
173
174 // If the flags has O_CREAT set then open/openat() require an additional
175 // argument specifying the file mode (permission bits) for the created file.
176 unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
177
178 // The create mode argument should be the last argument.
179 unsigned int MaxArgCount = CreateModeArgIndex + 1;
180
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000181 ProgramStateRef state = C.getState();
182
Devin Coughlin74810142016-12-16 23:31:56 +0000183 if (CE->getNumArgs() < MinArgCount) {
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000184 // The frontend should issue a warning for this case, so this is a sanity
185 // check.
186 return;
Devin Coughlin74810142016-12-16 23:31:56 +0000187 } else if (CE->getNumArgs() == MaxArgCount) {
188 const Expr *Arg = CE->getArg(CreateModeArgIndex);
Jordan Roseba129af2014-08-20 16:58:09 +0000189 QualType QT = Arg->getType();
190 if (!QT->isIntegerType()) {
Devin Coughlin74810142016-12-16 23:31:56 +0000191 SmallString<256> SBuf;
192 llvm::raw_svector_ostream OS(SBuf);
193 OS << "The " << CreateModeArgIndex + 1
194 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
195 << " argument to '" << VariantName << "' is not an integer";
196
Jordan Roseba129af2014-08-20 16:58:09 +0000197 ReportOpenBug(C, state,
Devin Coughlin74810142016-12-16 23:31:56 +0000198 SBuf.c_str(),
Jordan Roseba129af2014-08-20 16:58:09 +0000199 Arg->getSourceRange());
200 return;
201 }
Devin Coughlin74810142016-12-16 23:31:56 +0000202 } else if (CE->getNumArgs() > MaxArgCount) {
203 SmallString<256> SBuf;
204 llvm::raw_svector_ostream OS(SBuf);
205 OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
206 << " arguments";
207
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000208 ReportOpenBug(C, state,
Devin Coughlin74810142016-12-16 23:31:56 +0000209 SBuf.c_str(),
210 CE->getArg(MaxArgCount)->getSourceRange());
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000211 return;
212 }
213
Ted Kremenek212182d2010-04-08 22:15:34 +0000214 // The definition of O_CREAT is platform specific. We need a better way
215 // of querying this information from the checking environment.
Jordy Rosef3dd00a2011-07-15 06:28:59 +0000216 if (!Val_O_CREAT.hasValue()) {
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000217 if (C.getASTContext().getTargetInfo().getTriple().getVendor()
Douglas Gregore8bbc122011-09-02 00:18:52 +0000218 == llvm::Triple::Apple)
Jordy Rosef3dd00a2011-07-15 06:28:59 +0000219 Val_O_CREAT = 0x0200;
Ted Kremenek212182d2010-04-08 22:15:34 +0000220 else {
221 // FIXME: We need a more general way of getting the O_CREAT value.
222 // We could possibly grovel through the preprocessor state, but
Argyrios Kyrtzidis1696f502010-12-22 18:53:44 +0000223 // that would require passing the Preprocessor object to the ExprEngine.
Jordan Rose6b33c6f2014-03-26 17:05:46 +0000224 // See also: MallocChecker.cpp / M_ZERO.
Ted Kremenek212182d2010-04-08 22:15:34 +0000225 return;
226 }
227 }
228
Ted Kremenekd55522f2010-02-25 00:20:35 +0000229 // Now check if oflags has O_CREAT set.
Devin Coughlin74810142016-12-16 23:31:56 +0000230 const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
George Karpenkovd703ec92018-01-17 20:27:29 +0000231 const SVal V = C.getSVal(oflagsEx);
David Blaikie2fdacbc2013-02-20 05:52:05 +0000232 if (!V.getAs<NonLoc>()) {
Ted Kremenekd55522f2010-02-25 00:20:35 +0000233 // The case where 'V' can be a location can only be due to a bad header,
234 // so in this case bail out.
235 return;
236 }
David Blaikie2fdacbc2013-02-20 05:52:05 +0000237 NonLoc oflags = V.castAs<NonLoc>();
238 NonLoc ocreateFlag = C.getSValBuilder()
239 .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
Ted Kremenekdc891422010-12-01 21:57:22 +0000240 SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
Ted Kremenek9d0bb1e2010-12-01 21:28:31 +0000241 oflags, ocreateFlag,
242 oflagsEx->getType());
Ted Kremenekd55522f2010-02-25 00:20:35 +0000243 if (maskedFlagsUC.isUnknownOrUndef())
244 return;
David Blaikie2fdacbc2013-02-20 05:52:05 +0000245 DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
Ted Kremenekd55522f2010-02-25 00:20:35 +0000246
247 // Check if maskedFlags is non-zero.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000248 ProgramStateRef trueState, falseState;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000249 std::tie(trueState, falseState) = state->assume(maskedFlags);
Ted Kremenekd55522f2010-02-25 00:20:35 +0000250
251 // Only emit an error if the value of 'maskedFlags' is properly
252 // constrained;
253 if (!(trueState && !falseState))
254 return;
255
Devin Coughlin74810142016-12-16 23:31:56 +0000256 if (CE->getNumArgs() < MaxArgCount) {
257 SmallString<256> SBuf;
258 llvm::raw_svector_ostream OS(SBuf);
259 OS << "Call to '" << VariantName << "' requires a "
260 << CreateModeArgIndex + 1
261 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
262 << " argument when the 'O_CREAT' flag is set";
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000263 ReportOpenBug(C, trueState,
Devin Coughlin74810142016-12-16 23:31:56 +0000264 SBuf.c_str(),
Jordan Rosecd4db5c2014-08-20 16:58:03 +0000265 oflagsEx->getSourceRange());
Ted Kremenekd55522f2010-02-25 00:20:35 +0000266 }
267}
268
269//===----------------------------------------------------------------------===//
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000270// pthread_once
271//===----------------------------------------------------------------------===//
272
Kristof Umannf52f4f62019-01-26 15:56:40 +0000273void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
Jordy Rosef3dd00a2011-07-15 06:28:59 +0000274 const CallExpr *CE) const {
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000275
276 // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
277 // They can possibly be refactored.
278
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000279 if (CE->getNumArgs() < 1)
280 return;
281
282 // Check if the first argument is stack allocated. If so, issue a warning
283 // because that's likely to be bad news.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000284 ProgramStateRef state = C.getState();
George Karpenkovd703ec92018-01-17 20:27:29 +0000285 const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000286 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
287 return;
288
Devin Coughline39bd402015-09-16 22:03:05 +0000289 ExplodedNode *N = C.generateErrorNode(state);
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000290 if (!N)
291 return;
292
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000293 SmallString<256> S;
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000294 llvm::raw_svector_ostream os(S);
295 os << "Call to 'pthread_once' uses";
296 if (const VarRegion *VR = dyn_cast<VarRegion>(R))
297 os << " the local variable '" << VR->getDecl()->getName() << '\'';
298 else
299 os << " stack allocated memory";
300 os << " for the \"control\" value. Using such transient memory for "
301 "the control value is potentially dangerous.";
302 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
303 os << " Perhaps you intended to declare the variable as 'static'?";
304
Kristof Umannf52f4f62019-01-26 15:56:40 +0000305 LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
Jordy Rosef3dd00a2011-07-15 06:28:59 +0000306
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000307 auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N);
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000308 report->addRange(CE->getArg(0)->getSourceRange());
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000309 C.emitReport(std::move(report));
Ted Kremenekea4a5ab2010-04-08 19:53:31 +0000310}
311
312//===----------------------------------------------------------------------===//
Jordan Rose9e068aa2012-10-30 01:37:16 +0000313// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
314// with allocation size 0
Ted Kremenek0c27bcf2010-11-16 18:47:04 +0000315//===----------------------------------------------------------------------===//
Kristof Umannf52f4f62019-01-26 15:56:40 +0000316
Ted Kremenek940e00f2012-01-11 08:13:21 +0000317// FIXME: Eventually these should be rolled into the MallocChecker, but right now
318// they're more basic and valuable for widespread use.
Ted Kremenek0c27bcf2010-11-16 18:47:04 +0000319
Ted Kremenek134a83a2012-01-03 23:43:13 +0000320// Returns true if we try to do a zero byte allocation, false otherwise.
321// Fills in trueState and falseState.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000322static bool IsZeroByteAllocation(ProgramStateRef state,
Kristof Umannf52f4f62019-01-26 15:56:40 +0000323 const SVal argVal,
324 ProgramStateRef *trueState,
325 ProgramStateRef *falseState) {
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000326 std::tie(*trueState, *falseState) =
David Blaikie2fdacbc2013-02-20 05:52:05 +0000327 state->assume(argVal.castAs<DefinedSVal>());
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000328
Ted Kremenek134a83a2012-01-03 23:43:13 +0000329 return (*falseState && !*trueState);
330}
331
332// Generates an error report, indicating that the function whose name is given
333// will perform a zero byte allocation.
Alp Tokerf6a24ce2013-12-05 16:25:25 +0000334// Returns false if an error occurred, true otherwise.
Kristof Umannf52f4f62019-01-26 15:56:40 +0000335bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
336 CheckerContext &C,
337 ProgramStateRef falseState,
338 const Expr *arg,
339 const char *fn_name) const {
Devin Coughline39bd402015-09-16 22:03:05 +0000340 ExplodedNode *N = C.generateErrorNode(falseState);
Ted Kremenek134a83a2012-01-03 23:43:13 +0000341 if (!N)
342 return false;
343
Kristof Umannf52f4f62019-01-26 15:56:40 +0000344 LazyInitialize(this, BT_mallocZero,
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000345 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
Ted Kremenek134a83a2012-01-03 23:43:13 +0000346
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000347 SmallString<256> S;
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000348 llvm::raw_svector_ostream os(S);
Ted Kremenek134a83a2012-01-03 23:43:13 +0000349 os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000350 auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
Ted Kremenek134a83a2012-01-03 23:43:13 +0000351
352 report->addRange(arg->getSourceRange());
George Karpenkovb2cf0062018-10-23 18:24:53 +0000353 bugreporter::trackExpressionValue(N, arg, *report);
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000354 C.emitReport(std::move(report));
Ted Kremenek134a83a2012-01-03 23:43:13 +0000355
356 return true;
357}
358
Ted Kremenek940e00f2012-01-11 08:13:21 +0000359// Does a basic check for 0-sized allocations suitable for most of the below
360// functions (modulo "calloc")
Kristof Umannf52f4f62019-01-26 15:56:40 +0000361void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
362 const CallExpr *CE,
363 const unsigned numArgs,
364 const unsigned sizeArg,
365 const char *fn) const {
Ted Kremenek940e00f2012-01-11 08:13:21 +0000366 // Sanity check for the correct number of arguments
367 if (CE->getNumArgs() != numArgs)
368 return;
369
370 // Check if the allocation size is 0.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000371 ProgramStateRef state = C.getState();
Craig Topper0dbb7832014-05-27 02:45:47 +0000372 ProgramStateRef trueState = nullptr, falseState = nullptr;
Ted Kremenek940e00f2012-01-11 08:13:21 +0000373 const Expr *arg = CE->getArg(sizeArg);
George Karpenkovd703ec92018-01-17 20:27:29 +0000374 SVal argVal = C.getSVal(arg);
Ted Kremenek940e00f2012-01-11 08:13:21 +0000375
376 if (argVal.isUnknownOrUndef())
377 return;
378
379 // Is the value perfectly constrained to zero?
380 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000381 (void) ReportZeroByteAllocation(C, falseState, arg, fn);
Ted Kremenek940e00f2012-01-11 08:13:21 +0000382 return;
383 }
Sylvestre Ledru830885c2012-07-23 08:59:39 +0000384 // Assume the value is non-zero going forward.
Ted Kremenek940e00f2012-01-11 08:13:21 +0000385 assert(trueState);
386 if (trueState != state)
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000387 C.addTransition(trueState);
Ted Kremenek940e00f2012-01-11 08:13:21 +0000388}
389
Kristof Umannf52f4f62019-01-26 15:56:40 +0000390void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
391 const CallExpr *CE) const {
Ted Kremenek134a83a2012-01-03 23:43:13 +0000392 unsigned int nArgs = CE->getNumArgs();
393 if (nArgs != 2)
394 return;
395
Ted Kremenek49b1e382012-01-26 21:29:00 +0000396 ProgramStateRef state = C.getState();
Craig Topper0dbb7832014-05-27 02:45:47 +0000397 ProgramStateRef trueState = nullptr, falseState = nullptr;
Ted Kremenek134a83a2012-01-03 23:43:13 +0000398
399 unsigned int i;
400 for (i = 0; i < nArgs; i++) {
401 const Expr *arg = CE->getArg(i);
George Karpenkovd703ec92018-01-17 20:27:29 +0000402 SVal argVal = C.getSVal(arg);
Ted Kremenek134a83a2012-01-03 23:43:13 +0000403 if (argVal.isUnknownOrUndef()) {
404 if (i == 0)
405 continue;
406 else
407 return;
408 }
409
410 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
411 if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
412 return;
413 else if (i == 0)
414 continue;
415 else
416 return;
417 }
418 }
419
Sylvestre Ledru830885c2012-07-23 08:59:39 +0000420 // Assume the value is non-zero going forward.
Ted Kremenek134a83a2012-01-03 23:43:13 +0000421 assert(trueState);
422 if (trueState != state)
423 C.addTransition(trueState);
424}
425
Kristof Umannf52f4f62019-01-26 15:56:40 +0000426void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
427 const CallExpr *CE) const {
Ted Kremenek940e00f2012-01-11 08:13:21 +0000428 BasicAllocationCheck(C, CE, 1, 0, "malloc");
Ted Kremenek134a83a2012-01-03 23:43:13 +0000429}
430
Kristof Umannf52f4f62019-01-26 15:56:40 +0000431void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
432 const CallExpr *CE) const {
Ted Kremenek940e00f2012-01-11 08:13:21 +0000433 BasicAllocationCheck(C, CE, 2, 1, "realloc");
Ted Kremenek0c27bcf2010-11-16 18:47:04 +0000434}
Ted Kremenek940e00f2012-01-11 08:13:21 +0000435
Kristof Umannf52f4f62019-01-26 15:56:40 +0000436void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
437 const CallExpr *CE) const {
Jordan Rose9e068aa2012-10-30 01:37:16 +0000438 BasicAllocationCheck(C, CE, 2, 1, "reallocf");
439}
440
Kristof Umannf52f4f62019-01-26 15:56:40 +0000441void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
442 const CallExpr *CE) const {
Ted Kremenek940e00f2012-01-11 08:13:21 +0000443 BasicAllocationCheck(C, CE, 1, 0, "alloca");
444}
445
Kristof Umannf52f4f62019-01-26 15:56:40 +0000446void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
447 CheckerContext &C,
448 const CallExpr *CE) const {
David Majnemer51169932016-10-31 05:37:48 +0000449 BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
450}
451
Kristof Umannf52f4f62019-01-26 15:56:40 +0000452void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
453 const CallExpr *CE) const {
Ted Kremenek940e00f2012-01-11 08:13:21 +0000454 BasicAllocationCheck(C, CE, 1, 0, "valloc");
455}
456
Kristof Umannf52f4f62019-01-26 15:56:40 +0000457void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
458 CheckerContext &C) const {
Jordan Rose6cd16c52012-07-10 23:13:01 +0000459 const FunctionDecl *FD = C.getCalleeDecl(CE);
460 if (!FD || FD->getKind() != Decl::Function)
461 return;
462
Devin Coughlinaa0fd762016-12-17 01:08:17 +0000463 // Don't treat functions in namespaces with the same name a Unix function
464 // as a call to the Unix function.
465 const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
466 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
467 return;
468
Jordan Rose6cd16c52012-07-10 23:13:01 +0000469 StringRef FName = C.getCalleeName(FD);
Anna Zaksc6aa5312011-12-01 05:57:37 +0000470 if (FName.empty())
Ted Kremenekd55522f2010-02-25 00:20:35 +0000471 return;
472
Kristof Umannf52f4f62019-01-26 15:56:40 +0000473 if (FName == "calloc")
474 CheckCallocZero(C, CE);
475
476 else if (FName == "malloc")
477 CheckMallocZero(C, CE);
478
479 else if (FName == "realloc")
480 CheckReallocZero(C, CE);
481
482 else if (FName == "reallocf")
483 CheckReallocfZero(C, CE);
484
485 else if (FName == "alloca" || FName == "__builtin_alloca")
486 CheckAllocaZero(C, CE);
487
488 else if (FName == "__builtin_alloca_with_align")
489 CheckAllocaWithAlignZero(C, CE);
490
491 else if (FName == "valloc")
492 CheckVallocZero(C, CE);
Ted Kremenekd55522f2010-02-25 00:20:35 +0000493}
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +0000494
495//===----------------------------------------------------------------------===//
496// Registration.
497//===----------------------------------------------------------------------===//
498
Kristof Umannf52f4f62019-01-26 15:56:40 +0000499#define REGISTER_CHECKER(CHECKERNAME) \
500 void ento::register##CHECKERNAME(CheckerManager &mgr) { \
501 mgr.registerChecker<CHECKERNAME>(); \
Kristof Umann058a7a42019-01-26 14:23:08 +0000502 } \
503 \
Kristof Umannf52f4f62019-01-26 15:56:40 +0000504 bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) { \
Kristof Umann058a7a42019-01-26 14:23:08 +0000505 return true; \
Artem Dergachev7caff0e2017-06-27 11:14:39 +0000506 }
507
Kristof Umannf52f4f62019-01-26 15:56:40 +0000508REGISTER_CHECKER(UnixAPIMisuseChecker)
509REGISTER_CHECKER(UnixAPIPortabilityChecker)