Timothy Vann Timothy Vann - 5 days ago 7
Linux Question

c snprintf used to concat string

I'm using the following function on two different computers. One one computer is running Ubuntu and the other OS X. The function works on OS X, but not Ubuntu.

#include <stdio.h>

#define MAXBUF 256

char *safe_strncat(char *dest, const char *src, size_t n) {
snprintf(dest, n, "%s%s", dest, src);
return dest;
}

int main(int argc, const char * argv[]){
char st1[MAXBUF+1] = "abc";
char st2[MAXBUF+1] = "def";
char* st3;
printf("%s + %s = ",st1, st2);

st3 = safe_strncat(st1, st2, MAXBUF);

printf("%s\n",st3);
printf("original string = %s\n",st1);
}


Compile and run on Ubuntu


gcc concat_test.c -o concat_test

./concat_test

abc + def = def

original string = def


Compile and run in Xcode in OS X


abc + def = abcdef

original string = abcdef



  1. Why does this work on mac and not on Ubuntu?

  2. Should it work on Ubuntu?

  3. Should it work on Mac?

  4. I could swear it used to work in Ubuntu until recently, but I don't know what would have changed to make it stop working?

  5. Could compiler settings have anything to do with this working or not?


Answer

Your code invokes undefined behavior because you pass the destination buffer as one of the source strings of your snprintf() format. This is not supported:

7.21.6.5 The snprintf function

Synopsis

#include <stdio.h>

int snprintf(char * restrict s, size_t n,
             const char * restrict format, ...);

Description

The snprintf function is equivalent to fprintf, except that the output is written into an array (specified by argument s) rather than to a stream. If n is zero, nothing is written, and s may be a null pointer. Otherwise, output characters beyond the n-1st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array. If copying takes place between objects that overlap, the behavior is undefined.

(emphasis mine).

The implementation of snprintf differs between Ubuntu (glibc) and OS/X (Apple libc, based on BSD sources). The behavior differs and cannot be relied upon as it is undefined in all cases.

Comments