原文链接:

CON51-CPP. Ensure actively held locks are released on exceptional conditions


用于保护共享数据访问的互斥量可以使用 lock()成员函数进行加锁,并使用 unlock() 成员函数进行解锁。如果在调用lock()unlock()之间发生异常,并且该异常改变了控制流, 使得unlock()没有被调用,那么互斥锁将被留在锁定状态, 且任何由该互斥锁保护的临界区将无法被执行,这很可能导致死锁。

异常的抛出不能让互斥锁无限期地处于锁定状态。如果互斥量被加锁,并且在受该互斥量保护的临界区中发生异常,这个互斥量必须在异常被再次抛出或者后续任务执行前, 作为异常处理操作的一部分被解锁, 除非后续的控制流将解锁该互斥量。

C++提供了锁类(lock_guardunique_lockshared_lock),可用于初始化互斥量。锁对象在其构造函数中锁定互斥量,在析构函数中解锁互斥量。lock_guard 类提供了一个简单的 RAII 包装器。unique_lockshared_lock类也运用了RAII, 提供了另外一些功能,例如手动控制锁定策略。unique_lock类禁止锁被拷贝,虽然它允许锁的所有权被移动到另一个锁上。shared_lock类允许互斥量被多个锁共享。对于这三个类,如果发生异常并且控制流跳出锁作用范围,则析构函数将解锁互斥锁,程序可以正常继续工作。这些锁对象是确保在抛出异常时互斥量被正确释放的首选方式。

不合规代码示例

这个不合规的代码示例操作共享数据,并通过锁定互斥对象来保护关键部分。当执行结束时,它会解锁互斥对象。然而,如果在操作共享数据时出现异常,那么互斥对象将保持锁定状态。

1
2
3
4
5
6
7
8
9
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
pm.lock();

// Perform work on shared data.

pm.unlock();
}

合规解决方案 (手动解锁)

该合规方案在捕获任何在共享数据做操作过程中出现的异常, 并且在异常被重复抛出前解锁互斥量.

1
2
3
4
5
6
7
8
9
10
11
12
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
pm.lock();
try {
// Perform work on shared data.
} catch (...) {
pm.unlock();
throw;
}
pm.unlock(); // in case no exceptions occur
}

合规解决方案 (锁定对象)

这个合规方案使用了 lock_guard 对象来确保互斥量被解锁, 即使异常发生, 也不需要依赖异常处理机制来手动资源管理.

1
2
3
4
5
6
7
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
std::lock_guard<std::mutex> lk(pm);

// Perform work on shared data.
}

Risk Assessment

If an exception occurs while a mutex is locked, deadlock may result.

Rule Severity Likelihood Remediation Cost Priority Level
CON51-CPP Low Probable Low P6 L2

Automated Detection

Tool Version Checker Description
CodeSonar 7.3p0 CONCURRENCY.LOCK.NOUNLOCK Missing Lock Release
Helix QAC 2023.1 C++5018
Parasoft C/C++test 2022.2 CERT_CPP-CON51-a Do not call lock() directly on a mutex
PRQA QA-C++ 4.4 5018

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

This rule is a subset of ERR56-CPP. Guarantee exception safety.

MITRE CWE CWE-667, Improper Locking
SEI CERT Oracle Coding Standard for Java LCK08-J. Ensure actively held locks are released on exceptional conditions

Bibliography

[ISO/IEC 14882-2014] Subclause 30.4.2, “Locks”

img img img