[libc++] Use addressof in assignment operator.

Replace `&__rhs` with `_VSTD::addressof(__rhs)` to guard against ADL hijacking
of `operator&` in `operator=`. Thanks to @CaseyCarter for bringing it to our
attention.

Similar issues with hijacking `operator&` still exist, they will be
addressed separately.

Reviewed By: #libc, Quuxplusone, ldionne

Differential Revision: https://reviews.llvm.org/D110852
This commit is contained in:
Mark de Wever 2021-09-28 19:15:18 +02:00
parent 5ecdb77fc5
commit b8608b8723
26 changed files with 504 additions and 12 deletions

View File

@ -1541,7 +1541,7 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>&
__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u)
{
if (this != &__u)
if (this != _VSTD::addressof(__u))
{
__copy_assign_alloc(__u);
hash_function() = __u.hash_function();

View File

@ -1612,7 +1612,7 @@ template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>&
__tree<_Tp, _Compare, _Allocator>::operator=(const __tree& __t)
{
if (this != &__t)
if (this != _VSTD::addressof(__t))
{
value_comp() = __t.value_comp();
__copy_assign_alloc(__t);

View File

@ -1649,7 +1649,7 @@ template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>&
deque<_Tp, _Allocator>::operator=(const deque& __c)
{
if (this != &__c)
if (this != _VSTD::addressof(__c))
{
__copy_assign_alloc(__c);
assign(__c.begin(), __c.end());

View File

@ -990,7 +990,7 @@ template <class _Tp, class _Alloc>
forward_list<_Tp, _Alloc>&
forward_list<_Tp, _Alloc>::operator=(const forward_list& __x)
{
if (this != &__x)
if (this != _VSTD::addressof(__x))
{
base::__copy_assign_alloc(__x);
assign(__x.begin(), __x.end());

View File

@ -1392,7 +1392,7 @@ inline
list<_Tp, _Alloc>&
list<_Tp, _Alloc>::operator=(const list& __c)
{
if (this != &__c)
if (this != _VSTD::addressof(__c))
{
base::__copy_assign_alloc(__c);
assign(__c.begin(), __c.end());

View File

@ -1036,7 +1036,7 @@ public:
#ifndef _LIBCPP_CXX03_LANG
__tree_ = __m.__tree_;
#else
if (this != &__m) {
if (this != _VSTD::addressof(__m)) {
__tree_.clear();
__tree_.value_comp() = __m.__tree_.value_comp();
__tree_.__copy_assign_alloc(__m.__tree_);
@ -1820,7 +1820,7 @@ public:
#ifndef _LIBCPP_CXX03_LANG
__tree_ = __m.__tree_;
#else
if (this != &__m) {
if (this != _VSTD::addressof(__m)) {
__tree_.clear();
__tree_.value_comp() = __m.__tree_.value_comp();
__tree_.__copy_assign_alloc(__m.__tree_);

View File

@ -1056,7 +1056,7 @@ public:
#ifndef _LIBCPP_CXX03_LANG
__table_ = __u.__table_;
#else
if (this != &__u) {
if (this != _VSTD::addressof(__u)) {
__table_.clear();
__table_.hash_function() = __u.__table_.hash_function();
__table_.key_eq() = __u.__table_.key_eq();
@ -1988,7 +1988,7 @@ public:
#ifndef _LIBCPP_CXX03_LANG
__table_ = __u.__table_;
#else
if (this != &__u) {
if (this != _VSTD::addressof(__u)) {
__table_.clear();
__table_.hash_function() = __u.__table_.hash_function();
__table_.key_eq() = __u.__table_.key_eq();

View File

@ -3048,7 +3048,7 @@ template <class _Tp>
valarray<_Tp>&
valarray<_Tp>::operator=(const valarray& __v)
{
if (this != &__v)
if (this != _VSTD::addressof(__v))
return __assign_range(__v.__begin_, __v.__end_);
return *this;
}

View File

@ -1406,7 +1406,7 @@ inline _LIBCPP_INLINE_VISIBILITY
vector<_Tp, _Allocator>&
vector<_Tp, _Allocator>::operator=(const vector& __x)
{
if (this != &__x)
if (this != _VSTD::addressof(__x))
{
__base::__copy_assign_alloc(__x);
assign(__x.__begin_, __x.__end_);
@ -2859,7 +2859,7 @@ template <class _Allocator>
vector<bool, _Allocator>&
vector<bool, _Allocator>::operator=(const vector& __v)
{
if (this != &__v)
if (this != _VSTD::addressof(__v))
{
__copy_assign_alloc(__v);
if (__v.__size_)

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <map>
// class map
// map& operator=(const map& m);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <map>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
{
std::map<int, operator_hijacker> mo;
std::map<int, operator_hijacker> m;
m = mo;
}
{
std::map<operator_hijacker, int> mo;
std::map<operator_hijacker, int> m;
m = mo;
}
}

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <map>
// class multimap
// multimap& operator=(const multimap& m);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <map>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
{
std::multimap<int, operator_hijacker> mo;
std::multimap<int, operator_hijacker> m;
m = mo;
}
{
std::multimap<operator_hijacker, int> mo;
std::multimap<operator_hijacker, int> m;
m = mo;
}
}

View File

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <set>
// class multiset
// multiset& operator=(const multiset& s);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <set>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::multiset<operator_hijacker> so;
std::multiset<operator_hijacker> s;
s = so;
}

View File

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <set>
// class set
// set& operator=(const set& s);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <set>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::set<operator_hijacker> so;
std::set<operator_hijacker> s;
s = so;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <queue>
// priority_queue& operator=(const priority_queue&) = default;
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <queue>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::priority_queue<operator_hijacker> pqo;
std::priority_queue<operator_hijacker> pq;
pq = pqo;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <queue>
// queue& operator=(const queue& q);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <queue>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::queue<operator_hijacker> qo;
std::queue<operator_hijacker> q;
q = qo;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <array>
// implicitly generated array assignment operators
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <array>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::array<operator_hijacker, 1> ao;
std::array<operator_hijacker, 1> a;
a = ao;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <deque>
// deque& operator=(deque&& c);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <deque>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::deque<operator_hijacker> dqo;
std::deque<operator_hijacker> dq;
dq = dqo;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <forward_list>
// forward_list& operator=(const forward_list& x);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <forward_list>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::forward_list<operator_hijacker> lo;
std::forward_list<operator_hijacker> l;
l = lo;
}

View File

@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Guard the debug iterators against ADL-hijacking.
// XFAIL: LIBCXX-DEBUG-FIXME
// <list>
// list& operator=(const list& c);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <list>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::list<operator_hijacker> lo;
std::list<operator_hijacker> l;
l = lo;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <vector>
// vector& operator=(const vector& c);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <vector>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::vector<operator_hijacker> vo;
std::vector<operator_hijacker> v;
v = vo;
}

View File

@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Guard the debug iterators against ADL-hijacking.
// XFAIL: LIBCXX-DEBUG-FIXME
// <unordered_map>
// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
// class Alloc = allocator<pair<const Key, T>>>
// class unordered_map
// unordered_map& operator=(const unordered_map& u);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <unordered_map>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
{
std::unordered_map<int, operator_hijacker> mo;
std::unordered_map<int, operator_hijacker> m;
m = mo;
}
{
std::unordered_map<operator_hijacker, int> mo;
std::unordered_map<operator_hijacker, int> m;
m = mo;
}
}

View File

@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Guard the debug iterators against ADL-hijacking.
// XFAIL: LIBCXX-DEBUG-FIXME
// <unordered_map>
// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
// class Alloc = allocator<pair<const Key, T>>>
// class unordered_multimap
// unordered_multimap& operator=(const unordered_multimap& u);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <unordered_map>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
{
std::unordered_multimap<int, operator_hijacker> mo;
std::unordered_multimap<int, operator_hijacker> m;
m = mo;
}
{
std::unordered_multimap<operator_hijacker, int> mo;
std::unordered_multimap<operator_hijacker, int> m;
m = mo;
}
}

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Guard the debug iterators against ADL-hijacking.
// XFAIL: LIBCXX-DEBUG-FIXME
// <unordered_set>
// template <class Value, class Hash = hash<Value>, class Pred = equal_to<Value>,
// class Alloc = allocator<Value>>
// class unordered_multiset
// unordered_multiset& operator=(const unordered_multiset& u);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <unordered_set>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::unordered_multiset<operator_hijacker> so;
std::unordered_multiset<operator_hijacker> s;
s = so;
}

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Guard the debug iterators against ADL-hijacking.
// XFAIL: LIBCXX-DEBUG-FIXME
// <unordered_set>
// template <class Value, class Hash = hash<Value>, class Pred = equal_to<Value>,
// class Alloc = allocator<Value>>
// class unordered_set
// unordered_set& operator=(const unordered_set& u);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <unordered_set>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::unordered_set<operator_hijacker> so;
std::unordered_set<operator_hijacker> s;
s = so;
}

View File

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <valarray>
// template<class T> class valarray;
// valarray& operator=(const value_type& x);
// Validate whether the container can be copy-assigned with an ADL-hijacking operator&
#include <valarray>
#include "test_macros.h"
#include "operator_hijacker.h"
void test() {
std::valarray<operator_hijacker> vo;
std::valarray<operator_hijacker> v;
v = vo;
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef SUPPORT_OPERATOR_HIJACKER_H
#define SUPPORT_OPERATOR_HIJACKER_H
#include <cstddef>
#include <functional>
#include "test_macros.h"
/// Helper struct to test ADL-hijacking in containers.
///
/// The class has some additional operations to be usable in all containers.
struct operator_hijacker {
bool operator<(const operator_hijacker&) const { return true; }
bool operator==(const operator_hijacker&) const { return true; }
template <typename T>
friend void operator&(T&&) = delete;
template <class T, class U>
friend void operator,(T&&, U&&) = delete;
template <class T, class U>
friend void operator&&(T&&, U&&) = delete;
template <class T, class U>
friend void operator||(T&&, U&&) = delete;
};
template <>
struct std::hash<operator_hijacker> {
size_t operator()(const operator_hijacker&) const { return 0; }
};
#endif // SUPPORT_OPERATOR_HIJACKER_H