
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