RE: [boost] Re: static sized strings

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

Reece Dunn wrote:
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:
OK, thanks. First bug reports: 1. Compile problems under VC++ 6: No include brings in "std::size_t". 2. VC++ 6.x complains about references to a zero-sized array for template< std::size_t m > inline void copy( const char( & s )[ m ] ) { copy( s, m ); } This may be a VC++ 6.x issue, but if it's possible to keep VC++ 6 happy, it's worth doing. There's a big installed base. 3. "copy" function does not place a trailing null in the string. inline void copy( const char * s ) { copy( s, ::strlen( s )); } Note that "strlen" returns a count that does NOT contain the null. All the operations should guarantee that the string remains null terminated. A constructor should be provided, but all it has to do is put a null in the first character position. As for the naming issue, the important thing for retrofit work is that it should be possible to write a "using" statement that makes "strcopy", "sprintf", for char_string etc. valid without prefixes, and doesn't break anything else. You should be able to include something ("safe_strings.hpp"?) that does as much as possible to fix old code. This is a good start, and not hard to fix. I look forward to the next round. John Nagle

"John Nagle" <nagle@animats.com> wrote in message news:409A856E.3060006@animats.com... | 2. VC++ 6.x complains about references to a zero-sized array for | | template< std::size_t m > | inline void copy( const char( & s )[ m ] ) | { | copy( s, m ); | } vc6 is wierd in this regard. I have a workaround for this stuff in collection traits: remove the &. br Thorsten
participants (3)
-
John Nagle
-
Reece Dunn
-
Thorsten Ottosen