PointerSubChecker.cpp revision 276479
1191665Sbms//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
2191665Sbms//
3191665Sbms//                     The LLVM Compiler Infrastructure
4191665Sbms//
5191665Sbms// This file is distributed under the University of Illinois Open Source
6191665Sbms// License. See LICENSE.TXT for details.
7191665Sbms//
8191665Sbms//===----------------------------------------------------------------------===//
9191665Sbms//
10191665Sbms// This files defines PointerSubChecker, a builtin checker that checks for
11191665Sbms// pointer subtractions on two pointers pointing to different memory chunks.
12191665Sbms// This check corresponds to CWE-469.
13191665Sbms//
14191665Sbms//===----------------------------------------------------------------------===//
15191665Sbms
16191665Sbms#include "ClangSACheckers.h"
17191665Sbms#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18191665Sbms#include "clang/StaticAnalyzer/Core/Checker.h"
19191665Sbms#include "clang/StaticAnalyzer/Core/CheckerManager.h"
20191665Sbms#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21191665Sbms
22191665Sbmsusing namespace clang;
23191665Sbmsusing namespace ento;
24191665Sbms
25191665Sbmsnamespace {
26191665Sbmsclass PointerSubChecker
27191665Sbms  : public Checker< check::PreStmt<BinaryOperator> > {
28191665Sbms  mutable std::unique_ptr<BuiltinBug> BT;
29191665Sbms
30191665Sbmspublic:
31191665Sbms  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
32191672Sbms};
33191665Sbms}
34191665Sbms
35191665Sbmsvoid PointerSubChecker::checkPreStmt(const BinaryOperator *B,
36191665Sbms                                     CheckerContext &C) const {
37191665Sbms  // When doing pointer subtraction, if the two pointers do not point to the
38191665Sbms  // same memory chunk, emit a warning.
39191665Sbms  if (B->getOpcode() != BO_Sub)
40191665Sbms    return;
41191665Sbms
42191665Sbms  ProgramStateRef state = C.getState();
43191665Sbms  const LocationContext *LCtx = C.getLocationContext();
44191665Sbms  SVal LV = state->getSVal(B->getLHS(), LCtx);
45191665Sbms  SVal RV = state->getSVal(B->getRHS(), LCtx);
46191665Sbms
47191665Sbms  const MemRegion *LR = LV.getAsRegion();
48191665Sbms  const MemRegion *RR = RV.getAsRegion();
49191665Sbms
50191665Sbms  if (!(LR && RR))
51191665Sbms    return;
52191665Sbms
53191665Sbms  const MemRegion *BaseLR = LR->getBaseRegion();
54191665Sbms  const MemRegion *BaseRR = RR->getBaseRegion();
55191665Sbms
56191665Sbms  if (BaseLR == BaseRR)
57191665Sbms    return;
58191665Sbms
59191665Sbms  // Allow arithmetic on different symbolic regions.
60191665Sbms  if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
61191665Sbms    return;
62191665Sbms
63191665Sbms  if (ExplodedNode *N = C.addTransition()) {
64191665Sbms    if (!BT)
65191665Sbms      BT.reset(
66191665Sbms          new BuiltinBug(this, "Pointer subtraction",
67191665Sbms                         "Subtraction of two pointers that do not point to "
68191665Sbms                         "the same memory chunk may cause incorrect result."));
69195699Srwatson    BugReport *R = new BugReport(*BT, BT->getDescription(), N);
70191665Sbms    R->addRange(B->getSourceRange());
71191665Sbms    C.emitReport(R);
72191665Sbms  }
73191665Sbms}
74191665Sbms
75191665Sbmsvoid ento::registerPointerSubChecker(CheckerManager &mgr) {
76191665Sbms  mgr.registerChecker<PointerSubChecker>();
77191665Sbms}
78191665Sbms