Skip to content

Commit 9636f01

Browse files
Use same logic to check for pointer arithmetic in an assignment in array bounds inference and rewriter.
1 parent ad405bb commit 9636f01

File tree

4 files changed

+118
-99
lines changed

4 files changed

+118
-99
lines changed

clang/include/clang/3C/Utils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,9 @@ inline const clang::DiagnosticBuilder &operator<<(
257257
return DB;
258258
}
259259

260+
// Return true if an assignment LHS=RHS would result in invalidating the bounds
261+
// of LHS by assigning to a pointer a value derived from the pointer, for
262+
// example, by using pointer arithmetic to compute a new pointer at some offset
263+
// from the original.
264+
bool isAssignmentPointerArithmetic(clang::Expr *LHS, clang::Expr *RHS);
260265
#endif

clang/lib/3C/AVarBoundsInfo.cpp

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -992,87 +992,10 @@ bool AVarBoundsInfo::addAssignment(BoundsKey L, BoundsKey R) {
992992
return true;
993993
}
994994

995-
// Visitor to collect all the variables and structure member access that are
996-
// used during the life-time of the visitor.
997-
class CollectDeclsVisitor : public RecursiveASTVisitor<CollectDeclsVisitor> {
998-
public:
999-
explicit CollectDeclsVisitor() : ObservedDecls(), ObservedStructAccesses() {}
1000-
1001-
virtual ~CollectDeclsVisitor() {}
1002-
1003-
bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1004-
if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl()))
1005-
ObservedDecls.insert(VD);
1006-
return true;
1007-
}
1008-
1009-
// For a->b; We need to get `a->b` rather than just `b`. This way assignment
1010-
// from a field in one instance of a structure to the same field in another
1011-
// instance is not treated as pointer arithmetic.
1012-
bool VisitMemberExpr(MemberExpr *ME) {
1013-
// TODO: Is this cast legit? `getMemberDecl()` returns a `ValueDecl*`, but I
1014-
// think it can only be a `FieldDecl` for structs in C.
1015-
auto *FD = cast<FieldDecl>(ME->getMemberDecl());
1016-
1017-
// TODO: Is recursively using a new visitor the right thing to do? It feels
1018-
// odd.
1019-
CollectDeclsVisitor MEVis;
1020-
MEVis.TraverseStmt(ME->getBase());
1021-
// Field access through variable.
1022-
for (auto *D : MEVis.getObservedDecls()) {
1023-
std::vector<FieldDecl *> SingletonAccessList({FD});
1024-
ObservedStructAccesses.insert(std::make_pair(D, SingletonAccessList));
1025-
}
1026-
// Field access through other structure fields.
1027-
for (StructAccess SA : MEVis.getObservedStructAccesses()) {
1028-
SA.second.push_back(FD);
1029-
ObservedStructAccesses.insert(SA);
1030-
}
1031-
return false;
1032-
}
1033-
1034-
bool VisitCallExpr(CallExpr *CE) {
1035-
// Stop the visitor when we hit a CallExpr. This stops us from treating a
1036-
// function call like `a = foo(a);` the same as `a = a + 1`.
1037-
return false;
1038-
}
1039-
1040-
const std::set<VarDecl *> &getObservedDecls() { return ObservedDecls; }
1041-
1042-
typedef std::pair<VarDecl *, std::vector<FieldDecl *>> StructAccess;
1043-
const std::set<StructAccess> &getObservedStructAccesses() {
1044-
return ObservedStructAccesses;
1045-
}
1046-
1047-
private:
1048-
// Contains all VarDecls seen by this visitor
1049-
std::set<VarDecl *> ObservedDecls;
1050-
1051-
// Contains the source representation of all record access (MemberExpression)
1052-
// seen by this visitor.
1053-
std::set<StructAccess> ObservedStructAccesses;
1054-
};
1055-
1056995
bool AVarBoundsInfo::handlePointerAssignment(clang::Expr *L, clang::Expr *R,
1057996
ASTContext *C,
1058997
ConstraintResolver *CR) {
1059-
CollectDeclsVisitor LVarVis;
1060-
LVarVis.TraverseStmt(L->getExprStmt());
1061-
1062-
CollectDeclsVisitor RVarVis;
1063-
RVarVis.TraverseStmt(R->getExprStmt());
1064-
1065-
std::set<VarDecl *> CommonVars;
1066-
std::set<CollectDeclsVisitor::StructAccess> CommonStVars;
1067-
findIntersection(LVarVis.getObservedDecls(), RVarVis.getObservedDecls(),
1068-
CommonVars);
1069-
findIntersection(LVarVis.getObservedStructAccesses(),
1070-
RVarVis.getObservedStructAccesses(), CommonStVars);
1071-
1072-
// If CommonVars is not empty, then the same pointer appears on the LHS and
1073-
// RHS of an assignment. We say that the pointer is assigned from a pointer
1074-
// arithmetic expression.
1075-
if (!CommonVars.empty() || !CommonStVars.empty())
998+
if (isAssignmentPointerArithmetic(L ,R))
1076999
recordArithmeticOperation(L, CR);
10771000
return true;
10781001
}

clang/lib/3C/RewriteUtils.cpp

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -431,35 +431,32 @@ class TypeArgumentAdder : public clang::RecursiveASTVisitor<TypeArgumentAdder> {
431431
class AssignmentUpdater : public RecursiveASTVisitor<AssignmentUpdater> {
432432
public:
433433
explicit AssignmentUpdater(ASTContext *C, ProgramInfo &I, Rewriter &R)
434-
: Context(C), Info(I), CR(I, C), R(R) {}
434+
: Info(I), CR(I, C), R(R) {}
435435

436436
bool VisitBinaryOperator(BinaryOperator *O) {
437-
// TODO: Use CollectDeclsVisitor
438437
if (O->getOpcode() == clang::BO_Assign) {
439-
CollectDeclsVisitor LHSVis;
440-
CVarSet LHSCVs = CR.getExprConstraintVarsSet(O->getLHS());
441-
// FIXME: This isn't always a singleton: `int **a, **b; *(0 ? a : b) = 0;`
442-
// As long as inner pointers can't have bounds, we should be able
443-
// to differ a proper solution.
444-
ConstraintVariable *CV = getOnly(LHSCVs);
445-
CVarSet RHSCVs = CR.getExprConstraintVarsSet(O->getRHS());
446-
bool VarOnRHS = RHSCVs.find(CV) != RHSCVs.end();
447-
if (!VarOnRHS &&
448-
CV->hasBoundsKey() &&
449-
Info.getABoundsInfo().needsRangeBound(CV->getBoundsKey())) {
450-
// FIXME: This is very likely wrong sometimes.
451-
rewriteSourceRange(R, O->getLHS()->getSourceRange(),
452-
"__3c_tmp_" + CV->getName());
453-
R.InsertTextAfterToken(O->getEndLoc(),
454-
", " + CV->getName() + " = " + "__3c_tmp_" +
455-
CV->getName());
438+
if (!isAssignmentPointerArithmetic(O->getLHS(), O->getRHS())) {
439+
// TODO: I don't like calling getExprConstraintVars in the rewriting
440+
// because this has been a persistent source of errors in the cast
441+
// placement code.
442+
CVarSet LHSCVs = CR.getExprConstraintVarsSet(O->getLHS());
443+
// FIXME: This isn't always a singleton: `int **a, **b; *(0 ? a : b) = 0;`
444+
// As long as inner pointers can't have bounds, we should be able
445+
// to differ a proper solution.
446+
ConstraintVariable *CV = getOnly(LHSCVs);
447+
if (CV->hasBoundsKey() &&
448+
Info.getABoundsInfo().needsRangeBound(CV->getBoundsKey())) {
449+
std::string TmpVarName = "__3c_tmp_" + CV->getName();
450+
rewriteSourceRange(R, O->getLHS()->getSourceRange(), TmpVarName);
451+
R.InsertTextAfterToken(O->getEndLoc(),
452+
", " + CV->getName() + " = " + TmpVarName);
453+
}
456454
}
457455
}
458456
return true;
459457
}
460458

461459
private:
462-
ASTContext *Context;
463460
ProgramInfo &Info;
464461
ConstraintResolver CR;
465462
Rewriter &R;
@@ -708,7 +705,6 @@ void RewriteConsumer::HandleTranslationUnit(ASTContext &Context) {
708705
CLV.TraverseDecl(D);
709706
ECPV.TraverseDecl(D);
710707
TPA.TraverseDecl(D);
711-
//TODO: I don't believe the position of AU in the order should matter.
712708
AU.TraverseDecl(D);
713709
}
714710

clang/lib/3C/Utils.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Sema/Sema.h"
1616
#include "llvm/Support/Path.h"
1717
#include <errno.h>
18+
#include <clang/3C/ConstraintResolver.h>
1819

1920
using namespace llvm;
2021
using namespace clang;
@@ -598,3 +599,97 @@ SourceLocation getCheckedCAnnotationsEnd(const Decl *D) {
598599

599600
return End;
600601
}
602+
603+
// Visitor to collect all the variables and structure member access that are
604+
// used during the life-time of the visitor.
605+
class CollectDeclsVisitor : public RecursiveASTVisitor<CollectDeclsVisitor> {
606+
public:
607+
explicit CollectDeclsVisitor() : ObservedDecls(), ObservedStructAccesses() {}
608+
609+
virtual ~CollectDeclsVisitor() {}
610+
611+
bool VisitDeclRefExpr(DeclRefExpr *DRE) {
612+
if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl()))
613+
ObservedDecls.insert(VD);
614+
return true;
615+
}
616+
617+
// For a->b; We need to get `a->b` rather than just `b`. This way assignment
618+
// from a field in one instance of a structure to the same field in another
619+
// instance is not treated as pointer arithmetic.
620+
bool VisitMemberExpr(MemberExpr *ME) {
621+
// TODO: Is this cast legit? `getMemberDecl()` returns a `ValueDecl*`, but I
622+
// think it can only be a `FieldDecl` for structs in C.
623+
auto *FD = cast<FieldDecl>(ME->getMemberDecl());
624+
625+
// TODO: Is recursively using a new visitor the right thing to do? It feels
626+
// odd.
627+
CollectDeclsVisitor MEVis;
628+
MEVis.TraverseStmt(ME->getBase());
629+
// Field access through variable.
630+
for (auto *D : MEVis.getObservedDecls()) {
631+
std::vector<FieldDecl *> SingletonAccessList({FD});
632+
ObservedStructAccesses.insert(std::make_pair(D, SingletonAccessList));
633+
}
634+
// Field access through other structure fields.
635+
for (StructAccess SA : MEVis.getObservedStructAccesses()) {
636+
SA.second.push_back(FD);
637+
ObservedStructAccesses.insert(SA);
638+
}
639+
return false;
640+
}
641+
642+
bool VisitCallExpr(CallExpr *CE) {
643+
// Stop the visitor when we hit a CallExpr. This stops us from treating a
644+
// function call like `a = foo(a);` the same as `a = a + 1`.
645+
return false;
646+
}
647+
648+
const std::set<VarDecl *> &getObservedDecls() { return ObservedDecls; }
649+
650+
typedef std::pair<VarDecl *, std::vector<FieldDecl *>> StructAccess;
651+
const std::set<StructAccess> &getObservedStructAccesses() {
652+
return ObservedStructAccesses;
653+
}
654+
655+
private:
656+
// Contains all VarDecls seen by this visitor
657+
std::set<VarDecl *> ObservedDecls;
658+
659+
// Contains the source representation of all record access (MemberExpression)
660+
// seen by this visitor.
661+
std::set<StructAccess> ObservedStructAccesses;
662+
};
663+
664+
bool isAssignmentPointerArithmetic(Expr *LHS, Expr *RHS) {
665+
CollectDeclsVisitor LVarVis;
666+
LVarVis.TraverseStmt(LHS);
667+
668+
CollectDeclsVisitor RVarVis;
669+
RVarVis.TraverseStmt(RHS);
670+
671+
std::set<VarDecl *> CommonVars;
672+
std::set<CollectDeclsVisitor::StructAccess> CommonStVars;
673+
findIntersection(LVarVis.getObservedDecls(), RVarVis.getObservedDecls(),
674+
CommonVars);
675+
findIntersection(LVarVis.getObservedStructAccesses(),
676+
RVarVis.getObservedStructAccesses(), CommonStVars);
677+
678+
// If CommonVars is not empty, then the same pointer appears on the LHS and
679+
// RHS of an assignment. We say that the pointer is assigned from a pointer
680+
// arithmetic expression.
681+
return !CommonVars.empty() || !CommonStVars.empty();
682+
683+
// TODO: Consider alternative implementation. The above code is based on an
684+
// implementation that was already used in the array bounds inference
685+
// code, so I have continued using it here. When I first needed this for
686+
// my own code, I reimplemented using constraint variable sets as shown
687+
// below. I have not consider exactly how these differ yet.
688+
#if 0
689+
CVarSet LHSCVs = CR.getExprConstraintVarsSet(LHS);
690+
CVarSet RHSCVs = CR.getExprConstraintVarsSet(RHS);
691+
CVarSet CommonCVars;
692+
findIntersection(LHSCVs, RHSCVs, CommonCVars);
693+
return !CommonCVars.empty();
694+
#endif
695+
}

0 commit comments

Comments
 (0)