This checks for the implicit casting of an array of a derived type to a base pointer. This is problematic because if the base pointer is incremented or indexed, a size difference between the base and derived classes could result in a bad pointer calculation. I could check for the sizes of the two classes to see if they happen to be the same, but it's really just a bad practice, since the size could change on a later revision.

  - jim


// RUN: %clang_cc1 -analyze 
-analyzer-checker=core,cplusplus.experimental.PolymorphicPointers -verify %s

class base {
public:
        virtual void func(void) {
        }
};

class derived : public base {
public:
        int i;
        derived() { i = 0; }

        void func(void) {
        }
};

class derived2 : public derived {
public:
  int j;
  derived2() { j = 0; }
};

void foo1(void) {
        derived d[3];

  // check for implicit cast to base pointer
  base *bp = d;  // expected-warning{{Using a base pointer to an array of a 
derived type is unsafe because of possible size differences.}}
}

void fum(base *);

void foo2(void) {
  base b[3];
  derived d[3];

  // verify that don't give error on base class
  fum(b);  // no-warning
  // check for implicit cast as base pointer argument
        fum(d);  // expected-warning{{Using a base pointer to an array of a 
derived type is unsafe because of possible size differences.}}
}

void foo3(void) {
  derived2 d2[3];

  // derived to previous
  derived *dp = d2;  // expected-warning{{Using a base pointer to an array of a 
derived type is unsafe because of possible size differences.}}
}

void foo4(void) {
  derived2 d2[3];

  // derived to true base
  base *bp = d2;  // expected-warning{{Using a base pointer to an array of a 
derived type is unsafe because of possible size differences.}}
}


Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td     (revision 131677)
+++ lib/StaticAnalyzer/Checkers/Checkers.td     (working copy)
@@ -176,6 +176,10 @@
   HelpText<"Check improper uses of STL vector iterators">,
   DescFile<"IteratorsChecker.cpp">;
 
+def PolymorphicPointerChecker : Checker<"PolymorphicPointers">,
+  HelpText<"Check for use of base pointer to array of derived types">,
+  DescFile<"PolymorphicPointerChecker.cpp">;
+
 } // end: "cplusplus.experimental"
 
 
//===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt  (revision 131677)
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt  (working copy)
@@ -42,6 +42,7 @@
   ObjCUnusedIVarsChecker.cpp
   PointerArithChecker.cpp
   PointerSubChecker.cpp
+  PolymorphicPointerChecker.cpp
   PthreadLockChecker.cpp
   ReturnPointerRangeChecker.cpp
   ReturnUndefChecker.cpp

//=== PolymorphicPointerChecker.cpp -----------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// PolymorphicPointerChecker issues a warning when an array of derived types
// is implicitly cast to the base type. This is bad because the size of the
// derived type may not be the same size as the base type.
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/CharUnits.h"

using namespace clang;
using namespace ento;

namespace {
class PolymorphicPointerChecker : public Checker< check::PreStmt<CastExpr> > {
  mutable llvm::OwningPtr<BuiltinBug> BT;
public:
  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}

void PolymorphicPointerChecker::checkPreStmt(const CastExpr *CE,
          CheckerContext &C) const {
  const ImplicitCastExpr *ICE, *ICE2;
  if ((ICE = dyn_cast<ImplicitCastExpr>(CE)) == NULL)
    return;
  if (ICE->getCastKind() != CK_DerivedToBase)
    return;
  if ((ICE2 = dyn_cast<ImplicitCastExpr>(ICE->getSubExpr())) == NULL)
    return;
  if (ICE2->getCastKind() != CK_ArrayToPointerDecay)
    return;
  if (ExplodedNode *errorNode = C.generateSink()) {
    if (!BT)
      BT.reset(new BuiltinBug("Polymorphic Pointer",
                  "Using a base pointer to an array of a derived type is "
                  "unsafe because of possible size differences."));
    RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
                                             errorNode);
    R->addRange(CE->getSourceRange());
    C.EmitReport(R);
  }
}

void ento::registerPolymorphicPointerChecker(CheckerManager &mgr) {
  mgr.registerChecker<PolymorphicPointerChecker>();  
}

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to