libzmq icon indicating copy to clipboard operation
libzmq copied to clipboard

secure_allocator_t is nonconforming

Open tiagomacarios opened this issue 3 years ago • 2 comments

(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.

tiagomacarios avatar Nov 17 '22 20:11 tiagomacarios

Fixed in #4480?

rotu avatar Jun 12 '24 20:06 rotu