Skip to content

Commit 65b7ec0

Browse files
committed
Split the security aspect of PWR018 into PWR085
1 parent d313e3a commit 65b7ec0

7 files changed

Lines changed: 233 additions & 2 deletions

File tree

Checks/PWR018/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ control flow logic which the compilers cannot vectorize automatically.
1919
> In addition to facilitating vectorization, rewriting algorithms in a
2020
> non-recursive way increases code resilience. Recursive calls may rapidly lead
2121
> to stack overflows when the recursion depth is too high, potentially causing
22-
> crashes.
22+
> crashes. See check [PWR085](../PWR085/README.md) for more details.
2323
2424
> [!NOTE]
2525
> Whether the loop with a recursive function call is vectorizable or not after

Checks/PWR085/README.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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]

Checks/PWR085/example.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// PWR085: Favor iterative implementations over recursion to prevent stack overflows
2+
3+
double fib(unsigned n) {
4+
if (n == 0) {
5+
return 0.0;
6+
}
7+
if (n == 1) {
8+
return 1.0;
9+
}
10+
return fib(n - 1) + fib(n - 2);
11+
}
12+
13+
double example(unsigned times) {
14+
double sum = 0.0;
15+
for (unsigned i = 0; i < times; i++) {
16+
sum += fib(i);
17+
}
18+
return sum;
19+
}

Checks/PWR085/example.f90

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
! PWR085: Favor iterative implementations over recursion to prevent stack overflows
2+
3+
module mod_fibonacci
4+
implicit none
5+
contains
6+
recursive function fibonacci(n) result(fibo)
7+
implicit none
8+
integer, intent(in) :: n
9+
integer :: fibo
10+
11+
if (n == 0) then
12+
fibo = 0
13+
else if (n == 1) then
14+
fibo = 1
15+
else
16+
fibo = fibonacci(n - 1) + fibonacci(n - 2)
17+
end if
18+
end function fibonacci
19+
end module mod_fibonacci
20+
21+
subroutine example(times)
22+
use mod_fibonacci, only : fibonacci
23+
24+
implicit none
25+
integer, intent(in) :: times
26+
integer :: i, sum
27+
28+
sum = 0
29+
30+
do i = 0, times - 1
31+
sum = sum + fibonacci(i)
32+
end do
33+
end subroutine example

Checks/PWR085/solution.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// PWR085: Favor iterative implementations over recursion to prevent stack overflows
2+
3+
__attribute__((pure)) double example(unsigned times) {
4+
double sum = 0.0;
5+
double fib_0 = 0.0;
6+
double fib_1 = 1.0;
7+
for (unsigned i = 2; i < times; i++) {
8+
double fib = fib_0 + fib_1;
9+
sum += fib;
10+
fib_0 = fib_1;
11+
fib_1 = fib;
12+
}
13+
return sum;
14+
}

Checks/PWR085/solution.f90

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
! PWR085: Favor iterative implementations over recursion to prevent stack overflows
2+
3+
subroutine example(times)
4+
implicit none
5+
integer, intent(in) :: times
6+
integer :: i, sum
7+
integer :: fib_0, fib_1, fib
8+
9+
sum = 0
10+
fib_0 = 0
11+
fib_1 = 1
12+
13+
do i = 2, times - 1
14+
fib = fib_0 + fib_1
15+
sum = sum + fib
16+
fib_0 = fib_1
17+
fib_1 = fib
18+
end do
19+
end subroutine example

0 commit comments

Comments
 (0)