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 output:
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;
}
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>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With