Solutions for Developers, Services for Companies, Software for Users
 



bottrap link

A blog is now available Here.

Interested in becoming an Affiliate and earning 25% of all generated sales?  Click Here.

Handmade Art and
Treasures!

Handmade Art and Treasures: Fannys Follies

25% off for first-time customers at VistaPrint!

 

  

Using the n-Versions of the String Manipulation Functions

By James R. Twine (Copyright 2003, James R. Twine)

[Previous Article In Segment] [Next Article In Segment]

I am sure you are all familiar with the strcpy(...), strcmp(...), strcat(...), and sprintf(...) functions used to manipulate strings and string buffers.  But are you aware that those functions have "length-specified" counterparts that are designed to help you eliminate the potential for buffer overruns and underruns?

Take a look at the following code (note that it uses MFC):

void CSomeDlg::OnClickShowHello( void )
{
    const DWORD    HELLO_BUF_SIZE = 128;
    CString        sName;
    char           caBuffer[ HELLO_BUF_SIZE ];

    m_editName.GetWindowText( sName );                // Get Name From Edit Control
    sprintf( caBuffer, "Hello, %s!", (LPCSTR)sName ); // Build "Hello" String
    MessageBox( caBuffer );                           // Show Hello Message

    return;                                           // Done!
}

The code looks innocent enough, and you might think that the size of the caBuffer buffer would be "more than large enough" for any name with "Hello" in front of it.  However, this is the kind of assumption that leads to buffer attacks: if there is potential way to screw something up, someone will figure out how to do it.

The problem is two-fold.  First, the CString object used to obtain the text from the edit control does not have any length restrictions imposed upon it and will happily accept 1KB (or more) of text from the edit control.  Secondly, the sprintf(...) function does not know about the size of the target buffer, so it will happily copy as much text as it the CString object contains.

A small aside... There is an all-too-common belief that hard-coded limits are inherently bad.  I disagree: I believe that hard-coded limits are what can help prevent buffer overruns.  They are like gotos; used incorrectly they are no good at all, but used correctly, they can help.

The next version of the function addresses some of the limitations of the earlier one.

void CSomeDlg::OnClickShowHello( void )
{
    const DWORD    HELLO_BUF_SIZE = 128;
    const DWORD    NAME_BUF_SIZE = 64;
    char           caBuffer[ HELLO_BUF_SIZE ];
    char           caName[ NAME_BUF_SIZE ];

    m_editName.GetWindowText( caName, NAME_BUF_SIZE ); // Get Name From Edit Control
    snprintf( caBuffer, HELLO_BUF_SIZE,
            "Hello, %s!", caName );                    // Build "Hello" String
    MessageBox( caBuffer );                            // Show Hello Message

    return;                                            // Done!
}

This version of the function will not overrun the caBuffer buffer, regardless of the lengths of its parameters.  The sntprintf(...) function takes a parameter that specified the maximum number of characters to write into the buffer; in this case 128 characters.  We have also imposed a "sane" limit on the name read in from the edit control.

There is a subtle flaw in the above function that is covered in the next article, Using Size-Plus-One buffer sizing.  If the data passed to the sntprintf(...) function is large enough, caBuffer buffer will not be NUL terminated correctly; the sntprintf(...) function will not terminate the buffer if its length is reached while building the output into it.  In other words, we have fixed one problem, but caused another potential issue because we are not using the sntprintf(...) function and/or its buffer correctly.

[Previous Article In Segment] [Next Article In Segment]

The contents of this web site are Copyright ©1998-2006 by JRTwine Software, LLC. All Rights Reserved. 
Legal and Copyright Information.
bottrap link