Skip to content

Commit e7e5f74

Browse files
committed
[libc++] Guard call_once against operator hijacking.
1 parent e83ad81 commit e7e5f74

File tree

4 files changed

+24
-4
lines changed

4 files changed

+24
-4
lines changed

libcxx/include/__mutex/once_flag.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <__config>
1313
#include <__functional/invoke.h>
14+
#include <__memory/addressof.h>
1415
#include <__memory/shared_count.h> // __libcpp_acquire_load
1516
#include <__tuple/tuple_indices.h>
1617
#include <__tuple/tuple_size.h>
@@ -128,7 +129,7 @@ inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __fun
128129
typedef tuple<_Callable&&, _Args&&...> _Gp;
129130
_Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
130131
__call_once_param<_Gp> __p(__f);
131-
std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
132+
std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Gp>));
132133
}
133134
}
134135

@@ -138,15 +139,15 @@ template <class _Callable>
138139
inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) {
139140
if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
140141
__call_once_param<_Callable> __p(__func);
141-
std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
142+
std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Callable>));
142143
}
143144
}
144145

145146
template <class _Callable>
146147
inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) {
147148
if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
148149
__call_once_param<const _Callable> __p(__func);
149-
std::__call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>);
150+
std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<const _Callable>));
150151
}
151152
}
152153

libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "make_test_thread.h"
2323
#include "test_macros.h"
24+
#include "operator_hijacker.h"
2425

2526
typedef std::chrono::milliseconds ms;
2627

@@ -253,7 +254,20 @@ int main(int, char**)
253254
std::call_once(f2, std::move(rq));
254255
assert(rq.rv_called == 1);
255256
}
257+
{
258+
std::once_flag flag;
259+
auto f = [](const operator_hijacker&) {};
260+
std::call_once(flag, f, operator_hijacker{});
261+
}
262+
256263
#endif // TEST_STD_VER >= 11
257264

258-
return 0;
265+
#ifndef TEST_USE_FROZEN_CXX03_HEADERS
266+
{
267+
std::once_flag flag;
268+
operator_hijacker f;
269+
std::call_once(flag, f);
270+
}
271+
#endif // TEST_USE_FROZEN_CXX03_HEADERS
272+
return 0;
259273
}

libcxx/test/support/operator_hijacker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
struct operator_hijacker {
2424
TEST_CONSTEXPR bool operator<(const operator_hijacker&) const { return true; }
2525
TEST_CONSTEXPR bool operator==(const operator_hijacker&) const { return true; }
26+
TEST_CONSTEXPR void operator()() const {}
2627

2728
template <typename T>
2829
friend void operator&(T&&) = delete;

libcxx/test/support/test_macros.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@
272272
# define TEST_HAS_FROM_CHARS_FLOATING_POINT
273273
#endif
274274

275+
#ifdef _LIBCPP_USE_FROZEN_CXX03_HEADERS
276+
# define TEST_USE_FROZEN_CXX03_HEADERS
277+
#endif
278+
275279
namespace test_macros_detail {
276280
template <class T, class U>
277281
struct is_same { enum { value = 0};} ;

0 commit comments

Comments
 (0)