Skip to content

Commit 8355298

Browse files
CWE-460 (#962)
* Create compliant.py Signed-off-by: Ketki <[email protected]> * Create noncompliant.py Signed-off-by: Ketki <[email protected]> * Create README.md Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/noncompliant.py Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/compliant.py Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-460/README.md Co-authored-by: Bartlomiej Karas <[email protected]> Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update compliant.py for lint compliance Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> * Update README.md Signed-off-by: Ketki <[email protected]> --------- Signed-off-by: Ketki <[email protected]> Co-authored-by: Bartlomiej Karas <[email protected]>
1 parent 6d5bf6c commit 8355298

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
2+
# CWE-460: Improper Cleanup on Thrown Exception
3+
4+
Make sure that your code fully and correctly cleans up its state whenever an exception occurs to avoid unexpected state or control flow.
5+
6+
Often, when functions or loops become complicated, some level of resource cleanup is needed throughout execution.
7+
Exceptions can disturb the flow of the code and prevent the necessary cleanup from happening.
8+
9+
A consequence of this is that the code is left in a bad state.
10+
11+
One of the ways to mitigate this is to make sure that cleanup happens or that you should exit the program. Use throwing exceptions sparsely.
12+
13+
Another way to mitigate this is to use the ‘with’ statement. It simplifies resource management by automatically handling setup and cleanup tasks. It's commonly used with files, network connections and databases to ensure resources are properly released even if errors occur making your code cleaner.
14+
15+
## Non-Compliant Code Example
16+
17+
In the noncompliant.py example, a thread gets locked, but not unlocked due to an exception being thrown before it can be closed. This might lead to the lock remaining closed and inaccessible for further use.
18+
19+
noncompliant.py:
20+
21+
```python
22+
# SPDX-FileCopyrightText: OpenSSF project contributors
23+
# SPDX-License-Identifier: MIT
24+
25+
"""Non-compliant Code Example"""
26+
27+
import threading
28+
29+
lock = threading.Lock()
30+
31+
def perform_critical_operation():
32+
# the lock has been acquired for performing a critical operation
33+
lock.acquire()
34+
print("Lock acquired, performing critical operation...")
35+
# simulating an error before it can be released
36+
raise ValueError("Something went wrong!")
37+
lock.release() # This line is never reached due to the exception
38+
39+
try:
40+
perform_critical_operation()
41+
except ValueError as e:
42+
print(f"Caught exception: {e}")
43+
44+
# Next attempt to acquire the lock will block forever — deadlock!
45+
lock.acquire()
46+
print("This will never print because the lock was never released.")
47+
48+
```
49+
50+
In the above code example, the acquired lock never gets released, as an error gets thrown before it can be released.
51+
52+
## Compliant Solution
53+
54+
In compliant01.py we use the with statement to ensure that the lock is released properly even if an error is to occur.
55+
56+
compliant01.py:
57+
58+
## Compliant Code Example
59+
60+
```python
61+
# SPDX-FileCopyrightText: OpenSSF project contributors
62+
# SPDX-License-Identifier: MIT
63+
64+
""" Compliant Code Example """
65+
import threading
66+
67+
lock = threading.Lock()
68+
69+
def compliant_example():
70+
with lock:
71+
# the lock has been acquired using the 'with' statement and will be released when the block exits; even if an exception occurs
72+
print("Lock acquired, performing critical operation...")
73+
# raising an exception
74+
raise ValueError("Something went wrong!")
75+
print("Lock released.")
76+
77+
try:
78+
compliant_example()
79+
except ValueError as e:
80+
print(f"Caught exception: {e}")
81+
```
82+
83+
### with lock: is shorthand for
84+
85+
```python
86+
# SPDX-FileCopyrightText: OpenSSF project contributors
87+
# SPDX-License-Identifier: MIT
88+
89+
lock.acquire()
90+
try:
91+
...
92+
finally:
93+
lock.release()
94+
95+
```
96+
97+
It is best practice to use 'with' in such cases as it will make sure the resource gets released even if an exception occurs in the execution.
98+
99+
## Automated Detection
100+
101+
|||||
102+
|:---|:---|:---|:---|
103+
|Tool|Version|Checker|Description|
104+
105+
## Related Guidelines
106+
107+
|||
108+
|:---|:---|
109+
|[CWE MITRE Pillar](http://cwe.mitre.org/)|[https://cwe.mitre.org/data/definitions/460.html]|
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!--
2+
SPDX-FileCopyrightText: OpenSSF project contributors
3+
SPDX-License-Identifier: MIT
4+
-->
5+
6+
## Compliant Code Example
7+
8+
```python
9+
import threading
10+
11+
lock = threading.Lock()
12+
13+
14+
def perform_critical_operation():
15+
with lock:
16+
# the lock has been acquired using the 'with' statement and will be released when the block exits; even if an exception occurs
17+
print("Lock acquired, performing critical operation...")
18+
# raising an exception
19+
raise ValueError("Something went wrong!")
20+
# This line will not be reached because of the exception above,
21+
print("Lock released.")
22+
23+
24+
try:
25+
perform_critical_operation()
26+
except ValueError as e:
27+
print(f"Caught exception: {e}")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
import threading
5+
6+
7+
lock = threading.Lock()
8+
9+
10+
def perform_critical_operation():
11+
lock.acquire()
12+
print("Lock acquired, performing critical operation...")
13+
raise ValueError("Something went wrong!")
14+
lock.release() # This line is never reached due to the exception
15+
16+
17+
try:
18+
perform_critical_operation()
19+
except ValueError as e:
20+
print(f"Caught exception: {e}")
21+
22+
23+
# Next attempt to acquire the lock will block forever; as there is a deadlock!
24+
lock.acquire()
25+
print("This will not print because the lock was never released.")
26+

0 commit comments

Comments
 (0)