1f4a2713aSLionel Sambuc //=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This files defines PointerSubChecker, a builtin checker that checks for
11f4a2713aSLionel Sambuc // pointer subtractions on two pointers pointing to different memory chunks.
12f4a2713aSLionel Sambuc // This check corresponds to CWE-469.
13f4a2713aSLionel Sambuc //
14f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
15f4a2713aSLionel Sambuc
16f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
17f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21f4a2713aSLionel Sambuc
22f4a2713aSLionel Sambuc using namespace clang;
23f4a2713aSLionel Sambuc using namespace ento;
24f4a2713aSLionel Sambuc
25f4a2713aSLionel Sambuc namespace {
26f4a2713aSLionel Sambuc class PointerSubChecker
27f4a2713aSLionel Sambuc : public Checker< check::PreStmt<BinaryOperator> > {
28*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<BuiltinBug> BT;
29f4a2713aSLionel Sambuc
30f4a2713aSLionel Sambuc public:
31f4a2713aSLionel Sambuc void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
32f4a2713aSLionel Sambuc };
33f4a2713aSLionel Sambuc }
34f4a2713aSLionel Sambuc
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const35f4a2713aSLionel Sambuc void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
36f4a2713aSLionel Sambuc CheckerContext &C) const {
37f4a2713aSLionel Sambuc // When doing pointer subtraction, if the two pointers do not point to the
38f4a2713aSLionel Sambuc // same memory chunk, emit a warning.
39f4a2713aSLionel Sambuc if (B->getOpcode() != BO_Sub)
40f4a2713aSLionel Sambuc return;
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc ProgramStateRef state = C.getState();
43f4a2713aSLionel Sambuc const LocationContext *LCtx = C.getLocationContext();
44f4a2713aSLionel Sambuc SVal LV = state->getSVal(B->getLHS(), LCtx);
45f4a2713aSLionel Sambuc SVal RV = state->getSVal(B->getRHS(), LCtx);
46f4a2713aSLionel Sambuc
47f4a2713aSLionel Sambuc const MemRegion *LR = LV.getAsRegion();
48f4a2713aSLionel Sambuc const MemRegion *RR = RV.getAsRegion();
49f4a2713aSLionel Sambuc
50f4a2713aSLionel Sambuc if (!(LR && RR))
51f4a2713aSLionel Sambuc return;
52f4a2713aSLionel Sambuc
53f4a2713aSLionel Sambuc const MemRegion *BaseLR = LR->getBaseRegion();
54f4a2713aSLionel Sambuc const MemRegion *BaseRR = RR->getBaseRegion();
55f4a2713aSLionel Sambuc
56f4a2713aSLionel Sambuc if (BaseLR == BaseRR)
57f4a2713aSLionel Sambuc return;
58f4a2713aSLionel Sambuc
59f4a2713aSLionel Sambuc // Allow arithmetic on different symbolic regions.
60f4a2713aSLionel Sambuc if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
61f4a2713aSLionel Sambuc return;
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc if (ExplodedNode *N = C.addTransition()) {
64f4a2713aSLionel Sambuc if (!BT)
65*0a6a1f1dSLionel Sambuc BT.reset(
66*0a6a1f1dSLionel Sambuc new BuiltinBug(this, "Pointer subtraction",
67f4a2713aSLionel Sambuc "Subtraction of two pointers that do not point to "
68f4a2713aSLionel Sambuc "the same memory chunk may cause incorrect result."));
69f4a2713aSLionel Sambuc BugReport *R = new BugReport(*BT, BT->getDescription(), N);
70f4a2713aSLionel Sambuc R->addRange(B->getSourceRange());
71f4a2713aSLionel Sambuc C.emitReport(R);
72f4a2713aSLionel Sambuc }
73f4a2713aSLionel Sambuc }
74f4a2713aSLionel Sambuc
registerPointerSubChecker(CheckerManager & mgr)75f4a2713aSLionel Sambuc void ento::registerPointerSubChecker(CheckerManager &mgr) {
76f4a2713aSLionel Sambuc mgr.registerChecker<PointerSubChecker>();
77f4a2713aSLionel Sambuc }
78