Skip to content

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

Merged
sulekhark merged 12 commits into
masterfrom
bug_fix_1017
Apr 17, 2021
Merged

Fix for #1017: Compiler issues an invalid-bounds error message for an out-of-scope variable.#1031
sulekhark merged 12 commits into
masterfrom
bug_fix_1017

Conversation

@sulekhark

Copy link
Copy Markdown
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 dtarditi, kkjeer and mgrang April 14, 2021 17:06
Comment thread clang/lib/Sema/BoundsAnalysis.cpp
Comment thread clang/lib/Sema/SemaBounds.cpp Outdated

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

Copy link
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown

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.

@mgrang mgrang left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM.

@kkjeer kkjeer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@dtarditi dtarditi left a comment

Copy link
Copy Markdown
Member

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
Copy Markdown
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%

@dtarditi dtarditi left a comment

Copy link
Copy Markdown
Member

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