C strcat, strcpy and armageddon, part 6

See also: part 1part 2part 3part 4 and part 5.

Updates:

  • 3/3/2016 – Updated note about the problem with strlen(), referencing the discussion in part 5, and the solution in the summary.

And now, a simple one-page summary of how to make copying/appending C strings safer and hopefully avoid potential buffer overrun crashes (or other problems).

Copying Strings

Instead of using strcpy(), which does absolutely no checking to see if it’s copying more data than the destination buffer can hold, use strncpy() to limit how much can be copied. If the max amount is copied, strncpy() will not null terminate the destination, so you need to do that yourself.

#define BUFSIZE 30 // size of desination buffer

char buffer[BUFSIZE] = { 0 }; // Initialize buffer with zeros.
char *longString = "Copy this long string to the buffer.";
char *shortString = "Short string.";

// Instead of strcpy(buffer, shortString), do this:
// Copy up to max buffer size-1 (leaving room for a null).
// In case of max-sized string, make sure to null terminate. 
strncpy( buffer, shortString, BUFSIZE-1 );
buffer[BUFSIZE-1] = '\0';

printf( "Buffer: '%s'\n", buffer );

// Instead of strcpy(buffer, longString), do this:

// Copy up to max buffer size-1 (leaving room for a null).
// In case of max-sized string, make sure to null terminate. 
strncpy( buffer, longString, BUFSIZE-1 );
buffer[BUFSIZE-1] = '\0';

printf( "Buffer: '%s'\n", buffer );

That should produce the following output:

Buffer: 'Short string.'
Buffer: 'Copy this long string to the '

Appending Strings

Instead of using strcat() to append a string to an existing string buffer, use strncat() and some math to not copy more than the buffer can hold (counting how many characters are already in it). NOTE: As mentioned in part 5, the use of strlen() is still a point of failure so this is actually NOT a reliable fix.

#define BUFSIZE 30 // size of destination buffer

char buffer[BUFSIZE] = { 0 }; // Initialize buffer with zeros.
char *string1 = "Buffer start.";
char *string2 = "This is what we will be appending.";

printf( "Initial buffer  : '%s'\n", buffer );

// Let's put something in the buffer to demonstrate.
// In case of max-sized string, make sure to null terminate. 
strncpy( buffer, string1, BUFSIZE-1 );
buffer[BUFSIZE-1] = '\0';

printf( "Copied buffer   : '%s'\n", buffer );

// Instead of strcat(buffer, string2), do this:

// Let's "safely" append something to the buffer.
strncat( buffer, string2, BUFSIZE-strlen(buffer)-1 );
// NOTE: strlen() can cause a failure if the original buffer
// was already bad with too much data. We need an strnlen()
// but no such function exists in ANSI-C. See the followup
// article for a "roll your own" set of functions to solve this.
//strncat( buffer, string2, BUFSIZE-strnlen(buffer, BUFSIZE)-1);

printf( "Appended buffer: '%s'\n", buffer );

This should produce the following output:

Initial buffer : ''
Copied buffer : 'Buffer start.'
Appended buffer: 'Buffer start.This is what we '

Comparing Strings

And, instead of using strcmp() to compare strings, use strncmp() so you can set the maximum string size expected.

#define FIRSTNAME_SIZE 20

char firstName[FIRSTNAME_SIZE] = {0}; // Initialize with zeros.

...

// Instead of strcmp(buffer, firstname), do this:

if (strncmp( buffer, firstName, FIRSTNAME_SIZE ) == 0)
{
  ...

Follow these three simple steps and you will greatly reduce your chance of a buffer overrun that could cause unexpected problems.

Look for an upcoming article that will expand on this with replacement functions you can use to make things easier and more efficient.

Leave a Reply