|
| 1 | +# PWR085: Favor iterative implementations over recursion to prevent stack overflows |
| 2 | + |
| 3 | +### Issue |
| 4 | + |
| 5 | +Uncontrolled recursive calls may lead to program crashes. |
| 6 | + |
| 7 | +### Actions |
| 8 | + |
| 9 | +Rewrite the function using an iterative approach to avoid exhausting stack |
| 10 | +memory. |
| 11 | + |
| 12 | +### Relevance |
| 13 | + |
| 14 | +Recursive functions might seem the most intuitive approaches to implement some |
| 15 | +algorithms. However, a recursive algorithm that is not able to be "tail call |
| 16 | +optimized" can consume excessive stack memory, since the stack memory will need |
| 17 | +to grow with each call. |
| 18 | + |
| 19 | +This can be the case in a variety and a mix of scenarios, such as: |
| 20 | +- A system with limited stack memory. |
| 21 | +- An algorithm that requires a high number of recursive iterations. |
| 22 | +- A badly implemented control condition that does not exit when needed or when |
| 23 | +the recursion becomes too deep. |
| 24 | + |
| 25 | +> [!TIP] |
| 26 | +> In addition to increasing code resilience, rewriting algorithms |
| 27 | +> in a non-recursive way facilitates vectorization.See check |
| 28 | +> [PWR018](../PWR018/README.md) for more details. |
| 29 | +
|
| 30 | +### Code example |
| 31 | + |
| 32 | +#### C |
| 33 | + |
| 34 | +In the following example, the loop is invoking a recursive function computing |
| 35 | +the Fibonacci number: |
| 36 | + |
| 37 | +```c |
| 38 | +double fib(unsigned n) { |
| 39 | + if (n == 0) { |
| 40 | + return 0.0; |
| 41 | + } |
| 42 | + if (n == 1) { |
| 43 | + return 1.0; |
| 44 | + } |
| 45 | + return fib(n - 1) + fib(n - 2); |
| 46 | +} |
| 47 | + |
| 48 | +double example(unsigned times) { |
| 49 | + double sum = 0.0; |
| 50 | + for (unsigned i = 0; i < times; i++) { |
| 51 | + sum += fib(i); |
| 52 | + } |
| 53 | + return sum; |
| 54 | +} |
| 55 | +``` |
| 56 | +
|
| 57 | +As an alternative, Fibonacci's sequence can be calculated non-recursively: |
| 58 | +
|
| 59 | +```c |
| 60 | +__attribute__((pure)) double example(unsigned times) { |
| 61 | + double sum = 0.0; |
| 62 | + double fib_0 = 0.0; |
| 63 | + double fib_1 = 1.0; |
| 64 | + for (unsigned i = 2; i < times; i++) { |
| 65 | + double fib = fib_0 + fib_1; |
| 66 | + sum += fib; |
| 67 | + fib_0 = fib_1; |
| 68 | + fib_1 = fib; |
| 69 | + } |
| 70 | + return sum; |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +#### Fortran |
| 75 | + |
| 76 | +In the following example, the loop is invoking a recursive function computing |
| 77 | +the Fibonacci number: |
| 78 | + |
| 79 | +```fortran |
| 80 | +module mod_fibonacci |
| 81 | + implicit none |
| 82 | + contains |
| 83 | + recursive function fibonacci(n) result(fibo) |
| 84 | + implicit none |
| 85 | + integer, intent(in) :: n |
| 86 | + integer :: fibo |
| 87 | +
|
| 88 | + if (n == 0) then |
| 89 | + fibo = 0 |
| 90 | + else if (n == 1) then |
| 91 | + fibo = 1 |
| 92 | + else |
| 93 | + fibo = fibonacci(n - 1) + fibonacci(n - 2) |
| 94 | + end if |
| 95 | + end function fibonacci |
| 96 | +end module mod_fibonacci |
| 97 | +
|
| 98 | +subroutine example(times) |
| 99 | + use mod_fibonacci, only : fibonacci |
| 100 | +
|
| 101 | + implicit none |
| 102 | + integer, intent(in) :: times |
| 103 | + integer :: i, sum |
| 104 | +
|
| 105 | + sum = 0 |
| 106 | +
|
| 107 | + do i = 0, times - 1 |
| 108 | + sum = sum + fibonacci(i) |
| 109 | + end do |
| 110 | +end subroutine example |
| 111 | +``` |
| 112 | + |
| 113 | +As an alternative, Fibonacci's sequence can be calculated non-recursively: |
| 114 | + |
| 115 | +```fortran |
| 116 | +subroutine example(times) |
| 117 | + implicit none |
| 118 | + integer, intent(in) :: times |
| 119 | + integer :: i, sum |
| 120 | + integer :: fib_0, fib_1, fib |
| 121 | +
|
| 122 | + sum = 0 |
| 123 | + fib_0 = 0 |
| 124 | + fib_1 = 1 |
| 125 | +
|
| 126 | + do i = 2, times - 1 |
| 127 | + fib = fib_0 + fib_1 |
| 128 | + sum = sum + fib |
| 129 | + fib_0 = fib_1 |
| 130 | + fib_1 = fib |
| 131 | + end do |
| 132 | +end subroutine example |
| 133 | +``` |
| 134 | + |
| 135 | +### Related resources |
| 136 | + |
| 137 | +* [PWR085 examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR085/) |
| 138 | + |
| 139 | +### References |
| 140 | + |
| 141 | +* [CWE - CWE-674: Uncontrolled Recursion](https://cwe.mitre.org/data/definitions/674.html) |
| 142 | +[last checked February 2026] |
| 143 | + |
| 144 | +* [Tail call optmization](https://en.wikipedia.org/wiki/Tail_call) |
| 145 | +[last checked February 2026] |
0 commit comments