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 index variable leak when forall body is empty #25915

Merged
merged 4 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
5 changes: 5 additions & 0 deletions compiler/resolution/AutoDestroyScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ void AutoDestroyScope::addEarlyDeinit(VarSymbol* var) {
INT_FATAL("could not find scope declaring var");
}


size_t AutoDestroyScope::numLocalsAndDefers() const {
return mLocalsAndDefers.size();
}

VarSymbol* AutoDestroyScope::findVariableUsedBeforeInitialized(Expr* stmt) {

if (CallExpr* call = toCallExpr(stmt)) {
Expand Down
3 changes: 3 additions & 0 deletions compiler/resolution/AutoDestroyScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class AutoDestroyScope {

void addEarlyDeinit(VarSymbol* var);

// Counts how many declarations exists
jabraham17 marked this conversation as resolved.
Show resolved Hide resolved
size_t numLocalsAndDefers() const;

VarSymbol* findVariableUsedBeforeInitialized(Expr* stmt);

// Forget about initializations for outer variables initialized
Expand Down
12 changes: 12 additions & 0 deletions compiler/resolution/addAutoDestroyCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,18 @@ static void walkBlockWithScope(AutoDestroyScope& scope,
LabelSymbol* retLabel = (parent == NULL) ? findReturnLabel(fn) : NULL;
bool isDeadCode = false;

// If the body is empty, the scope may still have variables to be
// auto-destroyed; one key example is loop index variables in a forall.
// We need an anchor to call 'insertAutoDestroys', so if we do need to
// insert them, create a noop.
if (block->body.empty() && scope.numLocalsAndDefers() > 0) {
SET_LINENO(block);
auto noop = new CallExpr(PRIM_NOOP);
block->body.insertAtTail(noop);
scope.insertAutoDestroys(fn, noop, ignoredVariables);
noop->remove();
}

for (Expr* stmt = block->body.first(); stmt != NULL; stmt = stmt->next) {
//
// Handle the current statement
Expand Down
24 changes: 24 additions & 0 deletions test/functions/iterators/bugs/stmt-iter-memory-leak.chpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class C {
proc deinit() {
writeln("deinit C");
}
}

record R {
proc deinit() {
writeln("deinit R");
}
}

iter foo() {
yield new C();
yield new C();
}

iter bar() {
yield new R();
yield new R();
}

foo();
bar();
4 changes: 4 additions & 0 deletions test/functions/iterators/bugs/stmt-iter-memory-leak.good
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
deinit C
deinit C
deinit R
deinit R
3 changes: 3 additions & 0 deletions test/library/standard/Sort/errors/sortDomainArray.assoc7.good
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
sortDomainArray.chpl:55: warning: It is recommended to use 'Sort.sorted' instead of this method. Compile with '-snoSortedWarnings' to suppress this warning.
sortDomainArray.chpl:55: warning: It is recommended to use 'Sort.sorted' instead of this method. Compile with '-snoSortedWarnings' to suppress this warning.
Note: This source location is a guess.
sortDomainArray.chpl:55: warning: It is recommended to use 'Sort.sorted' instead of this method. Compile with '-snoSortedWarnings' to suppress this warning.
18 changes: 9 additions & 9 deletions test/library/standard/Sort/errors/sortDomainArray.chpl
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ var SpsA: [SpsD] real;

if sparse1 then sort(SpsD); // should be an error
if sparse2 then isSorted(SpsD); // should be an error
if sparse3 then var x = sorted(SpsD); // should be an error
if sparse3 then sorted(SpsD); // should be an error
if sparse4 then sort(SpsA); // should be an error
if sparse5 then isSorted(SpsA); // should be an error
if sparse6 then var x = sorted(SpsA); // should be an error
if sparse7 then var x = SpsD.sorted(); // should be an error
if sparse6 then sorted(SpsA); // should be an error
if sparse7 then SpsD.sorted(); // should be an error


//
Expand All @@ -48,11 +48,11 @@ var AssocA = [1 => "one", 10 => "ten", 3 => "three", 16 => "sixteen"];

if assoc1 then sort(AssocD); // should be an error
if assoc2 then isSorted(AssocD); // should be an error
if assoc3 then var x = sorted(AssocD);
if assoc3 then sorted(AssocD);
if assoc4 then sort(AssocA); // should be an error
if assoc5 then isSorted(AssocA); // should be an error
if assoc6 then var x = sorted(AssocA);
if assoc7 then var x = AssocD.sorted(); // not an error, but warns
if assoc6 then sorted(AssocA);
if assoc7 then AssocD.sorted(); // not an error, but warns


//
Expand All @@ -64,8 +64,8 @@ var RectA: [RectD] real;

if rect1 then sort(RectD); // should be an error
if rect2 then isSorted(RectD); // should be an error
if rect3 then var x = sorted(RectD); // should be an error
if rect3 then sorted(RectD); // should be an error
if rect4 then sort(RectA);
if rect5 then isSorted(RectA);
if rect6 then var x = sorted(RectA);
if rect7 then var x = RectD.sorted(); // should be an error
if rect6 then sorted(RectA);
if rect7 then RectD.sorted(); // should be an error