Search code examples
cglibcoverlapstrcat

Problem of overlap verification between two strings


I am currently recoding srtcat() from the standard C library and I have set up some checks to avoid overlap problems. The problem is that my program still enters the error handling.

Here is the code:

char *my_strcat(char *restrict dest, const char *restrict src)
{
    size_t dest_len = 0, src_len = 0;
    char *p = dest;
    src_len = my_strlen(src);
    if (!dest || !src)
        return NULL;
    dest_len = my_strlen(dest);
    if (src >= dest && src < dest + dest_len) {
        return NULL;
    }
    if (dest >= src && dest < src + src_len) {
        return NULL;
    }
    while (*p != '\0') p++, dest_len++;
    if (dest_len + src_len + 1 > sizeof(dest))
        return NULL;
    p = dest + dest_len;
    while (*src != '\0')
        *p++ = *src++;
    *p = '\0';
    return dest;
}
size_t my_strlen(const char *s)
{
    size_t count = 0;
    if (s != NULL) {
        while (*s != 0) {
            count++;
            s++;
        }
    }
    return count;
}

I tested this way :

int main(int argc, char **argv)
{
    const char *src = "Hello";
    char dest[100] = " world!";
    char *test = my_strcat(dest, src);
    printf("Src : %s Dest : %s\n", src, dest);
    printf("Return adress : %p, Value : %s\n", test, test);
    return 0;
}

According to gdb :

if (src >= dest && src < dest + dest_len) 
1: dest = 0x7fffffffda70 " world!"
2: src = 0x555555557004 "Hello"
3: dest_len = 0
4: src_len = 5

Output

Src : Hello Dest :  world!
Return adress : (nil), Value : (null)

Do you see the problem?

Update

Following your suggestions I have modified the code like this:

char *my_strcat(char *restrict dest, const char *restrict src, size_t d_size)
{
    size_t dest_len = 0, src_len = 0;
    char *p = dest;
    if (!dest || !src)
        return NULL;
    src_len = my_strlen(src);
    dest_len = my_strlen(dest);
    if (src >= dest && src < dest + dest_len) {
        return NULL;
    }
    if (dest >= src && dest < src + src_len) {
        return NULL;
    }
    while (*p != '\0') p++, dest_len++;
    if (dest_len + src_len + 1 > d_size)
        return NULL;
    p = dest + dest_len;
    while (*src != '\0')
        *p++ = *src++;
    *p = '\0';
    return dest;
}

And in the main : char *test = my_strcat(dest, src, sizeof(dest));

But it still doesn't work :

Src : Hello Dest :  world!
Return adress : 0x7fff74bc5650, Value :  world!

Solution

  • Having tried to guide toward understanding this problem, it seems best to present what should be working code (for study.) Sometimes too many words merely muddle the situation:

    char *my_strcat(char *restrict dest, const char *restrict src, size_t d_size) {
        if( !dest || !src )
            return NULL;
    
        size_t src_len = strlen( src );
        size_t dest_len = strlen( dest );
    
        if( dest_len + src_len + 1 > d_size )
            return NULL;
    
        char *p = dest + dest_len;
        while( (*p++ = *src++ ) != '\0' )
            ;
    
        return dest;
    }
    
    int main() {
        const char *src = "Hello";
        char dest[100] = " world!";
        printf("Src : %s Dest : %s\n", src, dest);
    
        char *test = my_strcat( dest, src, sizeof dest );
    
        if( test )
            printf("Value : %s\n", test );
    
        return 0;
    }
    

    Now, one can experiment by shrinking the size of dest to something larger than " world!" but smaller than " world!Hello"... Perhaps 9 bytes???

    And, now that the concatenation should be working (into a big enough buffer), adding the code to ensure there is no overlap of the actual character arrays. Known is the size of dest, and the length of src is measured.