4

I have a strange situation here. I am trying to use the Botan crypto library with VS2015 (because some other parts of the project use some heavy C++11 code which VS2013 is unable to compile) and I get a pretty long compilation error (see below).

After trying out various things, I came to the conclusion, that even if one of the botan headers is included in the compiled c++ source file, the compiler will throw the error below. Right now I have a single line in the file:

#include <botan/botan.h>

and this is the error I get:

    C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(876): error C2664: 'Botan::secure_allocator<_Newfirst>::secure_allocator(const Botan::secure_allocator<_Newfirst> &)': cannot convert
argument 1 from 'std::_Wrap_alloc<Botan::secure_allocator<Botan::byte>>' to 'const Botan::secure_allocator<_Newfirst> &'
        with
        [
            _Newfirst=std::_Container_proxy
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(876): note: Reason: cannot convert from 'std::_Wrap_alloc<Botan::secure_allocator<Botan::byte>>' to 'const Botan::secure_allocator<_Ne
wfirst>'
        with
        [
            _Newfirst=std::_Container_proxy
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(876): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(587): note: see reference to function template instantiation 'std::_Wrap_alloc<Botan::secure_allocator<_Newfirst>>::_Wrap_alloc<std::_Wr
ap_alloc<Botan::secure_allocator<Botan::byte>>>(_Other &) noexcept' being compiled
        with
        [
            _Newfirst=std::_Container_proxy,
            _Other=std::_Wrap_alloc<Botan::secure_allocator<Botan::byte>>
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(587): note: see reference to function template instantiation 'std::_Wrap_alloc<Botan::secure_allocator<_Newfirst>>::_Wrap_alloc<std::_Wr
ap_alloc<Botan::secure_allocator<Botan::byte>>>(_Other &) noexcept' being compiled
        with
        [
            _Newfirst=std::_Container_proxy,
            _Other=std::_Wrap_alloc<Botan::secure_allocator<Botan::byte>>
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(585): note: while compiling class template member function 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)
'
        with
        [
            _Ty=Botan::byte,
            _Alloc=Botan::secure_allocator<Botan::byte>
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(552): note: see reference to function template instantiation 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(voi
d)' being compiled
        with
        [
            _Ty=Botan::byte,
            _Alloc=Botan::secure_allocator<Botan::byte>
        ]
C:\Program Files\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(679): note: see reference to class template instantiation 'std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>' being compiled
        with
        [
            _Ty=Botan::byte,
            _Alloc=Botan::secure_allocator<Botan::byte>
        ]
c:\Botan\include\botan-1.11\botan/rng.h(43): note: see reference to class template instantiation 'std::vector<Botan::byte,Botan::secure_allocator<Botan::byte>>' being compiled
NMAKE : fatal error U1077: 'C:\PROGRA~1\MICROS~3.0\VC\bin\cl.exe' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 14.0\VC\BIN\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 14.0\VC\BIN\nmake.exe"' : return code '0x2'
Stop.

Since I was able to compile and run the botan tests, I have the feeling that I missed something, but I have no idea what. Does anyone has any experience with this? (BTW: The same code compiles nicely with g++ 4.9)

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • `std::_Wrap_alloc>' to 'const Botan::secure_allocator<_Newfirst> &'`: maybe the passed `std::_Wrap_alloc` object requires some inderection like `operator *` to get a `Botan::secure_allocator` object that is probably convertable to `Botan::secure_allocator<_Newfirst>`? – Aleksey F. Aug 04 '15 at 08:03
  • 1
    Maybe a missing include (to allow conversion of `Botan::secure_allocator`) ? – Jarod42 Aug 04 '15 at 09:29
  • I've added another possible workaround to the answer. – bogdan Aug 04 '15 at 20:22
  • Botan has never been tested with VS 2015, so it is not unlikely that it is an issue in the library. Thanks for bringing this up. – Simon Warta Aug 05 '15 at 10:34
  • Botan 1.11.20 released yesterday fixes the issue. Thanks again @bogdan! – Simon Warta Sep 08 '15 at 10:40

1 Answers1

6

Looking at the sources, it seems that Botan::secure_allocator doesn't provide a template constructor of the form

template<class U> secure_allocator(const secure_allocator<U>& other);

This is required by the Standard. In the current working draft, N4527, the relevant bits are in [17.6.3.5] Table 28 - Allocator requirements; also useful is the example in paragraph 9.

So, we can't blame the standard library implementation that comes with VC 14 for requiring this in order to compile. The error is on Botan's side in my opinion.


A quick fix is to add such a definition to Botan::secure_allocator:

template<class U> secure_allocator(const secure_allocator<U>&) BOTAN_NOEXCEPT { }

Since instantiations of this allocator template don't have any non-static data members, an empty body should be fine. However, I'm not familiar with the library, and we're talking about cryptography here, so, before using this to do any serious stuff, please confirm the change with the library authors.


Another possible workaround:

I've noticed that the code that calls the mixed-type constructor seems to only be enabled when iterator debugging is enabled, which happens by default in Debug mode.

Have you tried compiling in release mode? If my observations are correct, you won't get this error anymore, since the additional machinery for iterator debugging will be disabled.

To get the same behaviour in Debug mode, set the _ITERATOR_DEBUG_LEVEL macro to 0 globally.

Debug iterators can be useful to detect errors (as long as the performance hit doesn't affect you), so I wouldn't use this as a permanent fix, but it could be useful as a temporary workaround if you don't want to modify the Botan header file.

This could also explain why you were able to compile the tests: maybe they're compiled in release mode, or, anyway, with a combination of settings that disables iterator debugging?

bogdan
  • 9,229
  • 2
  • 33
  • 48
  • Do I get you right, that you are suggesting to add an explicit copy constructor? That would explain the error because other compilers do that implicitly. – Simon Warta Aug 05 '15 at 10:36
  • @SimonWarta That's not a copy constructor. Copy constructors cannot be template specializations, and their first parameter needs to be an lvalue reference to the type being constructed (the one I described can take any other specialization of the `secure_allocator` template). As far as I know, VC 14 does everything right when it comes to implicitly generating special member functions, so that's not the problem. The different behaviour seems to be caused by iterator debugging in VC14's STL, but that still doesn't make that allocator standard-compliant - that template constructor is required. – bogdan Aug 05 '15 at 11:36
  • Could you add your change along with the background information as a pull request to Botan please? There we can get feedback from some other developers. I am not an expert when it comes to templates. – Simon Warta Aug 05 '15 at 11:39
  • @SimonWarta I feel a bit uneasy about doing that, because I don't have the library configured on my machine, so I can't actually test any change. All of this is just me looking at the code. It's true that the general statement "that constructor should be there anyway" still stands, but it would be great if we could have confirmation for the two workarounds first, so that we know what's affected and what we're fixing. – bogdan Aug 05 '15 at 12:04
  • As one of the Botan developers I can ensure you that this some high quality work which will be very much appreciated within the Botan community that always struggles with non-gnu-linux platforms due to the lack of test machines. Every Botan pull request is automatically tested on Linux, OS X and MSVC 2013 in a CI system. You could just place it there as a pull request and ask others to reproduce and confirm your fix before merging. Of course, confirmation for the workarounds makes sense anyways. But you can get this in the Botan community as well. I could setup a VM for that. – Simon Warta Aug 05 '15 at 12:18
  • @SimonWarta Got it. I'll send a pull request and we'll go from there. – bogdan Aug 05 '15 at 12:49
  • Has that pull request already been merged or is it somewhere online so I could try it? I am facing exactly the same problem right now. – j00hi Sep 22 '15 at 15:25
  • 2
    @j00hi According to Simon Warta's [comment above](http://stackoverflow.com/questions/31802806/botan-compile-error-vs2015/31805705?noredirect=1#comment52773233_31802806), version 1.11.20 includes the fix. If you need to work with an older version and want to apply the change manually, the diff is [here](https://github.com/randombit/botan/pull/236/files). – bogdan Sep 22 '15 at 16:44