1//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines AdjustedReturnValueChecker, a simple check to see if the
11// return value of a function call is different than the one the caller thinks
12// it is.
13//
14//===----------------------------------------------------------------------===//
15
16#include "ClangSACheckers.h"
17#include "clang/StaticAnalyzer/Core/Checker.h"
18#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21
22using namespace clang;
23using namespace ento;
24
25namespace {
26class AdjustedReturnValueChecker :
27    public Checker< check::PostStmt<CallExpr> > {
28public:
29  void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
30};
31}
32
33void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
34                                               CheckerContext &C) const {
35
36  // Get the result type of the call.
37  QualType expectedResultTy = CE->getType();
38
39  // Fetch the signature of the called function.
40  const ProgramState *state = C.getState();
41
42  SVal V = state->getSVal(CE);
43
44  if (V.isUnknown())
45    return;
46
47  // Casting to void?  Discard the value.
48  if (expectedResultTy->isVoidType()) {
49    C.generateNode(state->BindExpr(CE, UnknownVal()));
50    return;
51  }
52
53  const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
54  if (!callee)
55    return;
56
57  QualType actualResultTy;
58
59  if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
60    const FunctionDecl *FD = FT->getDecl();
61    actualResultTy = FD->getResultType();
62  }
63  else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
64    const BlockTextRegion *BR = BD->getCodeRegion();
65    const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
66    const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
67    actualResultTy = FT->getResultType();
68  }
69
70  // Can this happen?
71  if (actualResultTy.isNull())
72    return;
73
74  // For now, ignore references.
75  if (actualResultTy->getAs<ReferenceType>())
76    return;
77
78
79  // Are they the same?
80  if (expectedResultTy != actualResultTy) {
81    // FIXME: Do more checking and actual emit an error. At least performing
82    // the cast avoids some assertion failures elsewhere.
83    SValBuilder &svalBuilder = C.getSValBuilder();
84    V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
85    C.generateNode(state->BindExpr(CE, V));
86  }
87}
88
89void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
90  mgr.registerChecker<AdjustedReturnValueChecker>();
91}
92