Boost logo

Boost :

From: Reece Dunn (msclrhd_at_[hidden])
Date: 2004-05-06 07:41:10


John Nagle wrote:
>Reece Dunn wrote:
>>There is currently a static-sized array in the Boost library that allows
>>you to operate on arrays of fixed size. I was wondering if something
>>similar exists for strings, in particular, providing buffer-overflow safe
>>string operations.
>>
>>I have an nstring< std::size_t n > string class that provides size-safe
>>copying and comparison, allowing for you to do things like:
>
> That's an excellent direction in which to be moving.
>
> How far can we go in replacing unsafe C strings? With
>the endless reports of buffer overflow exploits, anything
>that can be done in that direction would help.

This was the motivation for designing the class: to allow safe string
operations with a clean, easy-to-use interface. I have attached the source
below. Note that this is still a work-in-progress and as such is not yet
complete.

> I'd suggest a class with the following properties:
>
> Fixed-allocated strings, with length information.
> No calls to "new".

Typical usage would be something like:
   boost::char_string< 15 > str;
   str.copy( "Hello World!" );
NOTE: there is not yet an operator=.

The formatterex class is to support sprintf-like operations and can be used
like this:
   error_message( boost::formatterex< 1024 >( "[%s]: %s", severity, msg ));

> Supports most of the operations allowed for STL strings.

Good idea - this will help shifting between both classes.

> Also supports the "classic" C string operations, like
> "sprintf", "strlen", etc., using the classic C syntax for them.

Also a good idea. But where should these reside? In the global namespace,
std namespace or boost namespace?

> Implicit conversion to "const char*", but not "char *", for
> compatibility with existing library calls.

Done.

> Fully protected against overflow.

I hope that this is the case, although if any bugs are spotted, I'd
appreciate feedback so I can fix them. Note that the const char ( & )[ m ]
versions are to support string literals.

> It might also be worthwhile to provide "sprintf", "strlen", etc.
>for STL strings.

This is where things get tricky. Where do we place these overloads? Like
with the others (char_string) there is the question of how to be compatible
with the existing std+global namespace versions. Note that this is
complicated by the fact that the functions exist in the global namespace and
are using-imported into the std namespace in (all?) existing
implementations.

I would suggest having something like a boost::string namespace, where these
overloads (plus wchar_t overloads) of strlen, etc are placed. It may be that
the implementations need to be placed directly in the global namespace, but
I don't know what impact that would have.

> The basic idea is that this should be retrofittable to old code
>without major efforts. Ideally, you go through the code with
>a program, replacing "char foo[nnn]" with "char_array<nnn> foo",
>and "char *" with "char_array&", and it mostly works. Everything
>that doesn't work gets a compile-time error. You fix all the compile
>time errors, and your program is overflow-proof, at least in
>this area.

On my to-do list for this class is to add wchar_t support and support for a
traits class (char_traits?) as well as completing the implementation. Let me
know what you thing.

Regards,
Reece

=====

// (C) Copyright 2003-2004: Reece H. Dunn

#ifndef BOOST_CHAR_STRING_HPP
#define BOOST_CHAR_STRING_HPP
# include <cstring>

   namespace boost
   {
      template< std::size_t n >
      class char_string
      {
         private:
            char str[ n ];
         public: // access
            inline operator const char *() const
            {
               return( str );
            }
         public:
            inline const char * c_str() const
            {
               return( str );
            }
            inline std::size_t size() const
            {
               return( n );
            }
         public: // copy
            inline void copy( const char * s,
std::size_t l )
            {
               ::strncpy( str, s, ( l > n ) ? n : l );
            }
            inline void copy( const char * s )
            {
               copy( s, ::strlen( s ));
            }
            inline void copy( const char_string< n
> & s )
            {
               ::strncpy( str, s, n );
            }
            template< std::size_t m >
            inline void copy( const char( & s )[ m
] )
            {
               copy( s, m );
            }
         public: // comparison
            inline int comp( const char * s,
std::size_t l ) const
            {
               return( ::strncmp( str, s, ( l > n ) ? n : l ));
            }
            inline int comp( const char * s )
const
            {
               return( comp( s, ::strlen( s )));
            }
            inline int comp( const char_string< n
> & s ) const
            {
               return( ::strncmp( str, s, n ));
            }
            template< std::size_t m >
            inline int comp( const char( & s )[ m
] ) const
            {
               return( comp( s, m ));
            }
         public:
            inline char_string()
            {
               str[ 0 ] = '\0';
            }
      };

      template< std::size_t n >
      bool operator==( const char_string< n > & a, const char_string< n > &
b )
      {
         return( a.comp( b ) == 0 );
      }

      template< std::size_t n, std::size_t m >
      bool operator==( const char_string< n > & a, const char( & b )[ m ] )
      {
         return( a.comp( b ) == 0 );
      }

      template< std::size_t n, std::size_t m >
      bool operator==( const char( & b )[ m ], const char_string< n > & a )
      {
         return( a.comp( b ) == 0 );
      }

      // formatter -- sprintf-like operations

      template< std::size_t n >
      class formatterex: public char_string< n >
      {
         public:
            inline const char * operator()( const char * fs ... ) throw()
            {
               va_list args;
               va_start( args, fs );
               _vsnprintf( *this, n, fs, args );
               va_end( args );
               return( *this );
            }
         public:
            inline formatterex( const char * fs ... ) throw()
            {
               va_list args;
               va_start( args, fs );
               _vsnprintf( *this, n, fs, args );
               va_end( args );
            }
            inline formatterex() throw()
            {
            }
      };

      typedef formatterex< 512 >
formatter;
   }
#endif

_________________________________________________________________
Express yourself with cool emoticons - download MSN Messenger today!
http://www.msn.co.uk/messenger


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk