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