blob: 51ad1e2daf5e1a22b1714700ff7637e4a6148d86 [file] [log] [blame]
Shih-wei Liaof8fd82b2010-02-10 11:10:31 -08001//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This defines VLASizeChecker, a builtin check in GRExprEngine that
11// performs checks for declaration of VLA of undefined or zero size.
12//
13//===----------------------------------------------------------------------===//
14
15#include "GRExprEngineInternalChecks.h"
16#include "clang/Checker/PathSensitive/CheckerVisitor.h"
17#include "clang/Checker/PathSensitive/GRExprEngine.h"
18#include "clang/Checker/BugReporter/BugReporter.h"
19
20using namespace clang;
21
22namespace {
23class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
24 BugType *BT_zero;
25 BugType *BT_undef;
26
27public:
28 VLASizeChecker() : BT_zero(0), BT_undef(0) {}
29 static void *getTag() { static int tag = 0; return &tag; }
30 void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
31};
32} // end anonymous namespace
33
34void clang::RegisterVLASizeChecker(GRExprEngine &Eng) {
35 Eng.registerCheck(new VLASizeChecker());
36}
37
38void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
39 if (!DS->isSingleDecl())
40 return;
41
42 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
43 if (!VD)
44 return;
45
46 const VariableArrayType *VLA
47 = C.getASTContext().getAsVariableArrayType(VD->getType());
48 if (!VLA)
49 return;
50
51 // FIXME: Handle multi-dimensional VLAs.
52 const Expr* SE = VLA->getSizeExpr();
53 const GRState *state = C.getState();
54 SVal sizeV = state->getSVal(SE);
55
56 if (sizeV.isUndef()) {
57 // Generate an error node.
58 ExplodedNode *N = C.GenerateSink();
59 if (!N)
60 return;
61
62 if (!BT_undef)
63 BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
64 "garbage value as its size");
65
66 EnhancedBugReport *report =
67 new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
68 report->addRange(SE->getSourceRange());
69 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
70 C.EmitReport(report);
71 return;
72 }
73
74 // Check if the size is zero.
75 DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
76
77 const GRState *stateNotZero, *stateZero;
78 llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
79
80 if (stateZero && !stateNotZero) {
81 ExplodedNode* N = C.GenerateSink(stateZero);
82 if (!BT_zero)
83 BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
84 "size");
85
86 EnhancedBugReport *report =
87 new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
88 report->addRange(SE->getSourceRange());
89 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
90 C.EmitReport(report);
91 return;
92 }
93
94 // From this point on, assume that the size is not zero.
95 C.addTransition(stateNotZero);
96}