]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Checker/ReturnPointerRangeChecker.cpp
Update clang to r100181.
[FreeBSD/FreeBSD.git] / lib / Checker / ReturnPointerRangeChecker.cpp
1 //== 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"
16 #include "clang/Checker/BugReporter/BugType.h"
17 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
18 #include "clang/Checker/PathSensitive/GRExprEngine.h"
19
20 using namespace clang;
21
22 namespace {
23 class ReturnPointerRangeChecker : 
24     public CheckerVisitor<ReturnPointerRangeChecker> {      
25   BuiltinBug *BT;
26 public:
27     ReturnPointerRangeChecker() : BT(0) {}
28     static void *getTag();
29     void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
30 };
31 }
32
33 void clang::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) {
34   Eng.registerCheck(new ReturnPointerRangeChecker());
35 }
36
37 void *ReturnPointerRangeChecker::getTag() {
38   static int x = 0; return &x;
39 }
40
41 void 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  
49   SVal V = state->getSVal(RetE);
50   const MemRegion *R = V.getAsRegion();
51   if (!R)
52     return;
53
54   R = R->StripCasts();
55   if (!R)
56     return;
57
58   const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
59   if (!ER)
60     return;
61
62   DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
63
64   // FIXME: All of this out-of-bounds checking should eventually be refactored
65   // into a common place.
66
67   DefinedOrUnknownSVal NumElements
68     = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
69                                            ER->getValueType(C.getASTContext()));
70
71   const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
72   const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
73   if (StOutBound && !StInBound) {
74     ExplodedNode *N = C.GenerateSink(StOutBound);
75
76     if (!N)
77       return;
78   
79     // FIXME: This bug correspond to CWE-466.  Eventually we should have bug
80     // types explicitly reference such exploit categories (when applicable).
81     if (!BT)
82       BT = new BuiltinBug("Return of pointer value outside of expected range",
83            "Returned pointer value points outside the original object "
84            "(potential buffer overflow)");
85
86     // 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.
89
90     // Generate a report for this bug.
91     RangedBugReport *report = 
92       new RangedBugReport(*BT, BT->getDescription(), N);
93
94     report->addRange(RetE->getSourceRange());
95     C.EmitReport(report);
96   }
97 }