Skip to content

Commit fe0695d

Browse files
Merge branch 'master' of github.com:microsoft/checkedc-clang
2 parents f184449 + f0162f3 commit fe0695d

13 files changed

+419
-280
lines changed

clang/include/clang/AST/CanonBounds.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ namespace clang {
123123
/// expressions are equivalent semantically.
124124
bool CompareExprSemantically(const Expr *E1, const Expr *E2);
125125

126+
/// \brief Given the upper bound expr and the dereference expr for an
127+
/// _Nt_array_ptr gets the offset by which the pointer is dereferenced.
128+
/// The boolean return value indicates whether a valid offset exists.
129+
bool GetDerefOffset(const Expr *UpperExpr, const Expr *DerefExpr,
130+
llvm::APSInt &Offset);
131+
126132
/// \brief Compare declarations that may be used by expressions or
127133
/// or types.
128134
Result CompareDecl(const NamedDecl *D1, const NamedDecl *D2) const;

clang/include/clang/AST/PreorderAST.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,17 @@ namespace clang {
118118
// this to control when to stop recursive constant folding.
119119
void ConstantFold(Node *N, bool &Changed);
120120

121-
// Normalize expressions which do not have any integer constants.
122-
// @param[in] N is current node of the AST. Initial value is Root.
123-
void NormalizeExprsWithoutConst(Node *N);
121+
// Get the deref offset from the DerefExpr. The offset represents the
122+
// possible amount by which the bounds of an ntptr could be widened.
123+
// @param[in] UpperExpr is the upper bounds expr for the ntptr.
124+
// @param[in] DerefExpr is the dereferenced expr for the ntptr.
125+
// @param[out] Offset is the offset from the base by which the pointer is
126+
// dereferenced.
127+
// return Returns a boolean indicating whether a valid offset exists. True
128+
// means a valid offset was found and is present in the "Offset" parameter.
129+
// False means a valid offset was not found.
130+
bool GetDerefOffset(Node *UpperExpr, Node *DerefExpr,
131+
llvm::APSInt &Offset);
124132

125133
// Check if the two AST nodes N1 and N2 are equal.
126134
// @param[in] N1 is the first node.
@@ -151,6 +159,17 @@ namespace clang {
151159
// transformation of the AST.
152160
void Normalize();
153161

162+
// Get the offset by which a pointer is dereferenced. This function is
163+
// intended to be called from outside this class.
164+
// @param[in] this is the first AST.
165+
// @param[in] P is the second AST.
166+
// @param[out] Offset is the dereference offset.
167+
// @return Returns a bool indicating whether a valid dereference offset
168+
// exists.
169+
bool GetDerefOffset(PreorderAST &P, llvm::APSInt &Offset) {
170+
return GetDerefOffset(/*UpperExpr*/ Root, /*DerefExpr*/ P.Root, Offset);
171+
}
172+
154173
// Check if the two ASTs are equal. This is intended to be called from
155174
// outside this class and invokes IsEqual on the root nodes of the two ASTs
156175
// to recursively compare the AST nodes.

clang/include/clang/Sema/BoundsAnalysis.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,10 @@ namespace clang {
244244
void FillGenSet(Expr *E, ElevatedCFGBlock *EB, ElevatedCFGBlock *SuccEB);
245245

246246
// Uniformize the expr, fill Gen set for the edge EB->SuccEB.
247-
// @param[in] E is an ntptr dereference or array subscript expr.
247+
// @param[in] DerefExpr is an ntptr dereference or array subscript expr.
248248
// @param[in] Source block for the edge for which the Gen set is updated.
249249
// @param[in] Dest block for the edge for which the Gen set is updated.
250-
void FillGenSetForEdge(const Expr *E,
250+
void FillGenSetForEdge(const Expr *DerefExpr,
251251
ElevatedCFGBlock *EB,
252252
ElevatedCFGBlock *SuccEB);
253253

@@ -301,14 +301,6 @@ namespace clang {
301301
// @return The DeclRefExpr from the expression E or nullptr.
302302
DeclRefExpr *GetDeclOperand(const Expr *E);
303303

304-
// Make an expression uniform by moving all DeclRefExpr to the LHS and all
305-
// IntegerLiterals to the RHS.
306-
// @param[in] E is the expression which should be made uniform.
307-
// @return A pair of an expression and an integer constant. The expression
308-
// contains all DeclRefExprs of E and the integer constant contains all
309-
// IntegerLiterals of E.
310-
ExprIntPairTy SplitIntoBaseOffset(const Expr *E);
311-
312304
// Collect all ntptrs in scope. Currently, this simply collects all ntptrs
313305
// defined in all blocks in the current function. This function inserts the
314306
// VarDecls for the ntptrs in NtPtrsInScope.

clang/lib/AST/CanonBounds.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,32 @@ bool Lexicographic::CompareExprSemantically(const Expr *Arg1,
248248
return Res;
249249
}
250250

251+
bool Lexicographic::GetDerefOffset(const Expr *UpperExpr,
252+
const Expr *DerefExpr,
253+
llvm::APSInt &Offset) {
254+
Expr *E1 = const_cast<Expr *>(UpperExpr);
255+
Expr *E2 = const_cast<Expr *>(DerefExpr);
256+
257+
PreorderAST P1(Context, E1);
258+
P1.Normalize();
259+
if (P1.GetError()) {
260+
P1.Cleanup();
261+
return false;
262+
}
263+
264+
PreorderAST P2(Context, E2);
265+
P2.Normalize();
266+
if (P2.GetError()) {
267+
P2.Cleanup();
268+
return false;
269+
}
270+
271+
bool Res = P1.GetDerefOffset(P2, Offset);
272+
P1.Cleanup();
273+
P2.Cleanup();
274+
return Res;
275+
}
276+
251277
Result Lexicographic::CompareExpr(const Expr *Arg1, const Expr *Arg2) {
252278
if (Trace) {
253279
raw_ostream &OS = llvm::outs();

clang/lib/AST/PreorderAST.cpp

Lines changed: 87 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,25 @@ void PreorderAST::Create(Expr *E, Node *Parent) {
8282

8383
E = Lex.IgnoreValuePreservingOperations(Ctx, E->IgnoreParens());
8484

85-
if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
85+
if (!Parent) {
86+
// The invariant is that the root node must be a BinaryNode with an
87+
// addition operator. So for expressions like "if (*p)", we don't have a
88+
// BinaryOperator. So when we enter this function there is no root and the
89+
// parent is null. So we create a new BinaryNode with + as the operator and
90+
// add 0 as a LeafNodeExpr child of this BinaryNode. This helps us compare
91+
// expressions like "p" and "p + 1" by normalizing "p" to "p + 0".
92+
93+
auto *N = new BinaryNode(BO_Add, Parent);
94+
AddNode(N, Parent);
95+
96+
llvm::APInt Zero(Ctx.getTargetInfo().getIntWidth(), 0);
97+
auto *ZeroLiteral = new (Ctx) IntegerLiteral(Ctx, Zero, Ctx.IntTy,
98+
SourceLocation());
99+
auto *L = new LeafExprNode(ZeroLiteral, N);
100+
AddNode(L, /*Parent*/ N);
101+
Create(E, /*Parent*/ N);
102+
103+
} else if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
86104
BinaryOperator::Opcode BinOp = BO->getOpcode();
87105
Expr *LHS = BO->getLHS();
88106
Expr *RHS = BO->getRHS();
@@ -130,19 +148,6 @@ void PreorderAST::Create(Expr *E, Node *Parent) {
130148
Create(LHS, /*Parent*/ N);
131149
Create(RHS, /*Parent*/ N);
132150

133-
} else if (!Parent) {
134-
// The invariant is that the root node must be a BinaryNode. So for
135-
// expressions like "if (*p)", we don't have a BinaryOperator. So when we
136-
// enter this function there is no root and the parent is null. So we
137-
// create a new BinaryNode with + as the operator and add "p" as a
138-
// LeafNodeExpr child of this BinaryNode. Later, in the function
139-
// NormalizeExprsWithoutConst we normalize "p" to "p + 0" by adding 0 as a
140-
// sibling of "p".
141-
142-
auto *N = new BinaryNode(BO_Add, Parent);
143-
AddNode(N, Parent);
144-
Create(E, /*Parent*/ N);
145-
146151
} else {
147152
auto *N = new LeafExprNode(E, Parent);
148153
AddNode(N, Parent);
@@ -331,50 +336,80 @@ void PreorderAST::ConstantFold(Node *N, bool &Changed) {
331336
Changed = true;
332337
}
333338

334-
void PreorderAST::NormalizeExprsWithoutConst(Node *N) {
335-
// Consider the following case:
336-
// Upper bound expr: p
337-
// Deref expr: p + 1
338-
// In this case, we would not able able to extract the offset from the deref
339-
// expression because the upper bound expression does not contain a constant.
340-
// This is because the node-by-node comparison of the two expressions would
341-
// fail. So we require that expressions be of the form "(variable + constant)".
342-
// So, we normalize expressions by adding an integer constant to expressions
343-
// which do not have one. For example:
344-
// p ==> (p + 0)
345-
// (p + i) ==> (p + i + 0)
346-
// (p * i) ==> (p * i * 1)
339+
bool PreorderAST::GetDerefOffset(Node *UpperNode, Node *DerefNode,
340+
llvm::APSInt &Offset) {
341+
// Extract the offset by which a pointer is dereferenced. For the pointer we
342+
// compare the dereference expr with the declared upper bound expr. If the
343+
// non-integer parts of the two exprs are not equal we say that a valid
344+
// offset does not exist and return false. If the non-integer parts of the
345+
// two exprs are equal the offset is calculated as:
346+
// (integer part of deref expr - integer part of upper bound expr).
347+
348+
// Since we have already normalized exprs like "*p" to "*(p + 0)" we require
349+
// that the root of the preorder AST is a BinaryNode.
350+
auto *B1 = dyn_cast_or_null<BinaryNode>(UpperNode);
351+
auto *B2 = dyn_cast_or_null<BinaryNode>(DerefNode);
352+
353+
if (!B1 || !B2)
354+
return false;
347355

348-
auto *B = dyn_cast_or_null<BinaryNode>(N);
349-
if (!B)
350-
return;
356+
// If the opcodes mismatch we cannot have a valid offset.
357+
if (B1->Opc != B2->Opc)
358+
return false;
351359

352-
for (auto *Child : B->Children) {
353-
// Recursively normalize constants in the children of a BinaryNode.
354-
if (isa<BinaryNode>(Child))
355-
NormalizeExprsWithoutConst(Child);
360+
// We have already constant folded the constants. So return false if the
361+
// number of children mismatch.
362+
if (B1->Children.size() != B2->Children.size())
363+
return false;
356364

357-
else if (auto *ChildLeafNode = dyn_cast<LeafExprNode>(Child)) {
358-
if (ChildLeafNode->E->isIntegerConstantExpr(Ctx))
359-
return;
360-
}
361-
}
365+
// Check if the children are equivalent.
366+
for (size_t I = 0; I != B1->Children.size(); ++I) {
367+
auto *Child1 = B1->Children[I];
368+
auto *Child2 = B2->Children[I];
362369

363-
llvm::APInt IntConst;
364-
switch(B->Opc) {
365-
default: return;
366-
case BO_Add:
367-
IntConst = llvm::APInt(Ctx.getTargetInfo().getIntWidth(), 0);
368-
break;
369-
case BO_Mul:
370-
IntConst = llvm::APInt(Ctx.getTargetInfo().getIntWidth(), 1);
371-
break;
370+
if (IsEqual(Child1, Child2))
371+
continue;
372+
373+
// If the children are not equal we require that they be integer constant
374+
// leaf nodes. Otherwise we cannot have a valid offset.
375+
auto *L1 = dyn_cast_or_null<LeafExprNode>(Child1);
376+
auto *L2 = dyn_cast_or_null<LeafExprNode>(Child2);
377+
378+
if (!L1 || !L2)
379+
return false;
380+
381+
// Return false if either of the leaf nodes is not an integer constant.
382+
llvm::APSInt UpperOffset;
383+
if (!L1->E->isIntegerConstantExpr(UpperOffset, Ctx))
384+
return false;
385+
386+
llvm::APSInt DerefOffset;
387+
if (!L2->E->isIntegerConstantExpr(DerefOffset, Ctx))
388+
return false;
389+
390+
// Offset should always be of the form (ptr + offset). So we check for
391+
// addition.
392+
// Note: We have already converted (ptr - offset) to (ptr + -offset). So
393+
// its okay to only check for addition.
394+
if (B1->Opc != BO_Add)
395+
return false;
396+
397+
// This guards us from a case where the constants were not folded for
398+
// some reason. In theory this should never happen. But we are adding this
399+
// check just in case.
400+
llvm::APSInt Zero(Ctx.getTargetInfo().getIntWidth(), 0);
401+
if (llvm::APSInt::compareValues(Offset, Zero) != 0)
402+
return false;
403+
404+
// offset = deref offset - declared upper bound offset.
405+
// Return false if we encounter an overflow.
406+
bool Overflow;
407+
Offset = DerefOffset.ssub_ov(UpperOffset, Overflow);
408+
if (Overflow)
409+
return false;
372410
}
373411

374-
auto *IntLiteral = new (Ctx) IntegerLiteral(Ctx, IntConst, Ctx.IntTy,
375-
SourceLocation());
376-
auto *L = new LeafExprNode(IntLiteral, B);
377-
AddNode(L, B);
412+
return true;
378413
}
379414

380415
bool PreorderAST::IsEqual(Node *N1, Node *N2) {
@@ -438,7 +473,6 @@ void PreorderAST::Normalize() {
438473
ConstantFold(Root, Changed);
439474
if (Error)
440475
break;
441-
NormalizeExprsWithoutConst(Root);
442476
}
443477

444478
if (Ctx.getLangOpts().DumpPreorderAST) {

0 commit comments

Comments
 (0)