blob: 14edf566898325f4212eddd304a55bd4058be986 [file] [log] [blame]
Zhongxing Xuceeb02d2009-11-06 13:30:44 +00001//== ReturnPointerRangeChecker.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 ReturnPointerRangeChecker, which is a path-sensitive check
11// which looks for an out-of-bound pointer being returned to callers.
12//
13//===----------------------------------------------------------------------===//
14
15#include "GRExprEngineInternalChecks.h"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000016#include "clang/Checker/BugReporter/BugType.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000017#include "clang/Checker/PathSensitive/CheckerVisitor.h"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000018#include "clang/Checker/PathSensitive/GRExprEngine.h"
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000019
20using namespace clang;
21
22namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000023class ReturnPointerRangeChecker :
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000024 public CheckerVisitor<ReturnPointerRangeChecker> {
25 BuiltinBug *BT;
26public:
27 ReturnPointerRangeChecker() : BT(0) {}
28 static void *getTag();
29 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
30};
31}
32
33void clang::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) {
34 Eng.registerCheck(new ReturnPointerRangeChecker());
35}
36
37void *ReturnPointerRangeChecker::getTag() {
38 static int x = 0; return &x;
39}
40
41void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
42 const ReturnStmt *RS) {
43 const GRState *state = C.getState();
44
45 const Expr *RetE = RS->getRetValue();
46 if (!RetE)
47 return;
48
Ted Kremenek13976632010-02-08 16:18:51 +000049 SVal V = state->getSVal(RetE);
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000050 const MemRegion *R = V.getAsRegion();
Zhongxing Xub991f482009-11-11 11:55:54 +000051 if (!R)
52 return;
53
54 R = R->StripCasts();
55 if (!R)
56 return;
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000057
58 const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
59 if (!ER)
Ted Kremenek6f516f52009-11-06 20:16:31 +000060 return;
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000061
62 DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
63
Zhongxing Xub991f482009-11-11 11:55:54 +000064 // FIXME: All of this out-of-bounds checking should eventually be refactored
65 // into a common place.
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000066
Zhongxing Xue884ff82009-11-12 02:48:32 +000067 DefinedOrUnknownSVal NumElements
Zhongxing Xu3ed04d32010-01-18 08:54:31 +000068 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
69 ER->getValueType(C.getASTContext()));
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000070
71 const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
72 const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
73 if (StOutBound && !StInBound) {
Ted Kremenek19d67b52009-11-23 22:22:01 +000074 ExplodedNode *N = C.GenerateSink(StOutBound);
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000075
76 if (!N)
77 return;
78
Zhongxing Xub991f482009-11-11 11:55:54 +000079 // FIXME: This bug correspond to CWE-466. Eventually we should have bug
80 // types explicitly reference such exploit categories (when applicable).
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000081 if (!BT)
Ted Kremenek6f516f52009-11-06 20:16:31 +000082 BT = new BuiltinBug("Return of pointer value outside of expected range",
Zhongxing Xub991f482009-11-11 11:55:54 +000083 "Returned pointer value points outside the original object "
84 "(potential buffer overflow)");
Ted Kremenek6f516f52009-11-06 20:16:31 +000085
Zhongxing Xub991f482009-11-11 11:55:54 +000086 // FIXME: It would be nice to eventually make this diagnostic more clear,
87 // e.g., by referencing the original declaration or by saying *why* this
88 // reference is outside the range.
Ted Kremenek6f516f52009-11-06 20:16:31 +000089
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000090 // Generate a report for this bug.
91 RangedBugReport *report =
Benjamin Kramerd02e2322009-11-14 12:08:24 +000092 new RangedBugReport(*BT, BT->getDescription(), N);
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000093
Ted Kremenek6f516f52009-11-06 20:16:31 +000094 report->addRange(RetE->getSourceRange());
Zhongxing Xuceeb02d2009-11-06 13:30:44 +000095 C.EmitReport(report);
96 }
97}