CON54-CPP. 在循环中包装可能虚假唤醒的函数
原文链接:
CON54-CPP. Wrap functions that can spuriously wake up in a loop
std::condition_variable
类的 wait()
、wait_for()
和 wait_until()
成员函数暂时放弃互斥量的所有权,以便其它可能正在请求互斥量的线程可以继续执行。这些函数必须始终从由被互斥量锁定保护的代码中调用。等待线程只有在被通知后才会恢复执行,通常是由另一个线程调用成员函数 notify_one()
或 notify_all()
触发。
wait()
函数必须从检查条件谓词的循环中调用。条件谓词是由函数变量构建的表达式,必须为真, 线程才被允许继续执行。线程通过 wait()
、wait_for()
、wait_until()
或者其它机制暂停,稍后可能在条件谓词为真且线程被通知时恢复执行。
1 |
|
通知机制通知等待线程并允许它检测它的条件谓词。在另一个线程中调用 notify_all()
不能准确地判定哪个等待线程将被恢复。条件谓词语句允许被通知的线程在接收到通知后决定是否应该恢复。
不合规代码示例
这个不合规代码示例监视一个链表,并分配一个线程在链表非空时消费其中的元素。
这个线程使用 wait()
暂停执行,并在被通知时恢复,若列表有可消费的元素。即使链表仍然为空,线程也有可能被通知,可能是因为通知线程使用了 notify_all()
,它会通知所有线程。使用 notify_all()
的通知通常比使用 notify_one()
更受欢迎(有关更多信息请参见 CON55-CPP. Preserve thread safety and liveness when using condition variables )。
条件谓词通常是循环中否定的条件表达式。在这个不合规代码示例中,从链表中删除元素的条件谓词是 (list->next != nullptr)
,而循环条件中的条件表达式是 (list->next == nullptr)
。
这个不合规代码示例在 if
代码块内嵌套了 wait()
的调用,因此在接收到通知后条件谓词不为真。如果通知是虚假或恶意的,线程将会过早地唤醒。
1 |
|
合规解决方案(带谓词的显式循环)
这个合规解决方案在 while
循环中调用成员函数 wait()
,在调用 wait()
前后都进行条件判断。
1 |
|
合规解决方案(带 lambda 谓词的隐式循环)
std::condition_variable::wait()
函数有一种重载形式,它接受一个谓词形式的函数对象。这种 wait()
的形式表现得像是通过 while(!pred()) wait(lock)
实现的。这个合规的解决方案使用一个 lambda
作为谓词并将它传递给 wait()
函数。谓词为真, 程序继续执行,这和使用显式循环谓词的合规方案中的谓词逻辑刚好相反。
1 |
|
Risk Assessment
Failure to enclose calls to the wait()
, wait_for()
, or wait_until()
member functions inside a while
loop can lead to indefinite blocking and denial of service (DoS).
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON54-CPP | Low | Unlikely | Medium | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
CodeSonar | 7.3p0 | LANG.STRUCT.ICOL CONCURRENCY.BADFUNC.CNDWAIT | Inappropriate Call Outside Loop Use of Condition Variable Wait |
Helix QAC | 2023.1 | C++5019 | |
Klocwork | 2023.1 | CERT.CONC.WAKE_IN_LOOP | |
Parasoft C/C++test | 2022.2 | CERT_CPP-CON54-a | Wrap functions that can spuriously wake up in a loop |
Polyspace Bug Finder | R2023a | CERT C++: CON54-CPP | Checks for situations where functions that can spuriously wake up are not wrapped in loop |
PRQA QA-C++ | 4.4 | 5019 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[ISO/IEC 9899:2011] | 7.17.7.4, “The atomic_compare_exchange Generic Functions” |
---|---|
[Lea 2000] | 1.3.2, “Liveness” 3.2.2, “Monitor Mechanics” |
本文标题:CON54-CPP. 在循环中包装可能虚假唤醒的函数
文章作者:xwnb
发布时间:2023-04-01
最后更新:2023-04-17
原始链接:https://xwnb.github.io/posts/1519021198/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!并保留本声明。感谢您的阅读和支持!
分享