Skip to content

Explain bounds proof failure caused by free variables in inferred/declared bounds #903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 53 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5722d2d
Target error message at assignments
dopelsunce Jul 29, 2020
021e928
Target subexpressions to blame on error messages for unknown inferred…
dopelsunce Aug 1, 2020
354a859
Update tests to reflect fine-grained error messages
dopelsunce Aug 1, 2020
2a82843
Update comments
dopelsunce Aug 3, 2020
af5f9c3
Remove unused variable
dopelsunce Aug 3, 2020
f6f3af5
* Also add (V, E) to BlameAssignments if E modifies the bounds of V
dopelsunce Aug 3, 2020
7296d8b
Update tests to reflect the missing case
dopelsunce Aug 3, 2020
70aa057
Restore whitespace
dopelsunce Aug 4, 2020
3abacfd
Restore whitespace
dopelsunce Aug 4, 2020
b22bd1a
Restore whitespace
dopelsunce Aug 4, 2020
29926f2
Restore whitespace
dopelsunce Aug 4, 2020
3317bce
Refactor and address the missing case; fix tests
dopelsunce Aug 5, 2020
ff01d32
Clarify the logic in BlameAssignmentWithinStmt
dopelsunce Aug 6, 2020
d321731
Reorder BoundsDeclarationCheck enum and update comments
dopelsunce Aug 10, 2020
6b84507
Gather proof failure cause and new error message
dopelsunce Aug 11, 2020
729e959
Update diagnostic messages
dopelsunce Aug 12, 2020
a22825d
Convert offset constant to count
Aug 12, 2020
edb3309
Simplify error messages
dopelsunce Aug 13, 2020
3df3205
New error message
dopelsunce Aug 13, 2020
62c2af8
Find free variables; use const modifier for some parameters
dopelsunce Aug 14, 2020
13ecbba
Clean up and small fix
dopelsunce Aug 17, 2020
5c5729f
Check equal variable
Aug 17, 2020
aba5112
Traverse ImplicitCastExpr instead of DeclRefExpr
dopelsunce Aug 17, 2020
84781f7
Revert changes
dopelsunce Aug 18, 2020
69c8870
Remove extra changes
dopelsunce Aug 18, 2020
a1e0ebb
Add wrapper for ProofBoundsDeclValidity
dopelsunce Aug 18, 2020
f5be4c2
Add comments
dopelsunce Aug 18, 2020
cfa45ef
More comments
Aug 18, 2020
07f9d30
Fix CollectVariableSet Helper
Aug 24, 2020
caf29d3
Exclude variables that equal to a constant from free variables; consi…
dopelsunce Aug 24, 2020
3960544
Code refactoring
dopelsunce Aug 25, 2020
cf5c27d
Detect free variables in bases and offsets separately
dopelsunce Aug 27, 2020
2476209
Consider member accesses and filter out indirect accesses
dopelsunce Aug 28, 2020
1362645
Merge branch master
dopelsunce Aug 28, 2020
7199da9
Handle expected argument bounds
dopelsunce Aug 30, 2020
65476a1
Fix tests
dopelsunce Aug 30, 2020
9682a24
Add comments
dopelsunce Aug 31, 2020
c425694
Reformatting and fixing constant checking
dopelsunce Sep 2, 2020
7a65d59
Update comments and reformat
Sep 2, 2020
97b4556
fix test
Sep 2, 2020
842cc89
Do not check free variables in static cast
dopelsunce Sep 4, 2020
389e118
No free variable detection for static pointer casts and other cleanup
dopelsunce Sep 5, 2020
7a0c884
Clean up
dopelsunce Sep 5, 2020
b20f1e4
Minor fix
dopelsunce Sep 5, 2020
6dba79a
Add expected errors where the compiler is able to create a base range…
kkjeer Sep 15, 2020
867cf58
Free variables: fix #909 and #911 by ignoring casts in EquivExprs (#919)
dopelsunce Oct 10, 2020
555a93c
Detect indirect relationships between variables (#940)
kkjeer Jan 14, 2021
7db553c
Add free-variables.c test to CheckedC/static-checking
Jan 21, 2021
c934e70
Update InRangeWithFreeVars comment
Jan 22, 2021
7352252
Update more InRangeWithFreeVars comments
Jan 22, 2021
d46fc90
Update EqualExprsContainsExpr comment
Jan 22, 2021
323e8ee
Add TODO for quadratic algorithm in CollectVariableSetHelper
Jan 22, 2021
ab80d34
Merge branch 'master' of https://github.com/Microsoft/checkedc-clang …
Jan 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Free variables: fix #909 and #911 by ignoring casts in EquivExprs (#919)
* Fix issue #909 and #911 by ignoring casts in EquivExprs

* Replace IgnoreCasts with IgnoreParenCasts and add test cases
  • Loading branch information
dopelsunce authored Oct 10, 2020
commit 867cf58ba22c37b7b6bb30051a10887ec78a74ce
2 changes: 1 addition & 1 deletion clang/lib/AST/CanonBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ Result Lexicographic::CompareExpr(const Expr *Arg1, const Expr *Arg2) {
#include "clang/AST/StmtNodes.inc"
llvm_unreachable("cannot compare a statement");
case Expr::PredefinedExprClass: Cmp = Compare<PredefinedExpr>(E1, E2); break;
case Expr::DeclRefExprClass: return Compare<DeclRefExpr>(E1, E2);
case Expr::DeclRefExprClass: Cmp = Compare<DeclRefExpr>(E1, E2); break;
case Expr::IntegerLiteralClass: return Compare<IntegerLiteral>(E1, E2);
case Expr::FloatingLiteralClass: return Compare<FloatingLiteral>(E1, E2);
case Expr::ImaginaryLiteralClass: break;
Expand Down
39 changes: 24 additions & 15 deletions clang/lib/Sema/SemaBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,12 +571,12 @@ namespace {
// EqualExprsContainsExpr returns true if the set Exprs contains E.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't quite accurate. It returns true if Exprs contains an expression that is equivalent to E.

bool EqualExprsContainsExpr(Sema &S, const EqualExprTy Exprs, Expr *E,
EquivExprSets *EquivExprs) {
for (auto I = Exprs.begin(); I != Exprs.end(); ++I) {
for (auto I = Exprs.begin(); I != Exprs.end(); ++I) {
if (Lexicographic(S.Context, EquivExprs).CompareExpr(*I, E) ==
Lexicographic::Result::Equal)
return true;
}
return false;
Lexicographic::Result::Equal)
return true;
}
return false;
}

// Helper class for collecting a vector of unique variables as rvalues from an
Expand All @@ -595,12 +595,8 @@ namespace {
const EqualExprTy &GetVariableList() const { return VariableList; }

bool VisitDeclRefExpr(DeclRefExpr *E) {
// We cast variables to rvalues so they can be compared with rvalues in EquivExprSet.
// TODO(checkedc-clang#909): avoid constructing these ImplicitCastExprs.
ImplicitCastExpr *CastExpr = ExprCreatorUtil::CreateImplicitCast(
SemaRef, E, CK_LValueToRValue, E->getType());
if (!EqualExprsContainsExpr(SemaRef, VariableList, CastExpr, nullptr)) {
VariableList.push_back(CastExpr);
if (!EqualExprsContainsExpr(SemaRef, VariableList, E, nullptr)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has asymptotic behavior that is quadratic in the number of variables occurring in E. A better algorithm would be to use a hashtable to filter values and then append them the list of they aren't in the hash table. You could use the canonical declaration of the declaration referenced by E.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kkjeer, is my comment still accurate? If so, could you leave a comment in the code about the algorithm being quadratic. I don't like to leave quadratic algorithms around in a compiler without calling them out.

VariableList.push_back(E);
}

return true;
Expand Down Expand Up @@ -1465,8 +1461,7 @@ namespace {
break;
}

// We searched all declared variables and found neither a constant nor
// a match for SrcV.
// Find no constant or no match for SrcV in EquivExprs.
if (It == DstVars.end()) {
HasFreeVariables = true;
FreeVariables.push_back(SrcV);
Expand All @@ -1492,10 +1487,24 @@ namespace {
EqualExprTy Vars1 = CollectVariableSet(S, E1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This algorithm isn't correct because of its handling of equivalent expression sets. With equivalent expression sets, you may have two expressions that are known to be equal, such as "a.f == b.f", even though there is no equality of the variables used in the expressions. We don't know that a == b, for example.

We may need to generalize the notion of a variable v having relational information to another variable y. We need to check that there no expressions constructed from v or y that have relational information either.

EqualExprTy Vars2 = CollectVariableSet(S, E2);

if (AddFreeVariables(S, Vars1, Vars2, EquivExprs, Pos1, FreeVars))
// EquivVars holds sets of DeclRefExpr and IntegerLiteral filtered from
// EquivExprs.
EquivExprSets EquivVars;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An implication of my comment is that we shouldn't be filtering EquivVars. We could be removing expressions that have equality relationships and that use variables.

for (auto ExprSet : *EquivExprs) {
EqualExprTy Vars;
auto It = ExprSet.begin();
for (; It != ExprSet.end(); It++) {
*It = (*It)->IgnoreParenCasts();
if (isa<IntegerLiteral>(*It) || (isa<DeclRefExpr>(*It)))
Vars.push_back(*It);
}
EquivVars.push_back(Vars);
}

if (AddFreeVariables(S, Vars1, Vars2, &EquivVars, Pos1, FreeVars))
HasFreeVariables = true;

if (AddFreeVariables(S, Vars2, Vars1, EquivExprs, Pos2, FreeVars))
if (AddFreeVariables(S, Vars2, Vars1, &EquivVars, Pos2, FreeVars))
HasFreeVariables = true;

return HasFreeVariables;
Expand Down