head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.9
	netbsd-11-0-RC3:1.1.1.9
	netbsd-11-0-RC2:1.1.1.9
	netbsd-11-0-RC1:1.1.1.9
	perseant-exfatfs-base-20250801:1.1.1.9
	netbsd-11:1.1.1.9.0.10
	netbsd-11-base:1.1.1.9
	netbsd-10-1-RELEASE:1.1.1.9
	perseant-exfatfs-base-20240630:1.1.1.9
	perseant-exfatfs:1.1.1.9.0.8
	perseant-exfatfs-base:1.1.1.9
	netbsd-8-3-RELEASE:1.1.1.6
	netbsd-9-4-RELEASE:1.1.1.8
	netbsd-10-0-RELEASE:1.1.1.9
	netbsd-10-0-RC6:1.1.1.9
	netbsd-10-0-RC5:1.1.1.9
	netbsd-10-0-RC4:1.1.1.9
	netbsd-10-0-RC3:1.1.1.9
	netbsd-10-0-RC2:1.1.1.9
	netbsd-10-0-RC1:1.1.1.9
	netbsd-10:1.1.1.9.0.6
	netbsd-10-base:1.1.1.9
	netbsd-9-3-RELEASE:1.1.1.8
	cjep_sun2x:1.1.1.9.0.4
	cjep_sun2x-base:1.1.1.9
	cjep_staticlib_x-base1:1.1.1.9
	netbsd-9-2-RELEASE:1.1.1.8
	cjep_staticlib_x:1.1.1.9.0.2
	cjep_staticlib_x-base:1.1.1.9
	netbsd-9-1-RELEASE:1.1.1.8
	phil-wifi-20200421:1.1.1.9
	phil-wifi-20200411:1.1.1.9
	phil-wifi-20200406:1.1.1.9
	netbsd-8-2-RELEASE:1.1.1.6
	netbsd-9-0-RELEASE:1.1.1.8
	netbsd-9-0-RC2:1.1.1.8
	netbsd-9-0-RC1:1.1.1.8
	netbsd-9:1.1.1.8.0.2
	netbsd-9-base:1.1.1.8
	phil-wifi-20190609:1.1.1.8
	netbsd-8-1-RELEASE:1.1.1.6
	netbsd-8-1-RC1:1.1.1.6
	pgoyette-compat-merge-20190127:1.1.1.7.2.1
	pgoyette-compat-20190127:1.1.1.8
	pgoyette-compat-20190118:1.1.1.8
	pgoyette-compat-1226:1.1.1.8
	pgoyette-compat-1126:1.1.1.8
	pgoyette-compat-1020:1.1.1.8
	pgoyette-compat-0930:1.1.1.8
	pgoyette-compat-0906:1.1.1.8
	netbsd-7-2-RELEASE:1.1.1.4
	pgoyette-compat-0728:1.1.1.8
	clang-337282:1.1.1.8
	netbsd-8-0-RELEASE:1.1.1.6
	phil-wifi:1.1.1.7.0.4
	phil-wifi-base:1.1.1.7
	pgoyette-compat-0625:1.1.1.7
	netbsd-8-0-RC2:1.1.1.6
	pgoyette-compat-0521:1.1.1.7
	pgoyette-compat-0502:1.1.1.7
	pgoyette-compat-0422:1.1.1.7
	netbsd-8-0-RC1:1.1.1.6
	pgoyette-compat-0415:1.1.1.7
	pgoyette-compat-0407:1.1.1.7
	pgoyette-compat-0330:1.1.1.7
	pgoyette-compat-0322:1.1.1.7
	pgoyette-compat-0315:1.1.1.7
	netbsd-7-1-2-RELEASE:1.1.1.4
	pgoyette-compat:1.1.1.7.0.2
	pgoyette-compat-base:1.1.1.7
	netbsd-7-1-1-RELEASE:1.1.1.4
	clang-319952:1.1.1.7
	matt-nb8-mediatek:1.1.1.6.0.10
	matt-nb8-mediatek-base:1.1.1.6
	clang-309604:1.1.1.7
	perseant-stdc-iso10646:1.1.1.6.0.8
	perseant-stdc-iso10646-base:1.1.1.6
	netbsd-8:1.1.1.6.0.6
	netbsd-8-base:1.1.1.6
	prg-localcount2-base3:1.1.1.6
	prg-localcount2-base2:1.1.1.6
	prg-localcount2-base1:1.1.1.6
	prg-localcount2:1.1.1.6.0.4
	prg-localcount2-base:1.1.1.6
	pgoyette-localcount-20170426:1.1.1.6
	bouyer-socketcan-base1:1.1.1.6
	pgoyette-localcount-20170320:1.1.1.6
	netbsd-7-1:1.1.1.4.0.10
	netbsd-7-1-RELEASE:1.1.1.4
	netbsd-7-1-RC2:1.1.1.4
	clang-294123:1.1.1.6
	netbsd-7-nhusb-base-20170116:1.1.1.4
	bouyer-socketcan:1.1.1.6.0.2
	bouyer-socketcan-base:1.1.1.6
	clang-291444:1.1.1.6
	pgoyette-localcount-20170107:1.1.1.5
	netbsd-7-1-RC1:1.1.1.4
	pgoyette-localcount-20161104:1.1.1.5
	netbsd-7-0-2-RELEASE:1.1.1.4
	localcount-20160914:1.1.1.5
	netbsd-7-nhusb:1.1.1.4.0.8
	netbsd-7-nhusb-base:1.1.1.4
	clang-280599:1.1.1.5
	pgoyette-localcount-20160806:1.1.1.5
	pgoyette-localcount-20160726:1.1.1.5
	pgoyette-localcount:1.1.1.5.0.2
	pgoyette-localcount-base:1.1.1.5
	netbsd-7-0-1-RELEASE:1.1.1.4
	clang-261930:1.1.1.5
	netbsd-7-0:1.1.1.4.0.6
	netbsd-7-0-RELEASE:1.1.1.4
	netbsd-7-0-RC3:1.1.1.4
	netbsd-7-0-RC2:1.1.1.4
	netbsd-7-0-RC1:1.1.1.4
	clang-237755:1.1.1.4
	clang-232565:1.1.1.4
	clang-227398:1.1.1.4
	tls-maxphys-base:1.1.1.4
	tls-maxphys:1.1.1.4.0.4
	netbsd-7:1.1.1.4.0.2
	netbsd-7-base:1.1.1.4
	clang-215315:1.1.1.4
	clang-209886:1.1.1.4
	yamt-pagecache:1.1.1.3.0.4
	yamt-pagecache-base9:1.1.1.3
	tls-earlyentropy:1.1.1.3.0.2
	tls-earlyentropy-base:1.1.1.4
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.3
	riastradh-drm2-base3:1.1.1.3
	clang-202566:1.1.1.3
	clang-201163:1.1.1.2
	clang-199312:1.1.1.2
	clang-198450:1.1.1.2
	clang-196603:1.1.1.1
	clang-195771:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2013.11.28.14.14.52;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	ow8OybrawrB1f3fx;

1.1.1.1
date	2013.11.28.14.14.52;	author joerg;	state Exp;
branches;
next	1.1.1.2;
commitid	ow8OybrawrB1f3fx;

1.1.1.2
date	2014.01.05.15.39.32;	author joerg;	state Exp;
branches;
next	1.1.1.3;
commitid	wh3aCSIWykURqWjx;

1.1.1.3
date	2014.03.04.19.54.57;	author joerg;	state Exp;
branches
	1.1.1.3.2.1
	1.1.1.3.4.1;
next	1.1.1.4;
commitid	29z1hJonZISIXprx;

1.1.1.4
date	2014.05.30.18.14.44;	author joerg;	state Exp;
branches
	1.1.1.4.4.1;
next	1.1.1.5;
commitid	8q0kdlBlCn09GACx;

1.1.1.5
date	2016.02.27.22.12.06;	author joerg;	state Exp;
branches
	1.1.1.5.2.1;
next	1.1.1.6;
commitid	tIimz3oDlh1NpBWy;

1.1.1.6
date	2017.01.11.10.35.39;	author joerg;	state Exp;
branches;
next	1.1.1.7;
commitid	CNnUNfII1jgNmxBz;

1.1.1.7
date	2017.08.01.19.35.16;	author joerg;	state Exp;
branches
	1.1.1.7.2.1
	1.1.1.7.4.1;
next	1.1.1.8;
commitid	pMuDy65V0VicSx1A;

1.1.1.8
date	2018.07.17.18.31.07;	author joerg;	state Exp;
branches;
next	1.1.1.9;
commitid	wDzL46ALjrCZgwKA;

1.1.1.9
date	2019.11.13.22.19.28;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.3.2.1
date	2014.08.10.07.08.10;	author tls;	state Exp;
branches;
next	;
commitid	t01A1TLTYxkpGMLx;

1.1.1.3.4.1
date	2014.03.04.19.54.57;	author yamt;	state dead;
branches;
next	1.1.1.3.4.2;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.3.4.2
date	2014.05.22.16.18.30;	author yamt;	state Exp;
branches;
next	;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.4.4.1
date	2014.05.30.18.14.44;	author tls;	state dead;
branches;
next	1.1.1.4.4.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.4.4.2
date	2014.08.19.23.47.31;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.5.2.1
date	2017.03.20.06.52.42;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.7.2.1
date	2018.07.28.04.33.23;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.7.4.1
date	2019.06.10.21.45.28;	author christos;	state Exp;
branches;
next	1.1.1.7.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.7.4.2
date	2020.04.13.07.46.38;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines CallAndMessageChecker, a builtin checker that checks for various
// errors of call and objc message expressions.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace ento;

namespace {
class CallAndMessageChecker
  : public Checker< check::PreStmt<CallExpr>,
                    check::PreStmt<CXXDeleteExpr>,
                    check::PreObjCMessage,
                    check::PreCall > {
  mutable OwningPtr<BugType> BT_call_null;
  mutable OwningPtr<BugType> BT_call_undef;
  mutable OwningPtr<BugType> BT_cxx_call_null;
  mutable OwningPtr<BugType> BT_cxx_call_undef;
  mutable OwningPtr<BugType> BT_call_arg;
  mutable OwningPtr<BugType> BT_cxx_delete_undef;
  mutable OwningPtr<BugType> BT_msg_undef;
  mutable OwningPtr<BugType> BT_objc_prop_undef;
  mutable OwningPtr<BugType> BT_objc_subscript_undef;
  mutable OwningPtr<BugType> BT_msg_arg;
  mutable OwningPtr<BugType> BT_msg_ret;
  mutable OwningPtr<BugType> BT_call_few_args;
public:

  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

private:
  static bool PreVisitProcessArg(CheckerContext &C, SVal V,
                                 SourceRange argRange, const Expr *argEx,
                                 bool IsFirstArgument, bool checkUninitFields,
                                 const CallEvent &Call, OwningPtr<BugType> &BT);

  static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
                          ExplodedNode *N) const;

  void HandleNilReceiver(CheckerContext &C,
                         ProgramStateRef state,
                         const ObjCMethodCall &msg) const;

  static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
    if (!BT)
      BT.reset(new BuiltinBug(desc));
  }
};
} // end anonymous namespace

void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
                                        const Expr *BadE) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  BugReport *R = new BugReport(*BT, BT->getName(), N);
  if (BadE) {
    R->addRange(BadE->getSourceRange());
    if (BadE->isGLValue())
      BadE = bugreporter::getDerefExpr(BadE);
    bugreporter::trackNullOrUndefValue(N, BadE, *R);
  }
  C.emitReport(R);
}

static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
                                                     bool IsFirstArgument) {
  switch (Call.getKind()) {
  case CE_ObjCMessage: {
    const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
    switch (Msg.getMessageKind()) {
    case OCM_Message:
      return "Argument in message expression is an uninitialized value";
    case OCM_PropertyAccess:
      assert(Msg.isSetter() && "Getters have no args");
      return "Argument for property setter is an uninitialized value";
    case OCM_Subscript:
      if (Msg.isSetter() && IsFirstArgument)
        return "Argument for subscript setter is an uninitialized value";
      return "Subscript index is an uninitialized value";
    }
    llvm_unreachable("Unknown message kind.");
  }
  case CE_Block:
    return "Block call argument is an uninitialized value";
  default:
    return "Function call argument is an uninitialized value";
  }
}

bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V, SourceRange argRange,
                                               const Expr *argEx,
                                               bool IsFirstArgument,
                                               bool checkUninitFields,
                                               const CallEvent &Call,
                                               OwningPtr<BugType> &BT) {
  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT("Uninitialized argument value", BT);

      // Generate a report for this bug.
      StringRef Desc = describeUninitializedArgumentInCall(Call,
                                                           IsFirstArgument);
      BugReport *R = new BugReport(*BT, Desc, N);
      R->addRange(argRange);
      if (argEx)
        bugreporter::trackNullOrUndefValue(N, argEx, *R);
      C.emitReport(R);
    }
    return true;
  }

  if (!checkUninitFields)
    return false;

  if (Optional<nonloc::LazyCompoundVal> LV =
          V.getAs<nonloc::LazyCompoundVal>()) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (RecordDecl::field_iterator I =
               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
            FieldChain.push_back(*I);
            T = I->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT("Uninitialized argument value", BT);
        SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

        // Generate a report for this bug.
        BugReport *R = new BugReport(*BT, os.str(), N);
        R->addRange(argRange);

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.emitReport(R);
      }
      return true;
    }
  }

  return false;
}

void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
                                         CheckerContext &C) const{

  const Expr *Callee = CE->getCallee()->IgnoreParens();
  ProgramStateRef State = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
  SVal L = State->getSVal(Callee, LCtx);

  if (L.isUndef()) {
    if (!BT_call_undef)
      BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
                                         "uninitalized pointer value"));
    emitBadCall(BT_call_undef.get(), C, Callee);
    return;
  }

  ProgramStateRef StNonNull, StNull;
  llvm::tie(StNonNull, StNull) =
      State->assume(L.castAs<DefinedOrUnknownSVal>());

  if (StNull && !StNonNull) {
    if (!BT_call_null)
      BT_call_null.reset(
        new BuiltinBug("Called function pointer is null (null dereference)"));
    emitBadCall(BT_call_null.get(), C, Callee);
    return;
  }

  C.addTransition(StNonNull);
}

void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
                                         CheckerContext &C) const {

  SVal Arg = C.getSVal(DE->getArgument());
  if (Arg.isUndef()) {
    StringRef Desc;
    ExplodedNode *N = C.generateSink();
    if (!N)
      return;
    if (!BT_cxx_delete_undef)
      BT_cxx_delete_undef.reset(new BuiltinBug("Uninitialized argument value"));
    if (DE->isArrayFormAsWritten())
      Desc = "Argument to 'delete[]' is uninitialized";
    else
      Desc = "Argument to 'delete' is uninitialized";
    BugType *BT = BT_cxx_delete_undef.get();
    BugReport *R = new BugReport(*BT, Desc, N);
    bugreporter::trackNullOrUndefValue(N, DE, *R);
    C.emitReport(R);
    return;
  }
}


void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is "
                                               "uninitialized"));
      emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
      return;
    }

    ProgramStateRef StNonNull, StNull;
    llvm::tie(StNonNull, StNull) =
        State->assume(V.castAs<DefinedOrUnknownSVal>());

    if (StNull && !StNonNull) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer "
                                              "is null"));
      emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
      return;
    }

    State = StNonNull;
  }

  const Decl *D = Call.getDecl();
  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
    // If we have a declaration, we can make sure we pass enough parameters to
    // the function.
    unsigned Params = FD->getNumParams();
    if (Call.getNumArgs() < Params) {
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;

      LazyInit_BT("Function call with too few arguments", BT_call_few_args);

      SmallString<512> Str;
      llvm::raw_svector_ostream os(Str);
      os << "Function taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with less ("
         << Call.getNumArgs() << ")";

      BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
      C.emitReport(R);
    }
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  OwningPtr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT))
      return;

  // If we make it here, record our assumptions about the callee.
  C.addTransition(State);
}

void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                CheckerContext &C) const {
  SVal recVal = msg.getReceiverSVal();
  if (recVal.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      BugType *BT = 0;
      switch (msg.getMessageKind()) {
      case OCM_Message:
        if (!BT_msg_undef)
          BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
                                            "is an uninitialized value"));
        BT = BT_msg_undef.get();
        break;
      case OCM_PropertyAccess:
        if (!BT_objc_prop_undef)
          BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
                                                  "uninitialized object "
                                                  "pointer"));
        BT = BT_objc_prop_undef.get();
        break;
      case OCM_Subscript:
        if (!BT_objc_subscript_undef)
          BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an "
                                                       "uninitialized object "
                                                       "pointer"));
        BT = BT_objc_subscript_undef.get();
        break;
      }
      assert(BT && "Unknown message kind.");

      BugReport *R = new BugReport(*BT, BT->getName(), N);
      const ObjCMessageExpr *ME = msg.getOriginExpr();
      R->addRange(ME->getReceiverRange());

      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
      if (const Expr *ReceiverE = ME->getInstanceReceiver())
        bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
      C.emitReport(R);
    }
    return;
  } else {
    // Bifurcate the state into nil and non-nil ones.
    DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();

    ProgramStateRef state = C.getState();
    ProgramStateRef notNilState, nilState;
    llvm::tie(notNilState, nilState) = state->assume(receiverVal);

    // Handle receiver must be nil.
    if (nilState && !notNilState) {
      HandleNilReceiver(C, state, msg);
      return;
    }
  }
}

void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
                                               const ObjCMethodCall &msg,
                                               ExplodedNode *N) const {

  if (!BT_msg_ret)
    BT_msg_ret.reset(
      new BuiltinBug("Receiver in message expression is 'nil'"));

  const ObjCMessageExpr *ME = msg.getOriginExpr();

  QualType ResTy = msg.getResultType();

  SmallString<200> buf;
  llvm::raw_svector_ostream os(buf);
  os << "The receiver of message '" << ME->getSelector().getAsString()
     << "' is nil";
  if (ResTy->isReferenceType()) {
    os << ", which results in forming a null reference";
  } else {
    os << " and returns a value of type '";
    msg.getResultType().print(os, C.getLangOpts());
    os << "' that will be garbage";
  }

  BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
  report->addRange(ME->getReceiverRange());
  // FIXME: This won't track "self" in messages to super.
  if (const Expr *receiver = ME->getInstanceReceiver()) {
    bugreporter::trackNullOrUndefValue(N, receiver, *report);
  }
  C.emitReport(report);
}

static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
  return (triple.getVendor() == llvm::Triple::Apple &&
          (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
}

void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              const ObjCMethodCall &Msg) const {
  ASTContext &Ctx = C.getASTContext();
  static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver");

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = Msg.getResultType();
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(Msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (CanRetTy.getTypePtr()->isReferenceType()||
        (voidPtrSize < returnTypeSize &&
         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
           (Ctx.FloatTy == CanRetTy ||
            Ctx.DoubleTy == CanRetTy ||
            Ctx.LongDoubleTy == CanRetTy ||
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy)))) {
      if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
        emitNilReceiverBug(C, Msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  C.addTransition(state);
}

void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
  mgr.registerChecker<CallAndMessageChecker>();
}
@


1.1.1.1
log
@Import Clang 3.4rc1 r195771.
@
text
@@


1.1.1.2
log
@Import clang 3.5svn r198450.
@
text
@d429 2
a430 3
  os << "The receiver of message '";
  ME->getSelector().print(os);
  os << "' is nil";
@


1.1.1.3
log
@Import Clang 3.5svn r202566.
@
text
@d55 4
a58 4
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
                          const Expr *argEx, bool IsFirstArgument,
                          bool checkUninitFields, const CallEvent &Call,
                          OwningPtr<BugType> &BT) const;
d68 1
a68 1
  void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) const {
d70 1
a70 1
      BT.reset(new BuiltinBug(this, desc));
d122 1
a122 1
                                               OwningPtr<BugType> &BT) const {
d237 2
a238 2
      BT_call_undef.reset(new BuiltinBug(
          this, "Called function pointer is an uninitalized pointer value"));
d249 2
a250 2
      BT_call_null.reset(new BuiltinBug(
          this, "Called function pointer is null (null dereference)"));
d268 1
a268 2
      BT_cxx_delete_undef.reset(
          new BuiltinBug(this, "Uninitialized argument value"));
d292 2
a293 2
        BT_cxx_call_undef.reset(
            new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
d304 2
a305 2
        BT_cxx_call_null.reset(
            new BuiltinBug(this, "Called C++ object pointer is null"));
d368 1
a368 2
          BT_msg_undef.reset(new BuiltinBug(this,
                                            "Receiver in message expression "
d374 3
a376 2
          BT_objc_prop_undef.reset(new BuiltinBug(
              this, "Property access on an uninitialized object pointer"));
d381 3
a383 2
          BT_objc_subscript_undef.reset(new BuiltinBug(
              this, "Subscript access on an uninitialized object pointer"));
d421 1
a421 1
        new BuiltinBug(this, "Receiver in message expression is 'nil'"));
d458 1
a458 1
  static CheckerProgramPointTag Tag(this, "NilReceiver");
@


1.1.1.3.2.1
log
@Rebase.
@
text
@a29 9

struct ChecksFilter {
  DefaultBool Check_CallAndMessageUnInitRefArg;
  DefaultBool Check_CallAndMessageChecker;

  CheckName CheckName_CallAndMessageUnInitRefArg;
  CheckName CheckName_CallAndMessageChecker;
};

d35 12
a46 13
  mutable std::unique_ptr<BugType> BT_call_null;
  mutable std::unique_ptr<BugType> BT_call_undef;
  mutable std::unique_ptr<BugType> BT_cxx_call_null;
  mutable std::unique_ptr<BugType> BT_cxx_call_undef;
  mutable std::unique_ptr<BugType> BT_call_arg;
  mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
  mutable std::unique_ptr<BugType> BT_msg_undef;
  mutable std::unique_ptr<BugType> BT_objc_prop_undef;
  mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
  mutable std::unique_ptr<BugType> BT_msg_arg;
  mutable std::unique_ptr<BugType> BT_msg_ret;
  mutable std::unique_ptr<BugType> BT_call_few_args;

a47 1
  ChecksFilter Filter;
d55 4
a58 5
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
                          const Expr *ArgEx, bool IsFirstArgument,
                          bool CheckUninitFields, const CallEvent &Call,
                          std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl) const;
d68 1
a68 1
  void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
a71 4
  bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
                          const SourceRange &ArgRange,
                          const Expr *ArgEx, std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl, const char *BD) const;
a115 48
bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
                                               const SVal &V,
                                               const SourceRange &ArgRange,
                                               const Expr *ArgEx,
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl,
                                               const char *BD) const {
  if (!Filter.Check_CallAndMessageUnInitRefArg)
    return false;

  // No parameter declaration available, i.e. variadic function argument.
  if(!ParamDecl)
    return false;

  // If parameter is declared as pointer to const in function declaration,
  // then check if corresponding argument in function call is
  // pointing to undefined symbol value (uninitialized memory).
  StringRef Message;

  if (ParamDecl->getType()->isPointerType()) {
    Message = "Function call argument is a pointer to uninitialized value";
  } else if (ParamDecl->getType()->isReferenceType()) {
    Message = "Function call argument is an uninitialized value";
  } else
    return false;

  if(!ParamDecl->getType()->getPointeeType().isConstQualified())
    return false;

  if (const MemRegion *SValMemRegion = V.getAsRegion()) {
    const ProgramStateRef State = C.getState();
    const SVal PSV = State->getSVal(SValMemRegion);
    if (PSV.isUndef()) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BD, BT);
        BugReport *R = new BugReport(*BT, Message, N);
        R->addRange(ArgRange);
        if (ArgEx) {
          bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
        }
        C.emitReport(R);
      }
      return true;
    }
  }
  return false;
}

d117 2
a118 3
                                               SVal V,
                                               SourceRange ArgRange,
                                               const Expr *ArgEx,
d120 1
a120 1
                                               bool CheckUninitFields,
d122 1
a122 8
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl
                                               ) const {
  const char *BD = "Uninitialized argument value";

  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
    return true;

d125 1
a125 1
      LazyInit_BT(BD, BT);
d128 2
a129 2
      StringRef Desc =
          describeUninitializedArgumentInCall(Call, IsFirstArgument);
d131 3
a133 3
      R->addRange(ArgRange);
      if (ArgEx)
        bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
d139 1
a139 1
  if (!CheckUninitFields)
d162 4
a165 3
          for (const auto *I : RD->fields()) {
            const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
            FieldChain.push_back(I);
d191 1
a191 1
        LazyInit_BT(BD, BT);
d214 1
a214 1
        R->addRange(ArgRange);
d244 2
a245 1
  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
d300 1
a300 1
    std::tie(StNonNull, StNull) =
d315 1
a315 2
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
  if (FD) {
d344 1
a344 1
  std::unique_ptr<BugType> *BT;
d350 1
a350 4
  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
    const ParmVarDecl *ParamDecl = nullptr;
    if(FD && i < FD->getNumParams())
      ParamDecl = FD->getParamDecl(i);
d353 1
a353 1
                           checkUninitFields, Call, *BT, ParamDecl))
a354 1
  }
d365 1
a365 1
      BugType *BT = nullptr;
d405 1
a405 1
    std::tie(notNilState, nilState) = state->assume(receiverVal);
d488 1
a488 1
      if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
d514 3
a516 10
#define REGISTER_CHECKER(name)                                                 \
  void ento::register##name(CheckerManager &mgr) {                             \
    CallAndMessageChecker *Checker =                                           \
        mgr.registerChecker<CallAndMessageChecker>();                          \
    Checker->Filter.Check_##name = true;                                       \
    Checker->Filter.CheckName_##name = mgr.getCurrentCheckName();              \
  }

REGISTER_CHECKER(CallAndMessageUnInitRefArg)
REGISTER_CHECKER(CallAndMessageChecker)
@


1.1.1.4
log
@Import Clang 3.5svn r209886.
@
text
@a29 9

struct ChecksFilter {
  DefaultBool Check_CallAndMessageUnInitRefArg;
  DefaultBool Check_CallAndMessageChecker;

  CheckName CheckName_CallAndMessageUnInitRefArg;
  CheckName CheckName_CallAndMessageChecker;
};

d35 12
a46 13
  mutable std::unique_ptr<BugType> BT_call_null;
  mutable std::unique_ptr<BugType> BT_call_undef;
  mutable std::unique_ptr<BugType> BT_cxx_call_null;
  mutable std::unique_ptr<BugType> BT_cxx_call_undef;
  mutable std::unique_ptr<BugType> BT_call_arg;
  mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
  mutable std::unique_ptr<BugType> BT_msg_undef;
  mutable std::unique_ptr<BugType> BT_objc_prop_undef;
  mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
  mutable std::unique_ptr<BugType> BT_msg_arg;
  mutable std::unique_ptr<BugType> BT_msg_ret;
  mutable std::unique_ptr<BugType> BT_call_few_args;

a47 1
  ChecksFilter Filter;
d55 4
a58 5
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
                          const Expr *ArgEx, bool IsFirstArgument,
                          bool CheckUninitFields, const CallEvent &Call,
                          std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl) const;
d68 1
a68 1
  void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
a71 4
  bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
                          const SourceRange &ArgRange,
                          const Expr *ArgEx, std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl, const char *BD) const;
a115 48
bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
                                               const SVal &V,
                                               const SourceRange &ArgRange,
                                               const Expr *ArgEx,
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl,
                                               const char *BD) const {
  if (!Filter.Check_CallAndMessageUnInitRefArg)
    return false;

  // No parameter declaration available, i.e. variadic function argument.
  if(!ParamDecl)
    return false;

  // If parameter is declared as pointer to const in function declaration,
  // then check if corresponding argument in function call is
  // pointing to undefined symbol value (uninitialized memory).
  StringRef Message;

  if (ParamDecl->getType()->isPointerType()) {
    Message = "Function call argument is a pointer to uninitialized value";
  } else if (ParamDecl->getType()->isReferenceType()) {
    Message = "Function call argument is an uninitialized value";
  } else
    return false;

  if(!ParamDecl->getType()->getPointeeType().isConstQualified())
    return false;

  if (const MemRegion *SValMemRegion = V.getAsRegion()) {
    const ProgramStateRef State = C.getState();
    const SVal PSV = State->getSVal(SValMemRegion);
    if (PSV.isUndef()) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BD, BT);
        BugReport *R = new BugReport(*BT, Message, N);
        R->addRange(ArgRange);
        if (ArgEx) {
          bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
        }
        C.emitReport(R);
      }
      return true;
    }
  }
  return false;
}

d117 2
a118 3
                                               SVal V,
                                               SourceRange ArgRange,
                                               const Expr *ArgEx,
d120 1
a120 1
                                               bool CheckUninitFields,
d122 1
a122 8
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl
                                               ) const {
  const char *BD = "Uninitialized argument value";

  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
    return true;

d125 1
a125 1
      LazyInit_BT(BD, BT);
d128 2
a129 2
      StringRef Desc =
          describeUninitializedArgumentInCall(Call, IsFirstArgument);
d131 3
a133 3
      R->addRange(ArgRange);
      if (ArgEx)
        bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
d139 1
a139 1
  if (!CheckUninitFields)
d162 4
a165 3
          for (const auto *I : RD->fields()) {
            const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
            FieldChain.push_back(I);
d191 1
a191 1
        LazyInit_BT(BD, BT);
d214 1
a214 1
        R->addRange(ArgRange);
d244 2
a245 1
  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
d300 1
a300 1
    std::tie(StNonNull, StNull) =
d315 1
a315 2
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
  if (FD) {
d344 1
a344 1
  std::unique_ptr<BugType> *BT;
d350 1
a350 4
  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
    const ParmVarDecl *ParamDecl = nullptr;
    if(FD && i < FD->getNumParams())
      ParamDecl = FD->getParamDecl(i);
d353 1
a353 1
                           checkUninitFields, Call, *BT, ParamDecl))
a354 1
  }
d365 1
a365 1
      BugType *BT = nullptr;
d405 1
a405 1
    std::tie(notNilState, nilState) = state->assume(receiverVal);
d488 1
a488 1
      if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
d514 3
a516 10
#define REGISTER_CHECKER(name)                                                 \
  void ento::register##name(CheckerManager &mgr) {                             \
    CallAndMessageChecker *Checker =                                           \
        mgr.registerChecker<CallAndMessageChecker>();                          \
    Checker->Filter.Check_##name = true;                                       \
    Checker->Filter.CheckName_##name = mgr.getCurrentCheckName();              \
  }

REGISTER_CHECKER(CallAndMessageUnInitRefArg)
REGISTER_CHECKER(CallAndMessageChecker)
@


1.1.1.5
log
@Import Clang 3.8.0rc3 r261930.
@
text
@a42 1
                    check::ObjCMessageNil,
a62 6

  /// Fill in the return value that results from messaging nil based on the
  /// return type and architecture and diagnose if the return value will be
  /// garbage.
  void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;

d85 1
a85 1
                          SourceRange ArgRange,
d93 1
a93 1
  ExplodedNode *N = C.generateErrorNode();
d97 1
a97 1
  auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
d104 1
a104 1
  C.emitReport(std::move(R));
d134 1
a134 1
                                               SourceRange ArgRange,
d165 1
a165 1
      if (ExplodedNode *N = C.generateErrorNode()) {
d167 1
a167 1
        auto R = llvm::make_unique<BugReport>(*BT, Message, N);
d172 1
a172 1
        C.emitReport(std::move(R));
d196 1
a196 1
    if (ExplodedNode *N = C.generateErrorNode()) {
d202 1
a202 1
      auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
d206 1
a206 1
      C.emitReport(std::move(R));
d261 1
a261 1
      if (ExplodedNode *N = C.generateErrorNode()) {
d284 1
a284 1
        auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
d289 1
a289 1
        C.emitReport(std::move(R));
d334 1
a334 1
    ExplodedNode *N = C.generateErrorNode();
d345 1
a345 1
    auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
d347 1
a347 1
    C.emitReport(std::move(R));
d391 1
a391 1
      ExplodedNode *N = C.generateErrorNode();
d403 2
a404 2
      C.emitReport(
          llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
d439 1
a439 1
    if (ExplodedNode *N = C.generateErrorNode()) {
d464 1
a464 1
      auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
d471 1
a471 1
      C.emitReport(std::move(R));
d474 13
a489 5
void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
                                                CheckerContext &C) const {
  HandleNilReceiver(C, C.getState(), msg);
}

d515 1
a515 1
  auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
d521 1
a521 1
  C.emitReport(std::move(report));
d526 1
a526 2
          (triple.isiOS() || triple.isWatchOS() ||
           !triple.isMacOSXVersionLT(10,5)));
d563 1
a563 1
      if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
@


1.1.1.5.2.1
log
@Sync with HEAD
@
text
@d316 1
a316 1
          this, "Called function pointer is an uninitialized pointer value"));
d359 1
d392 5
a396 4
  if (D && (isa<FunctionDecl>(D) || isa<BlockDecl>(D))) {
    // If we have a function or block declaration, we can make sure we pass
    // enough parameters.
    unsigned Params = Call.parameters().size();
d406 2
a407 8
      if (isa<FunctionDecl>(D)) {
        os << "Function ";
      } else {
        assert(isa<BlockDecl>(D));
        os << "Block ";
      }
      os << "taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with fewer ("
a427 1
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
@


1.1.1.6
log
@Import Clang pre-4.0.0 r291444.
@
text
@d316 1
a316 1
          this, "Called function pointer is an uninitialized pointer value"));
d359 1
d392 5
a396 4
  if (D && (isa<FunctionDecl>(D) || isa<BlockDecl>(D))) {
    // If we have a function or block declaration, we can make sure we pass
    // enough parameters.
    unsigned Params = Call.parameters().size();
d406 2
a407 8
      if (isa<FunctionDecl>(D)) {
        os << "Function ";
      } else {
        assert(isa<BlockDecl>(D));
        os << "Block ";
      }
      os << "taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with fewer ("
a427 1
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
@


1.1.1.7
log
@Import clang r309604 from branches/release_50
@
text
@a23 1
#include "llvm/ADT/StringExtras.h"
d74 1
a74 1
                          const Expr *ArgEx, int ArgumentNumber,
d92 3
a94 4
                          SourceRange ArgRange, const Expr *ArgEx,
                          std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl, const char *BD,
                          int ArgumentNumber) const;
d114 2
a115 3
static void describeUninitializedArgumentInCall(const CallEvent &Call,
                                                int ArgumentNumber,
                                                llvm::raw_svector_ostream &Os) {
d121 1
a121 3
      Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
         << " argument in message expression is an uninitialized value";
      return;
d124 1
a124 2
      Os << "Argument for property setter is an uninitialized value";
      return;
d126 3
a128 5
      if (Msg.isSetter() && (ArgumentNumber == 0))
        Os << "Argument for subscript setter is an uninitialized value";
      else
        Os << "Subscript index is an uninitialized value";
      return;
d133 1
a133 3
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
       << " block call argument is an uninitialized value";
    return;
d135 1
a135 3
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
       << " function call argument is an uninitialized value";
    return;
d139 7
a145 4
bool CallAndMessageChecker::uninitRefOrPointer(
    CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
    std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
    int ArgumentNumber) const {
d156 1
a156 2
  SmallString<200> Buf;
  llvm::raw_svector_ostream Os(Buf);
d159 1
a159 2
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
       << " function call argument is a pointer to uninitialized value";
d161 1
a161 2
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
       << " function call argument is an uninitialized value";
d174 1
a174 1
        auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
d191 1
a191 1
                                               int ArgumentNumber,
d199 1
a199 2
  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
                         ArgumentNumber))
d205 1
d207 3
a209 5
      SmallString<200> Buf;
      llvm::raw_svector_ostream Os(Buf);
      describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
      auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);

d438 1
a438 1
                           Call.getArgExpr(i), i,
@


1.1.1.7.4.1
log
@Sync with HEAD
@
text
@d182 1
a182 1
    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
@


1.1.1.7.4.2
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.7.2.1
log
@Sync with HEAD
@
text
@d182 1
a182 1
    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
@


1.1.1.8
log
@Import clang r337282 from trunk
@
text
@d182 1
a182 1
    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
@


1.1.1.9
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.4.4.1
log
@file CallAndMessageChecker.cpp was added on branch tls-maxphys on 2014-08-19 23:47:31 +0000
@
text
@d1 598
@


1.1.1.4.4.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 598
//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines CallAndMessageChecker, a builtin checker that checks for various
// errors of call and objc message expressions.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace ento;

namespace {

struct ChecksFilter {
  DefaultBool Check_CallAndMessageUnInitRefArg;
  DefaultBool Check_CallAndMessageChecker;

  CheckName CheckName_CallAndMessageUnInitRefArg;
  CheckName CheckName_CallAndMessageChecker;
};

class CallAndMessageChecker
  : public Checker< check::PreStmt<CallExpr>,
                    check::PreStmt<CXXDeleteExpr>,
                    check::PreObjCMessage,
                    check::PreCall > {
  mutable std::unique_ptr<BugType> BT_call_null;
  mutable std::unique_ptr<BugType> BT_call_undef;
  mutable std::unique_ptr<BugType> BT_cxx_call_null;
  mutable std::unique_ptr<BugType> BT_cxx_call_undef;
  mutable std::unique_ptr<BugType> BT_call_arg;
  mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
  mutable std::unique_ptr<BugType> BT_msg_undef;
  mutable std::unique_ptr<BugType> BT_objc_prop_undef;
  mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
  mutable std::unique_ptr<BugType> BT_msg_arg;
  mutable std::unique_ptr<BugType> BT_msg_ret;
  mutable std::unique_ptr<BugType> BT_call_few_args;

public:
  ChecksFilter Filter;

  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

private:
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
                          const Expr *ArgEx, bool IsFirstArgument,
                          bool CheckUninitFields, const CallEvent &Call,
                          std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl) const;

  static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
                          ExplodedNode *N) const;

  void HandleNilReceiver(CheckerContext &C,
                         ProgramStateRef state,
                         const ObjCMethodCall &msg) const;

  void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
    if (!BT)
      BT.reset(new BuiltinBug(this, desc));
  }
  bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
                          const SourceRange &ArgRange,
                          const Expr *ArgEx, std::unique_ptr<BugType> &BT,
                          const ParmVarDecl *ParamDecl, const char *BD) const;
};
} // end anonymous namespace

void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
                                        const Expr *BadE) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  BugReport *R = new BugReport(*BT, BT->getName(), N);
  if (BadE) {
    R->addRange(BadE->getSourceRange());
    if (BadE->isGLValue())
      BadE = bugreporter::getDerefExpr(BadE);
    bugreporter::trackNullOrUndefValue(N, BadE, *R);
  }
  C.emitReport(R);
}

static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
                                                     bool IsFirstArgument) {
  switch (Call.getKind()) {
  case CE_ObjCMessage: {
    const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
    switch (Msg.getMessageKind()) {
    case OCM_Message:
      return "Argument in message expression is an uninitialized value";
    case OCM_PropertyAccess:
      assert(Msg.isSetter() && "Getters have no args");
      return "Argument for property setter is an uninitialized value";
    case OCM_Subscript:
      if (Msg.isSetter() && IsFirstArgument)
        return "Argument for subscript setter is an uninitialized value";
      return "Subscript index is an uninitialized value";
    }
    llvm_unreachable("Unknown message kind.");
  }
  case CE_Block:
    return "Block call argument is an uninitialized value";
  default:
    return "Function call argument is an uninitialized value";
  }
}

bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
                                               const SVal &V,
                                               const SourceRange &ArgRange,
                                               const Expr *ArgEx,
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl,
                                               const char *BD) const {
  if (!Filter.Check_CallAndMessageUnInitRefArg)
    return false;

  // No parameter declaration available, i.e. variadic function argument.
  if(!ParamDecl)
    return false;

  // If parameter is declared as pointer to const in function declaration,
  // then check if corresponding argument in function call is
  // pointing to undefined symbol value (uninitialized memory).
  StringRef Message;

  if (ParamDecl->getType()->isPointerType()) {
    Message = "Function call argument is a pointer to uninitialized value";
  } else if (ParamDecl->getType()->isReferenceType()) {
    Message = "Function call argument is an uninitialized value";
  } else
    return false;

  if(!ParamDecl->getType()->getPointeeType().isConstQualified())
    return false;

  if (const MemRegion *SValMemRegion = V.getAsRegion()) {
    const ProgramStateRef State = C.getState();
    const SVal PSV = State->getSVal(SValMemRegion);
    if (PSV.isUndef()) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BD, BT);
        BugReport *R = new BugReport(*BT, Message, N);
        R->addRange(ArgRange);
        if (ArgEx) {
          bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
        }
        C.emitReport(R);
      }
      return true;
    }
  }
  return false;
}

bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V,
                                               SourceRange ArgRange,
                                               const Expr *ArgEx,
                                               bool IsFirstArgument,
                                               bool CheckUninitFields,
                                               const CallEvent &Call,
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl
                                               ) const {
  const char *BD = "Uninitialized argument value";

  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
    return true;

  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT(BD, BT);

      // Generate a report for this bug.
      StringRef Desc =
          describeUninitializedArgumentInCall(Call, IsFirstArgument);
      BugReport *R = new BugReport(*BT, Desc, N);
      R->addRange(ArgRange);
      if (ArgEx)
        bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
      C.emitReport(R);
    }
    return true;
  }

  if (!CheckUninitFields)
    return false;

  if (Optional<nonloc::LazyCompoundVal> LV =
          V.getAs<nonloc::LazyCompoundVal>()) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (const auto *I : RD->fields()) {
            const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
            FieldChain.push_back(I);
            T = I->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BD, BT);
        SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

        // Generate a report for this bug.
        BugReport *R = new BugReport(*BT, os.str(), N);
        R->addRange(ArgRange);

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.emitReport(R);
      }
      return true;
    }
  }

  return false;
}

void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
                                         CheckerContext &C) const{

  const Expr *Callee = CE->getCallee()->IgnoreParens();
  ProgramStateRef State = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
  SVal L = State->getSVal(Callee, LCtx);

  if (L.isUndef()) {
    if (!BT_call_undef)
      BT_call_undef.reset(new BuiltinBug(
          this, "Called function pointer is an uninitalized pointer value"));
    emitBadCall(BT_call_undef.get(), C, Callee);
    return;
  }

  ProgramStateRef StNonNull, StNull;
  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());

  if (StNull && !StNonNull) {
    if (!BT_call_null)
      BT_call_null.reset(new BuiltinBug(
          this, "Called function pointer is null (null dereference)"));
    emitBadCall(BT_call_null.get(), C, Callee);
    return;
  }

  C.addTransition(StNonNull);
}

void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
                                         CheckerContext &C) const {

  SVal Arg = C.getSVal(DE->getArgument());
  if (Arg.isUndef()) {
    StringRef Desc;
    ExplodedNode *N = C.generateSink();
    if (!N)
      return;
    if (!BT_cxx_delete_undef)
      BT_cxx_delete_undef.reset(
          new BuiltinBug(this, "Uninitialized argument value"));
    if (DE->isArrayFormAsWritten())
      Desc = "Argument to 'delete[]' is uninitialized";
    else
      Desc = "Argument to 'delete' is uninitialized";
    BugType *BT = BT_cxx_delete_undef.get();
    BugReport *R = new BugReport(*BT, Desc, N);
    bugreporter::trackNullOrUndefValue(N, DE, *R);
    C.emitReport(R);
    return;
  }
}


void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(
            new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
      emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
      return;
    }

    ProgramStateRef StNonNull, StNull;
    std::tie(StNonNull, StNull) =
        State->assume(V.castAs<DefinedOrUnknownSVal>());

    if (StNull && !StNonNull) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(
            new BuiltinBug(this, "Called C++ object pointer is null"));
      emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
      return;
    }

    State = StNonNull;
  }

  const Decl *D = Call.getDecl();
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
  if (FD) {
    // If we have a declaration, we can make sure we pass enough parameters to
    // the function.
    unsigned Params = FD->getNumParams();
    if (Call.getNumArgs() < Params) {
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;

      LazyInit_BT("Function call with too few arguments", BT_call_few_args);

      SmallString<512> Str;
      llvm::raw_svector_ostream os(Str);
      os << "Function taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with less ("
         << Call.getNumArgs() << ")";

      BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
      C.emitReport(R);
    }
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  std::unique_ptr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
    const ParmVarDecl *ParamDecl = nullptr;
    if(FD && i < FD->getNumParams())
      ParamDecl = FD->getParamDecl(i);
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT, ParamDecl))
      return;
  }

  // If we make it here, record our assumptions about the callee.
  C.addTransition(State);
}

void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                CheckerContext &C) const {
  SVal recVal = msg.getReceiverSVal();
  if (recVal.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      BugType *BT = nullptr;
      switch (msg.getMessageKind()) {
      case OCM_Message:
        if (!BT_msg_undef)
          BT_msg_undef.reset(new BuiltinBug(this,
                                            "Receiver in message expression "
                                            "is an uninitialized value"));
        BT = BT_msg_undef.get();
        break;
      case OCM_PropertyAccess:
        if (!BT_objc_prop_undef)
          BT_objc_prop_undef.reset(new BuiltinBug(
              this, "Property access on an uninitialized object pointer"));
        BT = BT_objc_prop_undef.get();
        break;
      case OCM_Subscript:
        if (!BT_objc_subscript_undef)
          BT_objc_subscript_undef.reset(new BuiltinBug(
              this, "Subscript access on an uninitialized object pointer"));
        BT = BT_objc_subscript_undef.get();
        break;
      }
      assert(BT && "Unknown message kind.");

      BugReport *R = new BugReport(*BT, BT->getName(), N);
      const ObjCMessageExpr *ME = msg.getOriginExpr();
      R->addRange(ME->getReceiverRange());

      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
      if (const Expr *ReceiverE = ME->getInstanceReceiver())
        bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
      C.emitReport(R);
    }
    return;
  } else {
    // Bifurcate the state into nil and non-nil ones.
    DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();

    ProgramStateRef state = C.getState();
    ProgramStateRef notNilState, nilState;
    std::tie(notNilState, nilState) = state->assume(receiverVal);

    // Handle receiver must be nil.
    if (nilState && !notNilState) {
      HandleNilReceiver(C, state, msg);
      return;
    }
  }
}

void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
                                               const ObjCMethodCall &msg,
                                               ExplodedNode *N) const {

  if (!BT_msg_ret)
    BT_msg_ret.reset(
        new BuiltinBug(this, "Receiver in message expression is 'nil'"));

  const ObjCMessageExpr *ME = msg.getOriginExpr();

  QualType ResTy = msg.getResultType();

  SmallString<200> buf;
  llvm::raw_svector_ostream os(buf);
  os << "The receiver of message '";
  ME->getSelector().print(os);
  os << "' is nil";
  if (ResTy->isReferenceType()) {
    os << ", which results in forming a null reference";
  } else {
    os << " and returns a value of type '";
    msg.getResultType().print(os, C.getLangOpts());
    os << "' that will be garbage";
  }

  BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
  report->addRange(ME->getReceiverRange());
  // FIXME: This won't track "self" in messages to super.
  if (const Expr *receiver = ME->getInstanceReceiver()) {
    bugreporter::trackNullOrUndefValue(N, receiver, *report);
  }
  C.emitReport(report);
}

static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
  return (triple.getVendor() == llvm::Triple::Apple &&
          (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
}

void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              const ObjCMethodCall &Msg) const {
  ASTContext &Ctx = C.getASTContext();
  static CheckerProgramPointTag Tag(this, "NilReceiver");

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = Msg.getResultType();
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(Msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (CanRetTy.getTypePtr()->isReferenceType()||
        (voidPtrSize < returnTypeSize &&
         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
           (Ctx.FloatTy == CanRetTy ||
            Ctx.DoubleTy == CanRetTy ||
            Ctx.LongDoubleTy == CanRetTy ||
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy)))) {
      if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
        emitNilReceiverBug(C, Msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  C.addTransition(state);
}

#define REGISTER_CHECKER(name)                                                 \
  void ento::register##name(CheckerManager &mgr) {                             \
    CallAndMessageChecker *Checker =                                           \
        mgr.registerChecker<CallAndMessageChecker>();                          \
    Checker->Filter.Check_##name = true;                                       \
    Checker->Filter.CheckName_##name = mgr.getCurrentCheckName();              \
  }

REGISTER_CHECKER(CallAndMessageUnInitRefArg)
REGISTER_CHECKER(CallAndMessageChecker)
@


1.1.1.3.4.1
log
@file CallAndMessageChecker.cpp was added on branch yamt-pagecache on 2014-05-22 16:18:30 +0000
@
text
@d1 516
@


1.1.1.3.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 516
//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines CallAndMessageChecker, a builtin checker that checks for various
// errors of call and objc message expressions.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace ento;

namespace {
class CallAndMessageChecker
  : public Checker< check::PreStmt<CallExpr>,
                    check::PreStmt<CXXDeleteExpr>,
                    check::PreObjCMessage,
                    check::PreCall > {
  mutable OwningPtr<BugType> BT_call_null;
  mutable OwningPtr<BugType> BT_call_undef;
  mutable OwningPtr<BugType> BT_cxx_call_null;
  mutable OwningPtr<BugType> BT_cxx_call_undef;
  mutable OwningPtr<BugType> BT_call_arg;
  mutable OwningPtr<BugType> BT_cxx_delete_undef;
  mutable OwningPtr<BugType> BT_msg_undef;
  mutable OwningPtr<BugType> BT_objc_prop_undef;
  mutable OwningPtr<BugType> BT_objc_subscript_undef;
  mutable OwningPtr<BugType> BT_msg_arg;
  mutable OwningPtr<BugType> BT_msg_ret;
  mutable OwningPtr<BugType> BT_call_few_args;
public:

  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

private:
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
                          const Expr *argEx, bool IsFirstArgument,
                          bool checkUninitFields, const CallEvent &Call,
                          OwningPtr<BugType> &BT) const;

  static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
                          ExplodedNode *N) const;

  void HandleNilReceiver(CheckerContext &C,
                         ProgramStateRef state,
                         const ObjCMethodCall &msg) const;

  void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) const {
    if (!BT)
      BT.reset(new BuiltinBug(this, desc));
  }
};
} // end anonymous namespace

void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
                                        const Expr *BadE) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  BugReport *R = new BugReport(*BT, BT->getName(), N);
  if (BadE) {
    R->addRange(BadE->getSourceRange());
    if (BadE->isGLValue())
      BadE = bugreporter::getDerefExpr(BadE);
    bugreporter::trackNullOrUndefValue(N, BadE, *R);
  }
  C.emitReport(R);
}

static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
                                                     bool IsFirstArgument) {
  switch (Call.getKind()) {
  case CE_ObjCMessage: {
    const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
    switch (Msg.getMessageKind()) {
    case OCM_Message:
      return "Argument in message expression is an uninitialized value";
    case OCM_PropertyAccess:
      assert(Msg.isSetter() && "Getters have no args");
      return "Argument for property setter is an uninitialized value";
    case OCM_Subscript:
      if (Msg.isSetter() && IsFirstArgument)
        return "Argument for subscript setter is an uninitialized value";
      return "Subscript index is an uninitialized value";
    }
    llvm_unreachable("Unknown message kind.");
  }
  case CE_Block:
    return "Block call argument is an uninitialized value";
  default:
    return "Function call argument is an uninitialized value";
  }
}

bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V, SourceRange argRange,
                                               const Expr *argEx,
                                               bool IsFirstArgument,
                                               bool checkUninitFields,
                                               const CallEvent &Call,
                                               OwningPtr<BugType> &BT) const {
  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT("Uninitialized argument value", BT);

      // Generate a report for this bug.
      StringRef Desc = describeUninitializedArgumentInCall(Call,
                                                           IsFirstArgument);
      BugReport *R = new BugReport(*BT, Desc, N);
      R->addRange(argRange);
      if (argEx)
        bugreporter::trackNullOrUndefValue(N, argEx, *R);
      C.emitReport(R);
    }
    return true;
  }

  if (!checkUninitFields)
    return false;

  if (Optional<nonloc::LazyCompoundVal> LV =
          V.getAs<nonloc::LazyCompoundVal>()) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (RecordDecl::field_iterator I =
               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
            FieldChain.push_back(*I);
            T = I->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT("Uninitialized argument value", BT);
        SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

        // Generate a report for this bug.
        BugReport *R = new BugReport(*BT, os.str(), N);
        R->addRange(argRange);

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.emitReport(R);
      }
      return true;
    }
  }

  return false;
}

void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
                                         CheckerContext &C) const{

  const Expr *Callee = CE->getCallee()->IgnoreParens();
  ProgramStateRef State = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
  SVal L = State->getSVal(Callee, LCtx);

  if (L.isUndef()) {
    if (!BT_call_undef)
      BT_call_undef.reset(new BuiltinBug(
          this, "Called function pointer is an uninitalized pointer value"));
    emitBadCall(BT_call_undef.get(), C, Callee);
    return;
  }

  ProgramStateRef StNonNull, StNull;
  llvm::tie(StNonNull, StNull) =
      State->assume(L.castAs<DefinedOrUnknownSVal>());

  if (StNull && !StNonNull) {
    if (!BT_call_null)
      BT_call_null.reset(new BuiltinBug(
          this, "Called function pointer is null (null dereference)"));
    emitBadCall(BT_call_null.get(), C, Callee);
    return;
  }

  C.addTransition(StNonNull);
}

void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
                                         CheckerContext &C) const {

  SVal Arg = C.getSVal(DE->getArgument());
  if (Arg.isUndef()) {
    StringRef Desc;
    ExplodedNode *N = C.generateSink();
    if (!N)
      return;
    if (!BT_cxx_delete_undef)
      BT_cxx_delete_undef.reset(
          new BuiltinBug(this, "Uninitialized argument value"));
    if (DE->isArrayFormAsWritten())
      Desc = "Argument to 'delete[]' is uninitialized";
    else
      Desc = "Argument to 'delete' is uninitialized";
    BugType *BT = BT_cxx_delete_undef.get();
    BugReport *R = new BugReport(*BT, Desc, N);
    bugreporter::trackNullOrUndefValue(N, DE, *R);
    C.emitReport(R);
    return;
  }
}


void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(
            new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
      emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
      return;
    }

    ProgramStateRef StNonNull, StNull;
    llvm::tie(StNonNull, StNull) =
        State->assume(V.castAs<DefinedOrUnknownSVal>());

    if (StNull && !StNonNull) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(
            new BuiltinBug(this, "Called C++ object pointer is null"));
      emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
      return;
    }

    State = StNonNull;
  }

  const Decl *D = Call.getDecl();
  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
    // If we have a declaration, we can make sure we pass enough parameters to
    // the function.
    unsigned Params = FD->getNumParams();
    if (Call.getNumArgs() < Params) {
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;

      LazyInit_BT("Function call with too few arguments", BT_call_few_args);

      SmallString<512> Str;
      llvm::raw_svector_ostream os(Str);
      os << "Function taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with less ("
         << Call.getNumArgs() << ")";

      BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
      C.emitReport(R);
    }
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  OwningPtr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT))
      return;

  // If we make it here, record our assumptions about the callee.
  C.addTransition(State);
}

void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                CheckerContext &C) const {
  SVal recVal = msg.getReceiverSVal();
  if (recVal.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      BugType *BT = 0;
      switch (msg.getMessageKind()) {
      case OCM_Message:
        if (!BT_msg_undef)
          BT_msg_undef.reset(new BuiltinBug(this,
                                            "Receiver in message expression "
                                            "is an uninitialized value"));
        BT = BT_msg_undef.get();
        break;
      case OCM_PropertyAccess:
        if (!BT_objc_prop_undef)
          BT_objc_prop_undef.reset(new BuiltinBug(
              this, "Property access on an uninitialized object pointer"));
        BT = BT_objc_prop_undef.get();
        break;
      case OCM_Subscript:
        if (!BT_objc_subscript_undef)
          BT_objc_subscript_undef.reset(new BuiltinBug(
              this, "Subscript access on an uninitialized object pointer"));
        BT = BT_objc_subscript_undef.get();
        break;
      }
      assert(BT && "Unknown message kind.");

      BugReport *R = new BugReport(*BT, BT->getName(), N);
      const ObjCMessageExpr *ME = msg.getOriginExpr();
      R->addRange(ME->getReceiverRange());

      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
      if (const Expr *ReceiverE = ME->getInstanceReceiver())
        bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
      C.emitReport(R);
    }
    return;
  } else {
    // Bifurcate the state into nil and non-nil ones.
    DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();

    ProgramStateRef state = C.getState();
    ProgramStateRef notNilState, nilState;
    llvm::tie(notNilState, nilState) = state->assume(receiverVal);

    // Handle receiver must be nil.
    if (nilState && !notNilState) {
      HandleNilReceiver(C, state, msg);
      return;
    }
  }
}

void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
                                               const ObjCMethodCall &msg,
                                               ExplodedNode *N) const {

  if (!BT_msg_ret)
    BT_msg_ret.reset(
        new BuiltinBug(this, "Receiver in message expression is 'nil'"));

  const ObjCMessageExpr *ME = msg.getOriginExpr();

  QualType ResTy = msg.getResultType();

  SmallString<200> buf;
  llvm::raw_svector_ostream os(buf);
  os << "The receiver of message '";
  ME->getSelector().print(os);
  os << "' is nil";
  if (ResTy->isReferenceType()) {
    os << ", which results in forming a null reference";
  } else {
    os << " and returns a value of type '";
    msg.getResultType().print(os, C.getLangOpts());
    os << "' that will be garbage";
  }

  BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
  report->addRange(ME->getReceiverRange());
  // FIXME: This won't track "self" in messages to super.
  if (const Expr *receiver = ME->getInstanceReceiver()) {
    bugreporter::trackNullOrUndefValue(N, receiver, *report);
  }
  C.emitReport(report);
}

static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
  return (triple.getVendor() == llvm::Triple::Apple &&
          (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
}

void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              const ObjCMethodCall &Msg) const {
  ASTContext &Ctx = C.getASTContext();
  static CheckerProgramPointTag Tag(this, "NilReceiver");

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = Msg.getResultType();
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(Msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (CanRetTy.getTypePtr()->isReferenceType()||
        (voidPtrSize < returnTypeSize &&
         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
           (Ctx.FloatTy == CanRetTy ||
            Ctx.DoubleTy == CanRetTy ||
            Ctx.LongDoubleTy == CanRetTy ||
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy)))) {
      if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
        emitNilReceiverBug(C, Msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  C.addTransition(state);
}

void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
  mgr.registerChecker<CallAndMessageChecker>();
}
@


