org.sonar.plugins.csharp.S2190.html Maven / Gradle / Ivy
Why is this an issue?
Having an infinite loop or recursion will lead to a program failure or a program never finishing the execution.
public int Sum()
{
var i = 0;
var result = 0;
while (true) // Noncompliant: the program will never stop
{
result += i;
i++;
}
return result;
}
This can happen in multiple scenarios.
Loop statements
while
and for
loops with no break
or return
statements that have exit conditions which are
always false
will be indefinitely executed.
"goto" statements
goto
statement with nothing that stops it from being executed over and over again will prevent the program from the completion.
Recursion
When a recursive method call chain lacks an exit condition, the call stack will reach its limit and the program will crash due to a StackOverflowException.
int Pow(int num, int exponent)
{
return num * Pow(num, exponent - 1); // Noncompliant: no condition under which Pow isn't re-called
}
In this example, Pow
will keep calling Pow
with exponent - 1
forever, until the program crashes with a
StackOverflowException.
Recursion provides some benefits.
- Simplified code: recursion can often lead to more concise and elegant code by breaking down complex problems into smaller,
more manageable parts.
- Improved code readability: compared to iterative solutions, recursive solutions can be easier to understand and reason about.
However, it has disadvantages as well.
- Stack overflow: Recursive functions can lead to stack overflow if the recursion is too deep, potentially
causing the program to crash.
- Performance overhead: Recursive function calls can lead to poor performance due to the need to push and pop stack frames,
making them potentially slower than iterative solutions.
- Difficulty in debugging: Debugging recursive code can be challenging, as multiple recursive calls can make it harder to track
the flow of execution and identify logical errors.
- Space complexity: Recursive algorithms may require more memory compared to iterative approaches, as each recursive call adds a
new frame to the call stack.
- Lack of control: Recursion can sometimes lead to infinite loops or unexpected behavior if not properly implemented or
terminated, making it crucial to have proper base cases and exit conditions.
How to fix it
The program’s logic should incorporate a mechanism to break out of the control flow loop. Here are some examples.
Code examples
- Use a loop condition which eventually evaluates to
false
Noncompliant code example
public int Sum()
{
var i = 0;
var result = 0;
while (true) // Noncompliant: the program will never stop
{
result += i;
i++;
}
return result;
}
Compliant solution
public int Sum()
{
var i = 0;
var result = 0;
while (result < 1000)
{
result += i;
i++;
}
return result;
}
- As {rule:csharpsquid:S907} generally suggests, avoid using
goto
statements. Instead, you can use a loop statement or explicit
recursion.
Noncompliant code example
public int Sum()
{
var result = 0;
var i = 0;
iteration:
// Noncompliant: program never ends
result += i;
i++;
goto iteration;
return result;
}
Compliant solution
public int Sum()
{
var i = 0;
var result = 0;
while (result < 1000)
{
result += i;
i++;
}
return result;
}
- For a recursion make sure there is a base case when the recursive method is not re-called.
Noncompliant code example
int Pow(int num, int exponent)
{
return num * Pow(num, exponent - 1); // Noncompliant: no condition under which Pow isn't re-called
}
Compliant solution
int Pow(int num, int exponent)
{
if (exponent > 1) // recursion is now conditional and stoppable
{
num = num * Pow(num, exponent - 1);
}
return num;
}
Resources
Documentation
- Microsoft Learn - The "for" statement
- Microsoft Learn - The "while"
statement
- Microsoft Learn - The "goto" statement
- Wikipedia Recursion - wiki
- Microsoft Learn - StackOverflowException
class
- {rule:csharpsquid:S907} - "goto" statement should not be used
Articles & blog posts
- Edsger Dijkstra - A Case against the GO TO Statement