secure_allocator_t is nonconforming
(Most of this is copy and paste from an email thread with @BillyONeal)
secure_allocator_t is nonconforming - it doesn't rebind back to the same type.
That is, secure_allocator_t<U>::template rebind<T>::template rebind<U> isn't secure_allocator_t<U>, it is std::allocator<U>.
Example code:
#include <memory>
#include <vector>
template <typename T>
struct secure_allocator_t : std::allocator<T> {};
std::vector<uint8_t, secure_allocator_t<uint8_t> > vec(42);
Failure (observe the _DEBUG):
clang-cl -c -std:c++20 -D_DEBUG a.cpp
In file included from a.cpp:2:
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\include\vector(2125,27): error: no matching conversion for static_cast from
'std::vector<unsigned char, secure_allocator_t<unsigned char>>::_Alty' (aka 'secure_allocator_t<unsigned char>') to '_Rebind_alloc_t<std::vector<unsigned char,
secure_allocator_t<unsigned char>>::_Alty, std::_Container_proxy>' (aka 'secure_allocator_t<std::_Container_proxy>')
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Al);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\include\xmemory(1353,42): note: expanded from macro '_GET_PROXY_ALLOCATOR'
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\include\vector(683,9): note: in instantiation of function template specialization
'std::vector<unsigned char, secure_allocator_t<unsigned char>>::_Construct_n<>' requested here
_Construct_n(_Count);
^
a.cpp(7,52): note: in instantiation of member function 'std::vector<unsigned char, secure_allocator_t<unsigned char>>::vector' requested here
std::vector<uint8_t, secure_allocator_t<uint8_t> > vec(42);
^
a.cpp(5,8): note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'secure_allocator_t<unsigned char>' to
'const secure_allocator_t<std::_Container_proxy>' for 1st argument
struct secure_allocator_t : std::allocator<T> {};
^
a.cpp(5,8): note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'secure_allocator_t<unsigned char>' to
'secure_allocator_t<std::_Container_proxy>' for 1st argument
a.cpp(5,8): note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
In file included from a.cpp:2:
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\include\vector(832,27): error: no matching conversion for static_cast from
'std::vector<unsigned char, secure_allocator_t<unsigned char>>::_Alty' (aka 'secure_allocator_t<unsigned char>') to '_Rebind_alloc_t<std::vector<unsigned char,
secure_allocator_t<unsigned char>>::_Alty, std::_Container_proxy>' (aka 'secure_allocator_t<std::_Container_proxy>')
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\include\xmemory(1353,42): note: expanded from macro '_GET_PROXY_ALLOCATOR'
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp(7,52): note: in instantiation of member function 'std::vector<unsigned char, secure_allocator_t<unsigned char>>::~vector' requested here
std::vector<uint8_t, secure_allocator_t<uint8_t> > vec(42);
^
a.cpp(5,8): note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'secure_allocator_t<unsigned char>' to
'const secure_allocator_t<std::_Container_proxy>' for 1st argument
struct secure_allocator_t : std::allocator<T> {};
^
a.cpp(5,8): note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'secure_allocator_t<unsigned char>' to
'secure_allocator_t<std::_Container_proxy>' for 1st argument
a.cpp(5,8): note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
2 errors generated.
Rebinding back to the same type results in a compatible allocator is a runtime requirement.
Consider std::list<T, std::allocator<T>>. List doesn't allocate Ts, it allocates list_node<T>s. Rebind is the mechanism the library uses to get from an allocator for T to an allocator for something other than T.
The library is going to secure_allocator_t<T> and saying "give me the allocator for _Container_proxy", and secure_allocator_t is saying "std::allocator<_Container_proxy>". But secure_allocator_t<T> isn't convertible to std::allocator<_Container_proxy>, hence the error.
The right fix for libmzq is to either change:
template <typename T> struct secure_allocator_t : std::allocator<T>
{
};
into
template <typename T> using secure_allocator_t = std::allocator<T>;,
or change the behavior of ZMQ_USE_LIBSODIUM to apply inside the body of allocate and deallocate instead of changing the definition of the type entirely.
Fixed in #4480?