1381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
2381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//
3381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//                     The LLVM Compiler Infrastructure
4381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//
5381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// This file is distributed under the University of Illinois Open Source
6381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// License. See LICENSE.TXT for details.
7381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//
8381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
9381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//
10381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// This defines UnixAPIChecker, which is an assortment of checks on calls
11381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// to various, widely used UNIX/Posix functions.
12381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//
13381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
14381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
15027a6abdd6cedc0b8203da72eed6d15c796dce9dArgyrios Kyrtzidis#include "ClangSACheckers.h"
1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Basic/TargetInfo.h"
1755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
19695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
20983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2166d5142ab5026aa77ab6f1d7e4d9bdb0b438d55aTed Kremenek#include "llvm/ADT/Optional.h"
2200bd44d5677783527d7517c1ffe45e4d75a0f56fBenjamin Kramer#include "llvm/ADT/STLExtras.h"
2355fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/ADT/SmallString.h"
24381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek#include "llvm/ADT/StringSwitch.h"
25a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "llvm/Support/raw_ostream.h"
26381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek#include <fcntl.h>
27381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
28381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenekusing namespace clang;
299ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
30381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
31381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremeneknamespace {
32ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
336f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith  mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
34983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis  mutable Optional<uint64_t> Val_O_CREAT;
35bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek
36bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenekpublic:
37983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
38af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose
39af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
40af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
41c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
42af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
43c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
44eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose  void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
453e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
463e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
47af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose
48af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
49af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose                                             const CallExpr *) const;
50c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenekprivate:
51c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  bool ReportZeroByteAllocation(CheckerContext &C,
528bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek                                ProgramStateRef falseState,
53c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                const Expr *arg,
54c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                const char *fn_name) const;
553e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  void BasicAllocationCheck(CheckerContext &C,
563e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                            const CallExpr *CE,
573e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                            const unsigned numArgs,
583e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                            const unsigned sizeArg,
593e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                            const char *fn) const;
60381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek};
61381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek} //end anonymous namespace
62381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
63381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
64381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// Utility functions.
65381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
66381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
676f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmithstatic inline void LazyInitialize(OwningPtr<BugType> &BT,
68af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose                                  const char *name) {
69381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  if (BT)
70381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
716fd4505ad67a186da8cc26fdb493c93fe4937555Ted Kremenek  BT.reset(new BugType(name, categories::UnixAPI));
72381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek}
73381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
74381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
75381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// "open" (man 2 open)
76381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
77381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
78af5b043fe7933e515e405b8509b2609117045ce7Jordy Rosevoid UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
79bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek  // The definition of O_CREAT is platform specific.  We need a better way
80bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek  // of querying this information from the checking environment.
81af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  if (!Val_O_CREAT.hasValue()) {
82bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
83bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor                                                      == llvm::Triple::Apple)
84af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose      Val_O_CREAT = 0x0200;
85bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek    else {
86bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek      // FIXME: We need a more general way of getting the O_CREAT value.
87bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek      // We could possibly grovel through the preprocessor state, but
88d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis      // that would require passing the Preprocessor object to the ExprEngine.
89bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek      return;
90bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek    }
91bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek  }
92bace4ba042d87a0ed0ec15dbe6caad946b97bd33Ted Kremenek
93381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  // Look at the 'oflags' argument for the O_CREAT flag.
948bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
95381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
96381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  if (CE->getNumArgs() < 2) {
97381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    // The frontend should issue a warning for this case, so this is a sanity
98381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    // check.
99381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
100381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  }
101381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
102381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  // Now check if oflags has O_CREAT set.
103381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  const Expr *oflagsEx = CE->getArg(1);
1045eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
1055251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie  if (!V.getAs<NonLoc>()) {
106381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    // The case where 'V' can be a location can only be due to a bad header,
107381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    // so in this case bail out.
108381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
109381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  }
1105251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie  NonLoc oflags = V.castAs<NonLoc>();
1115251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie  NonLoc ocreateFlag = C.getSValBuilder()
1125251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
1139c14953d0c84f7cf5adfb4cd3c0f05a9b1723c1cTed Kremenek  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
114846eabd187be4bfe992e8bca131166b734d86e0dTed Kremenek                                                      oflags, ocreateFlag,
115846eabd187be4bfe992e8bca131166b734d86e0dTed Kremenek                                                      oflagsEx->getType());
116381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  if (maskedFlagsUC.isUnknownOrUndef())
117381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
1185251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
119381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
120381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  // Check if maskedFlags is non-zero.
1218bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef trueState, falseState;
12228f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek  llvm::tie(trueState, falseState) = state->assume(maskedFlags);
123381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
124381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  // Only emit an error if the value of 'maskedFlags' is properly
125381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  // constrained;
126381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  if (!(trueState && !falseState))
127381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
128381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
129381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  if (CE->getNumArgs() < 3) {
130d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek    ExplodedNode *N = C.generateSink(trueState);
131c757d798e609c8baebd9c26d3931c79df0dda637Ted Kremenek    if (!N)
132c757d798e609c8baebd9c26d3931c79df0dda637Ted Kremenek      return;
133c757d798e609c8baebd9c26d3931c79df0dda637Ted Kremenek
134af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose    LazyInitialize(BT_open, "Improper use of 'open'");
135af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose
136e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks    BugReport *report =
137e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks      new BugReport(*BT_open,
138381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek                            "Call to 'open' requires a third argument when "
139381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek                            "the 'O_CREAT' flag is set", N);
140381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    report->addRange(oflagsEx->getSourceRange());
141785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose    C.emitReport(report);
142381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek  }
143381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek}
144381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
145381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
14699d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek// pthread_once
14799d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek//===----------------------------------------------------------------------===//
14899d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
149af5b043fe7933e515e405b8509b2609117045ce7Jordy Rosevoid UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
150af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose                                      const CallExpr *CE) const {
15199d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
15299d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
15399d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  // They can possibly be refactored.
15499d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
15599d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  if (CE->getNumArgs() < 1)
15699d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    return;
15799d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
15899d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  // Check if the first argument is stack allocated.  If so, issue a warning
15999d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  // because that's likely to be bad news.
1608bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
1615eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  const MemRegion *R =
1625eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek    state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
16399d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
16499d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    return;
16599d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
166d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek  ExplodedNode *N = C.generateSink(state);
16799d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  if (!N)
16899d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    return;
16999d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
170f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith  SmallString<256> S;
17199d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  llvm::raw_svector_ostream os(S);
17299d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  os << "Call to 'pthread_once' uses";
17399d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
17499d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    os << " the local variable '" << VR->getDecl()->getName() << '\'';
17599d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  else
17699d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    os << " stack allocated memory";
17799d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  os << " for the \"control\" value.  Using such transient memory for "
17899d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  "the control value is potentially dangerous.";
17999d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
18099d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek    os << "  Perhaps you intended to declare the variable as 'static'?";
18199d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
182af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'");
183af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose
184e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks  BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N);
18599d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek  report->addRange(CE->getArg(0)->getSourceRange());
186785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose  C.emitReport(report);
18799d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek}
18899d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek
18999d9838b256ded8e59f85c93647ba5ec060b7145Ted Kremenek//===----------------------------------------------------------------------===//
190eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
191eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose// with allocation size 0
192b12fbc216f77bd309f8c416834b341ff43325aabTed Kremenek//===----------------------------------------------------------------------===//
1933e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek// FIXME: Eventually these should be rolled into the MallocChecker, but right now
1943e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek// they're more basic and valuable for widespread use.
195b12fbc216f77bd309f8c416834b341ff43325aabTed Kremenek
196c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek// Returns true if we try to do a zero byte allocation, false otherwise.
197c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek// Fills in trueState and falseState.
1988bef8238181a30e52dea380789a7e2d760eac532Ted Kremenekstatic bool IsZeroByteAllocation(ProgramStateRef state,
199c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                const SVal argVal,
2008bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek                                ProgramStateRef *trueState,
2018bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek                                ProgramStateRef *falseState) {
2023e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  llvm::tie(*trueState, *falseState) =
2035251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie    state->assume(argVal.castAs<DefinedSVal>());
2043e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek
205c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  return (*falseState && !*trueState);
206c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek}
207c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
208c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek// Generates an error report, indicating that the function whose name is given
209c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek// will perform a zero byte allocation.
210c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek// Returns false if an error occured, true otherwise.
211c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenekbool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
2128bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek                                              ProgramStateRef falseState,
213c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                              const Expr *arg,
214c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                              const char *fn_name) const {
215c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  ExplodedNode *N = C.generateSink(falseState);
216c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  if (!N)
217c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    return false;
218c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
2193e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  LazyInitialize(BT_mallocZero,
2203e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
221c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
222f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith  SmallString<256> S;
223c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  llvm::raw_svector_ostream os(S);
224c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
225c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);
226c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
227c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  report->addRange(arg->getSourceRange());
228a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose  bugreporter::trackNullOrUndefValue(N, arg, *report);
229785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose  C.emitReport(report);
230c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
231c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  return true;
232c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek}
233c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
2343e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek// Does a basic check for 0-sized allocations suitable for most of the below
2353e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek// functions (modulo "calloc")
2363e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenekvoid UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
2373e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                          const CallExpr *CE,
2383e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                          const unsigned numArgs,
2393e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                          const unsigned sizeArg,
2403e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                          const char *fn) const {
2413e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  // Sanity check for the correct number of arguments
2423e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  if (CE->getNumArgs() != numArgs)
2433e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    return;
2443e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek
2453e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  // Check if the allocation size is 0.
2468bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
2478bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef trueState = NULL, falseState = NULL;
2483e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  const Expr *arg = CE->getArg(sizeArg);
2493e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  SVal argVal = state->getSVal(arg, C.getLocationContext());
2503e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek
2513e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  if (argVal.isUnknownOrUndef())
2523e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    return;
2533e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek
2543e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  // Is the value perfectly constrained to zero?
2553e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
2563e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    (void) ReportZeroByteAllocation(C, falseState, arg, fn);
2573e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    return;
2583e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  }
259bed28ac1d1463adca3ecf24fca5c30646fa9dbb2Sylvestre Ledru  // Assume the value is non-zero going forward.
2603e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  assert(trueState);
2613e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  if (trueState != state)
2623e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek    C.addTransition(trueState);
2633e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek}
2643e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek
265c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenekvoid UnixAPIChecker::CheckCallocZero(CheckerContext &C,
266c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                     const CallExpr *CE) const {
267c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  unsigned int nArgs = CE->getNumArgs();
268c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  if (nArgs != 2)
269c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    return;
270c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
2718bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
2728bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef trueState = NULL, falseState = NULL;
273c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
274c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  unsigned int i;
275c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  for (i = 0; i < nArgs; i++) {
276c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    const Expr *arg = CE->getArg(i);
2775eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek    SVal argVal = state->getSVal(arg, C.getLocationContext());
278c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    if (argVal.isUnknownOrUndef()) {
279c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      if (i == 0)
280c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek        continue;
281c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      else
282c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek        return;
283c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    }
284c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
285c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
286c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
287c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek        return;
288c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      else if (i == 0)
289c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek        continue;
290c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      else
291c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek        return;
292c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    }
293c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  }
294c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
295bed28ac1d1463adca3ecf24fca5c30646fa9dbb2Sylvestre Ledru  // Assume the value is non-zero going forward.
296c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  assert(trueState);
297c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek  if (trueState != state)
298c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek    C.addTransition(trueState);
299c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek}
300c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
301af5b043fe7933e515e405b8509b2609117045ce7Jordy Rosevoid UnixAPIChecker::CheckMallocZero(CheckerContext &C,
302af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose                                     const CallExpr *CE) const {
3033e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  BasicAllocationCheck(C, CE, 1, 0, "malloc");
304c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek}
305c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
306c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenekvoid UnixAPIChecker::CheckReallocZero(CheckerContext &C,
307c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek                                      const CallExpr *CE) const {
3083e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  BasicAllocationCheck(C, CE, 2, 1, "realloc");
3093e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek}
310c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
311eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rosevoid UnixAPIChecker::CheckReallocfZero(CheckerContext &C,
312eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose                                       const CallExpr *CE) const {
313eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose  BasicAllocationCheck(C, CE, 2, 1, "reallocf");
314eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose}
315eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose
3163e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenekvoid UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
3173e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                     const CallExpr *CE) const {
3183e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  BasicAllocationCheck(C, CE, 1, 0, "alloca");
3193e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek}
320c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
3213e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenekvoid UnixAPIChecker::CheckVallocZero(CheckerContext &C,
3223e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                     const CallExpr *CE) const {
3233e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek  BasicAllocationCheck(C, CE, 1, 0, "valloc");
3243e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek}
325c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
326c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek
327b12fbc216f77bd309f8c416834b341ff43325aabTed Kremenek//===----------------------------------------------------------------------===//
328381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek// Central dispatch function.
329381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek//===----------------------------------------------------------------------===//
330381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
3313e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenekvoid UnixAPIChecker::checkPreStmt(const CallExpr *CE,
3323e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek                                  CheckerContext &C) const {
3335ef6e94b294cc47750d8ab220858a36726caba59Jordan Rose  const FunctionDecl *FD = C.getCalleeDecl(CE);
3345ef6e94b294cc47750d8ab220858a36726caba59Jordan Rose  if (!FD || FD->getKind() != Decl::Function)
3355ef6e94b294cc47750d8ab220858a36726caba59Jordan Rose    return;
3365ef6e94b294cc47750d8ab220858a36726caba59Jordan Rose
3375ef6e94b294cc47750d8ab220858a36726caba59Jordan Rose  StringRef FName = C.getCalleeName(FD);
338b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks  if (FName.empty())
339381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek    return;
340381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek
341af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  SubChecker SC =
342b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks    llvm::StringSwitch<SubChecker>(FName)
343af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose      .Case("open", &UnixAPIChecker::CheckOpen)
344af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose      .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
345c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      .Case("calloc", &UnixAPIChecker::CheckCallocZero)
346af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose      .Case("malloc", &UnixAPIChecker::CheckMallocZero)
347c1275da4eb5778eb3c9600e79918ad1fbec589c6Ted Kremenek      .Case("realloc", &UnixAPIChecker::CheckReallocZero)
348eafaad279f7be4552e5a2246fcda1b5d65698104Jordan Rose      .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
3493e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek      .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
3503e97758f22f31d0dbc336fc4794b86aed8607053Ted Kremenek      .Case("valloc", &UnixAPIChecker::CheckVallocZero)
351af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose      .Default(NULL);
352af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose
353af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose  if (SC)
354af5b043fe7933e515e405b8509b2609117045ce7Jordy Rose    (this->*SC)(C, CE);
355381d1bf0eeabccac1ba64909cad73d2ee963897bTed Kremenek}
356983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis
357983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
358983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis// Registration.
359983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
360983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis
361983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid ento::registerUnixAPIChecker(CheckerManager &mgr) {
362983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis  mgr.registerChecker<UnixAPIChecker>();
363983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis}
364