Skip to content

Commit 0a2eb85

Browse files
authored
[libc++] Add thread safety annotations for std::lock (#154078)
Fixes #151733
1 parent a5b5248 commit 0a2eb85

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

libcxx/include/__config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ typedef __char32_t char32_t;
934934
# endif
935935
# endif
936936

937-
# if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(__no_thread_safety_analysis__)
937+
# if __has_attribute(__no_thread_safety_analysis__)
938938
# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((__no_thread_safety_analysis__))
939939
# else
940940
# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS

libcxx/include/mutex

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ public:
320320
};
321321

322322
template <class _L0, class _L1>
323-
_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
323+
_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
324324
unique_lock<_L0> __u0(__l0, try_to_lock_t());
325325
if (__u0.owns_lock()) {
326326
if (__l1.try_lock()) {
@@ -335,7 +335,7 @@ _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
335335
# ifndef _LIBCPP_CXX03_LANG
336336

337337
template <class _L0, class _L1, class _L2, class... _L3>
338-
_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
338+
_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
339339
int __r = 0;
340340
unique_lock<_L0> __u0(__l0, try_to_lock);
341341
if (__u0.owns_lock()) {
@@ -350,8 +350,11 @@ _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3
350350

351351
# endif // _LIBCPP_CXX03_LANG
352352

353+
// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable
354+
// the analysis inside the function.
353355
template <class _L0, class _L1>
354-
_LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) {
356+
_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1)
357+
_LIBCPP_ACQUIRE_CAPABILITY(__l0, __l1) {
355358
while (true) {
356359
{
357360
unique_lock<_L0> __u0(__l0);
@@ -375,7 +378,7 @@ _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) {
375378
# ifndef _LIBCPP_CXX03_LANG
376379

377380
template <class _L0, class _L1, class _L2, class... _L3>
378-
void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
381+
_LIBCPP_NO_THREAD_SAFETY_ANALYSIS void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
379382
while (true) {
380383
switch (__i) {
381384
case 0: {
@@ -410,8 +413,14 @@ void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
410413
}
411414
}
412415

416+
// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable
417+
// the analysis inside the function.
413418
template <class _L0, class _L1, class _L2, class... _L3>
414-
inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
419+
_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
420+
# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
421+
_LIBCPP_ACQUIRE_CAPABILITY(__l0, __l1, __l2, __l3...)
422+
# endif
423+
{
415424
std::__lock_first(0, __l0, __l1, __l2, __l3...);
416425
}
417426

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: no-threads
10+
11+
// <mutex>
12+
13+
// GCC doesn't have thread safety attributes
14+
// UNSUPPORTED: gcc
15+
16+
// ADDITIONAL_COMPILE_FLAGS: -Wthread-safety -Wno-comment
17+
18+
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
19+
20+
#include <mutex>
21+
22+
#include "test_macros.h"
23+
24+
std::mutex m0;
25+
std::mutex m1;
26+
std::mutex m2;
27+
std::mutex m3;
28+
29+
void f1() {
30+
std::lock(m0, m1);
31+
} // expected-warning {{mutex 'm0' is still held at the end of function}} \
32+
expected-warning {{mutex 'm1' is still held at the end of function}}
33+
34+
#if TEST_STD_VER >= 11 && TEST_CLANG_VER >= 2101
35+
void f2() {
36+
std::lock(m0, m1, m2);
37+
} // expected-warning {{mutex 'm0' is still held at the end of function}} \
38+
expected-warning {{mutex 'm1' is still held at the end of function}} \
39+
expected-warning {{mutex 'm2' is still held at the end of function}}
40+
41+
void f3() {
42+
std::lock(m0, m1, m2, m3);
43+
} // expected-warning {{mutex 'm0' is still held at the end of function}} \
44+
expected-warning {{mutex 'm1' is still held at the end of function}} \
45+
expected-warning {{mutex 'm2' is still held at the end of function}} \
46+
expected-warning {{mutex 'm3' is still held at the end of function}}
47+
#endif

0 commit comments

Comments
 (0)