Home > Enterprise >  Running strncat on MacOS 11.6.1
Running strncat on MacOS 11.6.1

Time:11-06

I am on MacOS 11.6.1 and want to append a character to a string and copied the following from there: https://www.geeksforgeeks.org/how-to-append-a-character-to-a-string-in-c/

I am supposed to have the following ouptut:

Original String: Geek
Character to be appended: s
Appended String: Geeks

but only got the following one (with the last line missing)

Original String: Geek
Character to be appended: s

What am I doing wrong?

Here is the code

// C program to Append a Character to a String

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

int main()
{
    // declare and initialize string
    char str[6] = "Geek";

    // declare and initialize char
    char ch = 's';

    // print string
    printf("Original String: %s\n", str);
    printf("Character to be appended: %c\n", ch);

    // append ch to str
    strncat(str, &ch, 1);

    // print string
    printf("Appended String: %s\n", str);

    return 0;
}

CodePudding user response:

This is a bug in strncat, specifically in the __builtin___strn_chk routine used to implement it. Consider this extract of the code in the question:

char str[6] = "Geek";
char ch = 's';
strncat(str, &ch, 1);

As it happens, the compiler puts ch immediately before str in memory. Examining the assembly output of compilation shows strncat is implemented with a call to __builtin___strn_chk. Stepping through __builtin___strn_chk in a debugger shows it calls __chk_overlap to check whether the source and destination buffers overlap. For this call, it passes the address of str with a length of six (the four characters in it plus the new character to be concatenated and a terminating null character after that) and the address of ch with a length of two.

This length of two is incorrect; strncat or __builtin___strn_chk should take only one character from ch. This is a mistake in __builtin___strn_chk; it should pass a length of 1, not 2. __chk_overlap correctly determines the buffers it was passed overlap and generates a trap.

This can be reliably reproduced with:

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


int main(void)
{
    char buffer[] = "xabc\0\0";
    strncat(buffer 1, buffer, 1);
}

__builtin___strncat_chk is used because <string.h> includes a header secure/_string.h which defines strncat as a macro:

#define strncat(dest, ...) \
        __builtin___strncat_chk (dest, __VA_ARGS__, __darwin_obsz (dest))

So we can work around the bug by replacing strncat with (strncat), which forces the strncat function to be used instead of the macro. One could also use #undef strncat after including <string.h>.

CodePudding user response:

Ok, following the comment of Some programmer dude and Eric Postpischil and using strcpy() instead of strncat I could solve the problem:

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

int main()
{

    char str[6] = "Geek";
    char ch = 's';

    size_t lenstr = strlen(str);
    char *str2 = malloc(lenstr   1   1);
    
    strcpy(str2, str);
    str2[lenstr] = ch;
    str2[lenstr   1] = '\0';

    printf("Original String: %s\n", str);
    printf("Character to be appended: %c\n", ch);

    printf("Appended String: %s\n", str2);

    return 0;
}


  • Related