String buffer overruns?

Discussion in 'C++' started by Nephi Immortal, Feb 27, 2012.

  1. I am curious to ask a question. Poor buffer handling is implicated
    in many security issues that involve buffer overruns. All string
    buffers always include null terminator. What happen if you omit null
    terminator in source buffer?

    const int null_term = 1;
    const int nChars = 11;

    // null terminator is included automatically by C++ Compiler
    char name[ nChars + null_term ] = “Hello World”;

    name[ nChars ] = 0xFF; // omit null terminator

    std::string str( name );

    The valid characters and garbled characters in name are copied into
    str until null terminator is found somewhere. It is possible to
    trigger error message like denied security alert because data is not
    authorized to be read in read-only memory somewhere.

    std::string str( name, nChars ); // is better than string str( name )

    The std::string( char* ) constructor function should be removed from C+
    + Standard Library. Why do C++ Standard Library leave it alone in
    order to have legacy compatibility with C strings?

    The C++ Standard Library recommends to use std::string( char*, size )
    constructor function instead.

    The string class uses dynamic memory allocation. Do C++ Standard
    Library offer fixed string buffers which string buffers are pushed
    into the stack? Of course, fixed string is less flexible unless large
    source buffer does not fit into small destination buffer and extra
    characters are truncated if memory reallocation is not used.
     
    Nephi Immortal, Feb 27, 2012
    #1
    1. Advertising

  2. Nephi Immortal <> wrote:
    > The std::string( char* ) constructor function should be removed from C+
    > + Standard Library. Why do C++ Standard Library leave it alone in
    > order to have legacy compatibility with C strings?


    How many times have I found it useful to do something like this?

    std::string s = "Hello";

    Or something like this?

    foo("Hello"); // foo() takes a const std::string& as parameter

    I'd say about a million times. How many times have I made the mistake of
    initializing a std::string with a non-null-terminated char array? Well,
    that would be approximately zero times.

    I prefer having the huge convenience constructor even at the minuscule
    risk of a bug that has yet to happen to me.
     
    Juha Nieminen, Feb 28, 2012
    #2
    1. Advertising

  3. Nephi Immortal

    Goran Guest

    On Feb 27, 8:06 pm, Nephi Immortal <> wrote:
    >         I am curious to ask a question.  Poor buffer handling is implicated
    > in many security issues that involve buffer overruns.  All string
    > buffers always include null terminator.  What happen if you omit null
    > terminator in source buffer?
    >
    > const int null_term = 1;
    > const int nChars = 11;
    >
    > // null terminator is included automatically by C++ Compiler
    > char name[ nChars + null_term ] = “Hello World”;
    >
    > name[ nChars ] = 0xFF; // omit null terminator
    >
    > std::string str( name );
    >
    >         The valid characters and garbled characters in name are copied into
    > str until null terminator is found somewhere.  It is possible to
    > trigger error message like denied security alert because data is not
    > authorized to be read in read-only memory somewhere.
    >
    > std::string str( name, nChars ); // is better than string str( name )
    >
    > The std::string( char* ) constructor function should be removed from C+
    > + Standard Library.


    I disagree. When done right, things work correctly.

    > Why do C++ Standard Library leave it alone in
    > order to have legacy compatibility with C strings?


    Having good compatibility with C was always important in C++. So "C
    way" of doing strings is supported. I see nothing wrong with that.

    In general, yes, C++ coding can be unsafe. However, there are tools
    that pinpoint errors pretty early in development cycle. I see nothing
    wrong in that approach.

    > The string class uses dynamic memory allocation.  Do C++ Standard
    > Library offer fixed string buffers which string buffers are pushed
    > into the stack?


    AFAIK, no. Implementation is free to use "short string optimization".

    Since you are asking about buffer overruns, careful: in practice,
    overrunning a stack buffer is typically more dangerous than over-
    running a heap one ;-).

    Goran.
     
    Goran, Feb 28, 2012
    #3
  4. Juha Nieminen <> wrote:
    > How many times have I found it useful to do something like this?
    >
    > std::string s = "Hello";
    >
    > Or something like this?
    >
    > foo("Hello"); // foo() takes a const std::string& as parameter


    Or consider the convenience of this:

    int main(int argc, char* argv[])
    {
    std::vector<std::string> parameters(argv+1, argv+argc);
    ...
    }

    What would be your suggestion to make that "safer"?
     
    Juha Nieminen, Feb 28, 2012
    #4
  5. On 27.02.2012 20:06, Nephi Immortal wrote:
    > I am curious to ask a question. Poor buffer handling is implicated
    > in many security issues that involve buffer overruns. All string
    > buffers always include null terminator. What happen if you omit null
    > terminator in source buffer?


    > The std::string( char* ) constructor function should be removed from C+
    > + Standard Library. Why do C++ Standard Library leave it alone in
    > order to have legacy compatibility with C strings?


    First of all there is no std::string( char* ) constructor. There is a
    std::string( const char* ) constructor. And this is an important difference.

    It is quite difficult to get an accidental string buffer overrun bug
    without using char* for strings, because you need to have the
    terminating null removed at the first place. Most compilers will at
    least warn about that.

    Not using char* is mostly sufficient to avoid buffer overruns.
    Of course, with invalid data you might still cause memory allocation
    errors or excessive memory usage. But while this might be enough for a
    DOS attack, it will not help for intrusion attacks.


    > The C++ Standard Library recommends to use std::string( char*, size )
    > constructor function instead.


    This won't help in any way, because to adapt C strings you need to write
    std::string(name, strlen(name)) which shares the same problem, of
    course. Writing
    const char name[] = "Hello World";
    std::string(name, 200);
    is entirely wrong, because now you have again a buffer overrun, but this
    time in the source buffer. All you can do is
    std::string(name, strlen(name, 200));


    > The string class uses dynamic memory allocation. Do C++ Standard
    > Library offer fixed string buffers which string buffers are pushed
    > into the stack? Of course, fixed string is less flexible unless large
    > source buffer does not fit into small destination buffer and extra
    > characters are truncated if memory reallocation is not used.


    Well, going back to COBOL is definitely not what I like.
    How many problems came from too small, fixed string buffers. Long names
    of foreign people do not fit into the fields. Moving an application to
    an active directory is prevented because the user name with domain does
    no longer fit in the fields. An application, originally designed for
    local files, seems to work with URLs too - fine. Unfortunately they are
    truncated. :-(


    Marcel
     
    Marcel Müller, Feb 28, 2012
    #5
  6. Nephi Immortal

    gwowen Guest

    On Feb 27, 7:06 pm, Nephi Immortal <> wrote:

    > // null terminator is included automatically by C++ Compiler
    > char name[ nChars + null_term ] = “Hello World”;


    const char* name = "Hello World"; // no need to count chars...

    > name[ nChars ] = 0xFF; // omit null terminator


    Won't compile! Win!
     
    gwowen, Feb 28, 2012
    #6
  7. On Feb 28, 8:36 am, gwowen <> wrote:
    > On Feb 27, 7:06 pm, Nephi Immortal <> wrote:
    >
    > > // null terminator is included automatically by C++ Compiler
    > > char name[ nChars + null_term ] = “Hello World”;

    >
    > const char* name = "Hello World"; // no need to count chars...
    >
    > > name[ nChars ] = 0xFF; // omit null terminator

    >
    > Won't compile!  Win!


    No way! Will compile sucessfully. You lose!

    I wish to do

    string str = "anything";

    if str does not have sufficient memory, it would be str = "" unless
    exception is removed to replace with assertion.

    if( !str )
    assert(...);
    else
    cout << str << endl;

    You need to implement and add operator!() to string.
     
    Nephi Immortal, Feb 28, 2012
    #7
  8. On Feb 28, 7:38 am, Nephi Immortal <> wrote:

    > > const char* name = "Hello World"; // no need to count chars...

    >
    > > > name[ nChars ] = 0xFF; // omit null terminator

    >
    > > Won't compile!  Win!

    >
    > No way!  Will compile sucessfully.  You lose!


    Er, no:

    1) if you do 'const char * name = "Hello World";'
    then there is no need for 'nChars' variable. Without it, the line
    above indeed won't compile,

    2) even if for some reason you did have such a variable, the line
    still won't compile because it would be attempting to modify the
    character referenced by name[nChars], whose type is *const* char.


    > I wish to do
    >
    > string str = "anything";


    What's stopping you?


    > if str does not have sufficient memory, it would be str = "" unless
    > exception is removed to replace with assertion.


    Not quite. Yes, insufficient memory means that you would have an
    std::bad_alloc exception thrown. But if you catch the exception,
    'str' is not "" ... in fact, you cannot refer to 'str' at all: it is
    not in scope after the catch block, since it must of necessity be
    declared inside a 'try' block in order to be able to catch the
    exception coming from the constructor.

    An alternative which does pretty much what your previously-posted code
    does would be to allocate it with new:

    string * strP = 0;
    try { strP = new string("anything"); }
    catch (const std::bad_alloc &) { assert(...); }

    // you can use a reference for syntactic sugar if you like
    string & str = *strP;
    cout << str << endl;

    // clean-up
    delete strP;


    In C++ 2011 it would be preferable to declare strP as a
    std::unique_ptr<string> of course so no clean-up step was needed.


    - Kevin B. McCarty
     
    Kevin McCarty, Feb 28, 2012
    #8
  9. Nephi Immortal

    gwowen Guest

    On Feb 28, 3:38 pm, Nephi Immortal <> wrote:

    >> size_t nChars = 12;
    >> const char* name = "Hello World"; // no need to count chars...
    >> name[ nChars ] = 0xFF; // omit null terminator
    >> Won't compile!  Win!

    >
    > No way!  Will compile sucessfully.  You lose!


    Your compiler allows you to modify a const object? Your compiler is
    broken.
     
    gwowen, Feb 29, 2012
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Raja
    Replies:
    12
    Views:
    24,438
    John Harrison
    Jun 21, 2004
  2. Replies:
    2
    Views:
    607
    sergejusz
    Mar 26, 2007
  3. Neal Becker

    buffer creates only read-only buffer?

    Neal Becker, Jan 8, 2009, in forum: Python
    Replies:
    0
    Views:
    416
    Neal Becker
    Jan 8, 2009
  4. Casey Hawthorne

    Buffer Overruns other C Gotchas -- "Coders at Work"

    Casey Hawthorne, Nov 3, 2009, in forum: C Programming
    Replies:
    45
    Views:
    893
    Seebs
    Nov 5, 2009
  5. Nephi Immortal

    Possible buffer overruns?

    Nephi Immortal, Apr 28, 2012, in forum: C++
    Replies:
    3
    Views:
    501
    Juha Nieminen
    Apr 29, 2012
Loading...

Share This Page