How can I overcome the inconsistent behavior of snprintf on different UNIX-like operating systems?

On man pages, snprintf returns the number of bytes written from glibc version 2.6 onwards. But in lower versions of libc2.2 and HP-UX, it returns a positive integer, which can lead to a buffer overflow.

How can I overcome this and write portable code?

Edit: for clarity

This code works fine in lib 2.3

    if ( snprintf( cmd, cmdLen + 1, ". %s%s", myVar1, myVar2 )  != cmdLen )
    {
        fprintf( stderr, "\nError: Unable to  copy bmake command!!!");
        returnCode = ERR_COPY_FILENAME_FAILED;
    }

It returns the string length (10) in Linux. But the same code returns a positive number that is greater than the number of characters printed on the HP-UX machine. I hope this explanation will be perfect.

+3
source share
6 answers

snprintf, -1 , .

. . , .

  while (1) {
      /* Try to print in the allocated space. */
      va_start(ap, fmt);
      n = vsnprintf (p, size, fmt, ap);
      va_end(ap);
      /* If that worked, return the string. */
      if (n > -1 && n < size)
         return p;
      /* Else try again with more space. */
      if (n > -1)    /* glibc 2.1 */
         size = n+1; /* precisely what is needed */
      else           /* glibc 2.0 */
         size *= 2;  /* twice the old size */
      if ((np = realloc (p, size)) == NULL) {
         free(p);
         return NULL;
      } else {
         p = np;
      }
   }
+4
+2

. , :

snprintf() vsnprintf() ( '\ 0'). - , ( "\ 0" ), , , , , .

, , :

int ret = snprintf(cmd, cmdLen + 1, ". %s%s", myVar1, myVar2 ) == -1)
if(ret == -1 || ret > cmdLen)
{
    //output was truncated
}
else
{
    //everything is groovy
}
+1

* printf, , -, , , :

  • c99- * printf, 9 , , .

  • my_snprintf() #ifdef , , vsnprintf() ( - , ).

  • vsnprintf() , , , vstr, - .

... , # 1 # 2 -1, - , c99 * printf / -1 .

, ustr, . , vstr.

+1

/ , sprintf , , .

What you do is create a temporary file with tmpfile (), fprintf () before it (which reliably returns the number of bytes written), then rewind and read all the text or part of the text to the clipboard.

Example:

int my_snprintf(char *buf, size_t n, const char *fmt, ...)
{
    va_list va;
    int nchars;
    FILE *tf = tmpfile();

    va_start(va, n);
    nchars = vfprintf(tf, fmt, va);
    if (nchars >= (int) n)
        nchars = (int) n - 1;
    va_end(va);
    memset(buf, 0, 1 + (size_t) nchars);

    if (nchars > 0)
    {
        rewind(tf);
        fread(buf, 1, (size_t) nchars, tf);
    }

    fclose(tf);

    return nchars;   
}
0
source

Use far superior asprintf () instead.

This is a GNU extension, but it should be copied to the target platform in case it is not available.

0
source

Source: https://habr.com/ru/post/1697197/


All Articles