user1424739
user1424739

Reputation: 13755

The correct way to use `strcat()` when the destination does not have enough space?

man strcat says the following.

char *strcat(char *restrict s1, const char *restrict s2);

The string s1 must have sufficient space to hold the result.

What is the correct way to handle the situation when s1 does not have enough space?

Upvotes: 2

Views: 2042

Answers (4)

Kaz
Kaz

Reputation: 58627

If the destination buffer already holds a string of length M, and you want to add to it another string of length N, then that buffer has to be at least M + N + 1 bytes wide. If it is smaller, then you just cannot do this; it is impossible to add that material to the existing string. If you put the material there anyway, it will overrun the buffer, whereupon we are into undefined behavior.

If adding those strings is a requirement for your program, then you have to take a step back and re-think the program's text manipulation and buffer strategy, or at least adjust some constants in the program to make things bigger. Maybe it's acceptable for the program to have certain maximum limits and terminate with a diagnostic message if they are exceeded. Or maybe it has to be rewritten to avoid limits (or at least very small, stringent limits), by using dynamic memory allocation.

Some things are impossible. If you ask the helpful clerk at the hardware store about how you can put a 1/4" diameter nut onto a 3/4" diameter bolt, he will probably tell you that it can't be done. This is the programming analog of that.

Upvotes: 0

chux
chux

Reputation: 154218

strcat(s1, s2); can lead to overflow so the precaution "The string s1 must have sufficient space to hold the result." is warranted.

Assume s1 can hold N characters: N-1 non-'\0' + the null character.

The correct way to use strcat() when the destination does not have enough space?

When the concatenation may overflow, I see no application to use strcat(). Instead use other functions.


To detect potential overflow:

  1. Test strlen(s1), strlen(s2) prior to the call.

    size_t l1 = strlen(s1);
    assert(l1 < N); // This really should be true already.
    N -= l1;
    size_t l2 = strlen(s2);
    if (l1 >= N) Handle_TooBigSomehow();
    strcpy(s1 + l1, s2);
    
  2. Use strncat(char * restrict s1, const char * restrict s2, size_t n)

Note that n here is not N: the size available to s1.

The strncat function appends not more than n characters (a null character and characters that follow it are not appended) from the array pointed to by s2 to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. A terminating null character is always appended to the result. C11 §7.23.3.2 2

    size_t l1 = strlen(s1);
    assert(l1 < N); // This really should be true already.
    strncat(s1, s2, N - 1 - l1);
    // or faster
    strncat(s1 + l1, s2, N - 1 - l1);

Unfortunately there is no clear indication that there was insufficient space, yet at least there is no overflow and s1 is null character terminated.

Upvotes: 0

risbo
risbo

Reputation: 188

It is responsibility of programmer to know size of s1. If you don't have enough space you can call realloc(s1,num_of_bytes) to allocate more space.

Upvotes: -1

Govind Parmar
Govind Parmar

Reputation: 21572

If s1 does not contain sufficient space to hold strlen(s1) + strlen(s2) + 1, trying to use strcat(s1, s2) has undefined behavior.

There's no internal checking in strcat for a buffer overflow of s1. If you overflow, you overflow. However, there are some platform-specific alternatives which if used correctly can reduce the risk of overflow. As a Windows developer I prefer StringCchCat and StringCbCat in <strsafe.h>.

If you want to guarantee safety for strcat, you can wrap it yourself. Something like:

int safe_strcat(char *s1, char *s2, size_t s1_size)
{
    if (strlen(s1) + strlen(s2) + 1 > s1_size)
    {
        return 0;
    }
    strcat(s1, s2);
    return 1;
}

Upvotes: 1

Related Questions