Safe Coding Practices – String Handling 2

As with the strcpy() function, covered in last week’s Lesson, you run a risk of buffer overflow with strcat(). The compiler doesn’t check for an overflow; to ensure that you’re practicing safe coding habits, that task is up to you.

The strcat() function sticks one string onto the end of another, a concatenation in geek-speak. You must ensure that enough room is available in the first string’s buffer to handle the length of the second string.

I could show you the bad example first, instead the following code demonstrates one effective way to handle concatenation that ensures the buffers don’t overflow.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char input[32];
    char *result;

    /* get first string */
    printf("Secret code: ");
    fgets(input,32,stdin);

    /* create buffer and copy */
    result = (char *)malloc( strlen(input) + 1);
    if(!result)
    {
        puts("Memory allocation error");
        exit(1);
    }
    strcpy(result,input);

    /* get second string */
    printf("Confirmation: ");
    fgets(input,32,stdin);

    /* append to buffer */
    result = (char *)realloc(result,strlen(result)+strlen(input)+1);
    if(!result)
    {
        puts("Memory allocation error");
        exit(1);
    }
    strcat(result,input);

    printf("Resulting string below\n%s\n",
            result);

    return(0);
}

The first safe coding practice is to use the fgets() function to fetch the string. The size argument in fgets() is identical to the input[] buffer size; fgets() stops input at one less than its size value or whenever a newline ('\n') or EOF is encountered.

At Line 15, the malloc() function allocates enough storage for the string input. Upon success, that location is assigned to the result pointer. The string is then copied from the input buffer to the result buffer at Line 21.

Line 25 uses the input buffer again to fetch the second string. This approach is valid as any new content replaces the existing content in the input buffer; if nothing is input, the buffer holds a single null character ('\0').

At Line 28, the realloc() function attempts to resize the result buffer. The new size is calculated based on the length of the string currently in the result buffer, plus the new string in the input buffer, plus one for a null character. Upon success, the strcat() function (Line 34) appends the string in input to the string in result.

Whether you use malloc() or realloc() any of the other applicable *alloc() functions, the goal is the same: Ensure that the buffer has adequate storage to handle all characters in the final string. That way, you don’t risk a buffer overflow when using the strcat() function. You must, however, use a buffer to collect input, which is the input[] array in this example.

If you’re dealing with string constants in your code, or you know the maximum allowed storage for a string, you can use static buffer sizes that provide plenty of wiggle room. That’s okay, assuming that you monitor the strings’ lengths diligently, but if you’re truly after safe coding practices, allocate the storage as the program runs.
Next week’s Lesson covers a third aspect of string booboos, which are manually-created strings that lack a termination character.

Leave a Reply