Skip to content
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

Fix for #1017: Compiler issues an invalid-bounds error message for an out-of-scope variable. #1031

Merged
merged 12 commits into from
Apr 17, 2021

Conversation

sulekhark
Copy link
Contributor

Intersecting the set of in-scope variables across the predecessors of a basic block excludes most variables that are not in-scope for the basic block. However, an exception is when a variable goes out of scope within the basic block. When this happens, the bug in #1017 manifests.

Fix:
Enabling the AddLifetime flag during CFG construction produces the CFGLifetimeEnds CFGElement for every variable that goes out of scope. When we encounter this CFGElement, we remove the variable that goes out of scope from the ObservedBounds map if it is a checked pointer, and also delete all available expressions that use this out-of-scope variable.

@sulekhark sulekhark requested review from mgrang, kkjeer and dtarditi April 14, 2021 17:06
clang/lib/Sema/BoundsAnalysis.cpp Show resolved Hide resolved

EquivExprSets CrntEquivExprs(State.EquivExprs);
State.EquivExprs.clear();
for (auto I = CrntEquivExprs.begin(); I != CrntEquivExprs.end(); ++I) {
Copy link

Choose a reason for hiding this comment

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

Since CrntEquivExprs is not mutated inside the loop, a more efficient way to write this loop is as follows:
for (auto I = CrntEquivExprs.begin(), E = CrntEquivExprs.end(); I != E; ++I)

This avoids repeated evaluation of CrntEquivExprs.end() each time through the loop.

See https://llvm.org/docs/CodingStandards.html#don-t-evaluate-end-every-time-through-a-loop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

// CFGElement. When a variable goes out of scope, ObservedBounds and
// EquivExprs in the CheckingState have to be updated.
CFGLifetimeEnds LE = Elem.castAs<CFGLifetimeEnds>();
VarDecl *V = const_cast<VarDecl *>(LE.getVarDecl());
Copy link

Choose a reason for hiding this comment

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

Can LE.getVarDecl() be null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It shouldn't be null but I have added check to ensure this.

Copy link

Choose a reason for hiding this comment

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

If LE.getVarDecl() is null const_cast<VarDecl *>(LE.getVarDecl()) will crash. It may be better to use dyn_cast_or_null instead of const_cast.

Copy link

Choose a reason for hiding this comment

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

If LE.getVarDecl() is null const_cast<VarDecl *>(LE.getVarDecl()) will crash. It may be better to use dyn_cast_or_null instead of const_cast.

In an offline discussion Sulekha pointed to this link (https://en.cppreference.com/w/cpp/language/const_cast) which indicates that "a null pointer value would be converted to a null pointer value of new_type". So this code should work fine and there is no need to explicitly check if LE.getVarDecl() is null before invoking const_cast.

Copy link

@mgrang mgrang left a comment

Choose a reason for hiding this comment

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

LGTM.

Copy link
Contributor

@kkjeer kkjeer left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@dtarditi dtarditi left a comment

Choose a reason for hiding this comment

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

@sulekhark, what is the effect on compile-time of this change?

In the future, we might want to optimize how deletion is done for equivalent expressions, given that the deletion operation is being done every time a variable lifetime ends. I'm not requesting that we optimize it right now. I'm curious about the effect on compile-time of this change.

@sulekhark
Copy link
Contributor Author

@dtarditi Compile time increases by 2.35% .

Here are the details:
master: compile time summed up over all clang and checkedc test cases (averaged over six runs): 6133 s
bug_fix_1017: compile time summed up over all clang and checkedc test cases (averaged over six runs): 6277 s
Overall increase in compile time : 144 s
Percentage increase : 2.35%

Copy link
Member

@dtarditi dtarditi left a comment

Choose a reason for hiding this comment

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

Thanks for measuring the effect on compile-time and opening an issue to track looking at that later. A 2% compile-time increase is something that we can live with for now, so I approve the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants