PointerSubChecker.cpp revision ec8605f1d7ec846dbf51047bfd5c56d32d1ff91c
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//                     The LLVM Compiler Infrastructure
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// License. See LICENSE.TXT for details.
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//===----------------------------------------------------------------------===//
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// This files defines PointerSubChecker, a builtin checker that checks for
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// pointer subtractions on two pointers pointing to different memory chunks.
126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// This check corresponds to CWE-469.
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//===----------------------------------------------------------------------===//
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ClangSACheckers.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/Checker.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using namespace clang;
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using namespace ento;
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class PointerSubChecker
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  : public Checker< check::PreStmt<BinaryOperator> > {
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  mutable llvm::OwningPtr<BuiltinBug> BT;
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)public:
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)};
336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     CheckerContext &C) const {
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // When doing pointer subtraction, if the two pointers do not point to the
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // same memory chunk, emit a warning.
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (B->getOpcode() != BO_Sub)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const GRState *state = C.getState();
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SVal LV = state->getSVal(B->getLHS());
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SVal RV = state->getSVal(B->getRHS());
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const MemRegion *LR = LV.getAsRegion();
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const MemRegion *RR = RV.getAsRegion();
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!(LR && RR))
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const MemRegion *BaseLR = LR->getBaseRegion();
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const MemRegion *BaseRR = RR->getBaseRegion();
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (BaseLR == BaseRR)
566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Allow arithmetic on different symbolic regions.
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ExplodedNode *N = C.generateNode()) {
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!BT)
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      BT.reset(new BuiltinBug("Pointer subtraction",
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          "Subtraction of two pointers that do not point to "
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          "the same memory chunk may cause incorrect result."));
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    R->addRange(B->getSourceRange());
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    C.EmitReport(R);
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ento::registerPointerSubChecker(CheckerManager &mgr) {
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  mgr.registerChecker<PointerSubChecker>();
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)