Skip to content

Commit

Permalink
Merge pull request #42166 from mindula/fix-crash
Browse files Browse the repository at this point in the history
Fix compiler crash caused by functions with infinite while loops
  • Loading branch information
KavinduZoysa authored Mar 4, 2024
2 parents 1818b84 + 62bec15 commit 9262ae2
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ public void visit(BLangBlockFunctionBody astBody) {
}
this.env.enclLoopEndBB = endLoopEndBB;
this.currentBlock = prevBlock;
addReturnBB(astBody.pos);
}

private BIRBasicBlock beginBreakableBlock(BLangBlockStmt.FailureBreakMode mode) {
Expand Down Expand Up @@ -1392,15 +1393,9 @@ public void visit(BLangReturn astReturnStmt) {
BIROperand retVarRef = new BIROperand(this.env.enclFunc.returnVariable);
setScopeAndEmit(new Move(astReturnStmt.pos, this.env.targetOperand, retVarRef));

// Check whether this function already has a returnBB.
// Check and add a returnBB if the function does not have a returnBB.
// A given function can have only one BB that has a return instruction.
if (this.env.returnBB == null) {
// If not create one
BIRBasicBlock returnBB = new BIRBasicBlock(this.env.nextBBId());
addToTrapStack(returnBB);
returnBB.terminator = new BIRTerminator.Return(getFunctionLastLinePos());
this.env.returnBB = returnBB;
}
addReturnBB(getFunctionLastLinePos());
if (this.env.enclBB.terminator == null) {
this.env.unlockVars.forEach(s -> {
int i = s.size();
Expand Down Expand Up @@ -1438,12 +1433,7 @@ private BLangDiagnosticLocation getFunctionLastLinePos() {
public void visit(BLangPanic panicNode) {
panicNode.expr.accept(this);
// Some functions will only have panic but we need to add return for them to make current algorithm work.
if (this.env.returnBB == null) {
BIRBasicBlock returnBB = new BIRBasicBlock(this.env.nextBBId());
addToTrapStack(returnBB);
returnBB.terminator = new BIRTerminator.Return(panicNode.pos);
this.env.returnBB = returnBB;
}
addReturnBB(panicNode.pos);
this.env.enclBB.terminator = new BIRTerminator.Panic(panicNode.pos, this.env.targetOperand, this.currentScope);

// This basic block will contain statement that comes right after this 'if' statement.
Expand Down Expand Up @@ -3059,4 +3049,13 @@ private BIRVariableDcl getAnnotations(BVarSymbol annotations, BIRGenEnv env) {
}
return globalVarMap.get(annotations);
}

private void addReturnBB(Location pos) {
if (this.env.returnBB == null) {
BIRBasicBlock returnBB = new BIRBasicBlock(this.env.nextBBId());
addToTrapStack(returnBB);
returnBB.terminator = new BIRTerminator.Return(pos);
this.env.returnBB = returnBB;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ public void testNestedWhileStmtLoopTerminationWithFail() {
Assert.assertEquals(actual, expected);
}

@Test(description = "Test while statement with infinite loop")
public void testWhileStmtWithEndlessLoop() {
CompileResult compiled = BCompileUtil.compile("test-src/statements/whilestatement/while-stmt-infinite.bal");
Assert.assertEquals(compiled.getErrorCount(), 0);
}

@Test(description = "Check incompatible types.")
public void testNegative1() {
int index = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const TRUE = true;

function testWhileStatementWithEndlessLoop() returns int {
int x = 1;
while true {
x += 1;
}
}

function testWhileStatementWithEndlessLoop2() returns int|never {
int x = 1;
while TRUE {
x += 1;
}
}

function testWhileStatementWithEndlessLoop3() returns int {
int x = 1;
while true {
while true {
while true {
x += 1;
}
}
}
}

function testWhileStatementWithEndlessLoop4() returns int {
int x = 0;
while true {
x += 1;
if (x == 50) {
// Intentionally no break statement
}
}
}

function testInfiniteLoopWhileStatementInWorker() returns future<int> {
worker name returns int {
while true {

}
}
return name;
}

function testInfiniteLoopWhileStatementInAnonymousFunction() {
function() returns int fn = function () returns int {
while true {

}
};
_ = fn();
}


function testInfiniteLoopWhileStatementInConditionalStatement(int x) returns int {
if x > 10 {
while true {

}
} else {
while true {

}
}
}

client class MyClientClass {
resource function accessor path() returns int {
while true {

}
}

remote function testInfiniteLoopWhileStatementInRemote() returns int {
while true {

}
}
}

0 comments on commit 9262ae2

Please sign in to comment.