14

It seems to be the month of C++ templates for me...

I have a SecureString. SecureString looks just like a std::string, except it uses a custom allocator which zeroizes on destruction:

class SecureString
{
public:
  typedef std::basic_string< char, std::char_traits<char>, zallocator<char> > SecureStringBase;
  typedef zallocator<char>::size_type size_type;
  static const size_type npos = static_cast<size_type>(-1);
  ....
private:
  SecureStringBase m_base;
};

The full code for SecureString can be found at http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/esapi/util/SecureString.h; and the code for the allocator can be found at http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/esapi/util/zAllocator.h.

Currently, we have a swap defined that takes a std::string as an argument:

void SecureString::swap(std::string& str)
{
  SecureStringBase temp(str.data(), str.size());
  m_base.swap(temp);
  str = std::string(temp.data(), temp.size());
}

I feel like I'm missing an opportunity in swap because the underlying types only differ by allocators. Can anyone see a way to avoid the temporary? Is it possible to use rebind to make this run faster?

EDIT: SecureString::swap(std::string& str) is now gone. Reference to the function in this thread has been left in place for posterity.

Jeff

jww
  • 97,681
  • 90
  • 411
  • 885
  • 4
    Why swap a std::string with a SecureString? Why not only provide swap for SecureString with SecureString? – dalle Sep 05 '11 at 06:22
  • @dalle: we are trying to make it easy on users. – jww Sep 05 '11 at 07:16
  • 3
    If there's any benefit in using SecureString, then swapping a string with a SecureString sounds like a very unsafe operation to me. If the point of SecureString is to clear the memory before freeing, and you swap its contents into a regular string, then they won't be cleared before freeing, so whatever bad thing it is that might happen, you've let it. Surely data should be easy to transfer from a string to a SecureString, but getting it back out should go through some function that's easy to identify and audit for data safety. – Steve Jessop Sep 05 '11 at 10:53
  • @Steve: you're right. I was thinking along the lines of swapping a std::string in, not a SecureString out. Kevin probably would have caught it on audit. – jww Sep 05 '11 at 11:19

1 Answers1

9

Unfortunately... no.

This is not what rebind is for. rebind is used because an allocator is meant to allocate objects of one type, and one type only (std::allocator<T>) in the STL.

However, there is a trick. When you instantiate std::list<T, std::allocator<T>> for example, then the allocator does not have to allocate Ts, it has to allocate some internal structure instead like __list_node<T>, and that is when rebind is put to use, it creates a new allocator, sibling of the precedent (they differ only by the template parameter and likely share the same memory pool under the covers).

In your case however, your allocator and the std::string allocator are different, and thus they cannot exchange memory. So you have to do a copy.

You can optimize the void swap(SecureString&, SecureString&) operation, but not this one.

One question: why not typedef std::string<char, SecureAllocator<char>> SecureString; ?

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thanks - I was afraid of that. As for the typedef, it was originally a typedef. However, we wanted to consume std::strings to ease use for users. I could not figure out how to overload copy and assignment (et al) to take the std::string using only a typedef. – jww Sep 05 '11 at 07:15
  • 1
    @noloader: it's not possible, indeed. Direct interaction with `std::string` will effectively necessitate a custom class. I am not sure of providing this `swap` though. – Matthieu M. Sep 05 '11 at 07:21