Skip to content

Commit

Permalink
Bounds checking for pointer dereferences and array subscripts (checke…
Browse files Browse the repository at this point in the history
…dc#1176)

* Add TargetBounds argument to UpdateAfterAssignment

* Update comments to include pointer dereferences and array subscripts

* Add LValueAbstractSet argument to UpdateBoundsAfterAssignment

* Use the AbstractSet's representative to record equality if LValue belongs to an AbstractSet

* Add EmitDeclaredBoundsNote method

* Remove requirement that A->GetDecl() must exist from validation methods

* Update bounds widening warning comment

* Add ExprUtil::IsDereferenceOrSubscript method

* Visit pointer dereferences and array subscripts in FindLValueHelper

* Visit pointer dereferences and array subscripts in LValueCountHelper

* Transform pointer dereference and array subscripts in ReplaceLValueHelper

* Update increment/decrement tests for pointer dereferences/array subscripts in bounds-context.c

* Add initial test file pointer-dereference-bounds for bounds checking pointer dereferences and array subscripts

* PreorderAST: the canonical form of e1[e2] is *(e1 + e2 + 0), not *(e1 + e2)

* Add tests for updating dereference and array subscript expressions used in return bounds

* Use ExprUtil::IsDereferenceOrSubscript to check for dereference/array subscript expressions in UpdateAfterAssignment

* Add more tests to pointer-dereference-bounds.c

* Synthesize member expressions that depend on lvalues that use a member expression to update memory

* Add tests for synthesizing member expressions that depend on dereferenced member expressions to pointer-dereference-bounds.c

* Add tests for synthesizing member expressions whose bounds depend on dereferenced/subscripted member expressions to synthesized-members.c

* Add test for bounds-safe interface typed dereferences

* Remove else before returns in ReplaceLValueHelper
  • Loading branch information
kkjeer authored Sep 7, 2021
1 parent d6852fe commit ce4831a
Show file tree
Hide file tree
Showing 9 changed files with 670 additions and 119 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ExprUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ class ExprUtil {
// pointer). Returns false if E is nullptr.
static bool ReadsMemoryViaPointer(Expr *E, bool IncludeAllMemberExprs = false);

// IsDereferenceOrSubscript returns true if the expression e is a pointer
// dereference *e1 or an array subscript expression e1[e2].
static bool IsDereferenceOrSubscript(Expr *E);

// IsReturnValueExpr return true if the expression E is a _Return_value
// expression.
static bool IsReturnValueExpr(Expr *E);
Expand Down
44 changes: 44 additions & 0 deletions clang/lib/AST/ExprUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,18 @@ bool ExprUtil::ReadsMemoryViaPointer(Expr *E, bool IncludeAllMemberExprs) {
}
}

bool ExprUtil::IsDereferenceOrSubscript(Expr *E) {
if (!E)
return false;
E = E->IgnoreParens();
if (isa<ArraySubscriptExpr>(E))
return true;
UnaryOperator *UO = dyn_cast<UnaryOperator>(E);
if (!UO)
return false;
return UO->getOpcode() == UnaryOperatorKind::UO_Deref;
}

bool ExprUtil::IsReturnValueExpr(Expr *E) {
BoundsValueExpr *BVE = dyn_cast_or_null<BoundsValueExpr>(E);
if (!BVE)
Expand Down Expand Up @@ -348,6 +360,22 @@ namespace {
return true;
}

bool VisitUnaryOperator(UnaryOperator *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return true;
if (Lex.CompareExprSemantically(E, LValue))
Found = true;
return true;
}

bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return true;
if (Lex.CompareExprSemantically(E, LValue))
Found = true;
return true;
}

// Do not traverse the child of a BoundsValueExpr.
// Expressions within a BoundsValueExpr should not be considered
// when looking for LValue.
Expand Down Expand Up @@ -437,6 +465,22 @@ namespace {
return true;
}

bool VisitUnaryOperator(UnaryOperator *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return true;
if (Lex.CompareExprSemantically(E, LValue))
++Count;
return true;
}

bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return true;
if (Lex.CompareExprSemantically(E, LValue))
++Count;
return true;
}

// Do not traverse the child of a BoundsValueExpr.
// If a BoundsValueExpr uses the expression LValue (or a variable whose
// declaration matches V), this should not count toward the total
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/PreorderAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,14 @@ void PreorderAST::CreateUnaryOperator(UnaryOperator *E, Node *Parent) {
}

void PreorderAST::CreateArraySubscript(ArraySubscriptExpr *E, Node *Parent) {
// e1[e2] has the same canonical form as *(e1 + e2).
// e1[e2] has the same canonical form as *(e1 + e2 + 0).
auto *DerefExpr = BinaryOperator::Create(Ctx, E->getBase(), E->getIdx(),
BinaryOperatorKind::BO_Add, E->getType(),
E->getValueKind(), E->getObjectKind(),
E->getExprLoc(), FPOptionsOverride());
auto *N = new UnaryOperatorNode(UnaryOperatorKind::UO_Deref, Parent);
AttachNode(N, Parent);
Create(DerefExpr, N);
AddZero(DerefExpr, N);
}

void PreorderAST::CreateMember(MemberExpr *E, Node *Parent) {
Expand Down
53 changes: 37 additions & 16 deletions clang/lib/Sema/BoundsUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,9 @@ namespace {
if (Lex.CompareExpr(V, E) == Lexicographic::Result::Equal) {
if (OriginalValue)
return OriginalValue;
else
return ExprError();
} else
return E;
return ExprError();
}
return E;
}

ExprResult TransformMemberExpr(MemberExpr *E) {
Expand All @@ -238,34 +237,56 @@ namespace {
if (Lex.CompareExprSemantically(M, E)) {
if (OriginalValue)
return OriginalValue;
else
return ExprError();
} else
return ExprError();
}
return E;
}

ExprResult TransformUnaryOperator(UnaryOperator *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return E;
if (Lex.CompareExprSemantically(LValue, E)) {
if (OriginalValue)
return OriginalValue;
return ExprError();
}
return E;
}

ExprResult TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
return E;
if (Lex.CompareExprSemantically(LValue, E)) {
if (OriginalValue)
return OriginalValue;
return ExprError();
}
return E;
}

// Overriding TransformImplicitCastExpr is necessary since TreeTransform
// does not preserve implicit casts.
ExprResult TransformImplicitCastExpr(ImplicitCastExpr *E) {
// Replace V with OV (if applicable) in the subexpression of E.
// Replace LValue with OriginalValue (if applicable) in the
// subexpression of E.
ExprResult ChildResult = TransformExpr(E->getSubExpr());
if (ChildResult.isInvalid())
return ChildResult;

Expr *Child = ChildResult.get();
CastKind CK = E->getCastKind();

// Only cast children of lvalue to rvalue or array to pointer casts
// to an rvalue if necessary. The transformed child expression may
// no longer be an lvalue, depending on the original value.
// For example, if x is transformed to the original value x + 1, it
// does not need to be cast to an rvalue.
if (CK == CastKind::CK_LValueToRValue ||
CK == CastKind::CK_ArrayToPointerDecay)
// Only cast children of lvalue to rvalue casts to an rvalue if
// necessary. The transformed child expression may no longer be
// an lvalue, depending on the original value. For example, if x
// is transformed to the original value x + 1, it does not need to
// be cast to an rvalue.
return ExprCreatorUtil::EnsureRValue(SemaRef, Child);
else
return ExprCreatorUtil::CreateImplicitCast(SemaRef, Child,
CK, E->getType());

return ExprCreatorUtil::CreateImplicitCast(SemaRef, Child,
CK, E->getType());
}
};
}
Expand Down
Loading

0 comments on commit ce4831a

Please sign in to comment.