LWN.net Logo

strcpy() / strlcpy() / asprintf()

strcpy() / strlcpy() / asprintf()

Posted Mar 30, 2012 12:50 UTC (Fri) by nix (subscriber, #2304)
In reply to: strcpy() / strlcpy() / asprintf() by abacus
Parent article: A turning point for GNU libc

And unlike strlcpy(), asprintf() really *is* very hard to implement in terms of other functions without either reimplementing printf format string parsing, or doing some sort of hideous hack involving mmap()ed regions repeated sprintf()ing, and catching SIGSEGV to detect overruns (yes, I've done that, yes, it made me feel ill).


(Log in to post comments)

strcpy() / strlcpy() / asprintf()

Posted Mar 30, 2012 15:56 UTC (Fri) by nybble41 (subscriber, #55106) [Link]

It seems to me like asprintf() should be easy to implement in terms of two calls to vsnprintf():

int vasprintf(char **strp, const char *fmt, va_list ap)
{
  va_list ap_copy;
  char *str;
  int bytes;
  char nul;

  /* Determine the amount of memory required to format the string */
  /* vsnprintf() returns the space required, but only stores the NUL. */
  va_copy(ap_copy, ap);
  bytes = vsnprintf(&nul, 1, fmt, ap_copy);
  va_end(ap_copy);

  if (bytes <= 0)
    return bytes;

  str = (char*)malloc(bytes);

  if (!str)
    return -1;

  /* Format the string into the destination buffer */
  bytes = vsnprintf(str, bytes, fmt, ap);

  if (bytes <= 0)
  {
    free(str);
    return bytes;
  }

  /* No errors; store pointer to destination buffer and return its size. */
  *strp = str;
  return bytes;
}

int asprintf(char **strp, const char *fmt, ...)
{
  int bytes;
  va_list ap;

  va_start(ap, fmt);
  bytes = vasprintf(strp, fmt, ap);
  va_end(ap);

  return bytes;
}

Is there any reason this implementation wouldn't work? (Ignoring minor issues/typos; I'm making this up as I go.)

strcpy() / strlcpy() / asprintf()

Posted Mar 30, 2012 17:50 UTC (Fri) by nix (subscriber, #2304) [Link]

Ah yes, of course if you had a vsnprintf() you can do it. I forgot about that. (I spent way too long on deprived platforms with either no snprintf() or none that worked.)

strcpy() / strlcpy() / asprintf()

Posted Mar 31, 2012 21:10 UTC (Sat) by lacos (subscriber, #70616) [Link]

You can still implement it easily (but perhaps not too elegantly): vfprintf() the stuff to "/dev/null", and use the return value for allocation. Both the vfprintf() function and the /dev/null special file are mandated by SUSv1 (UNIX(R) 95) and possibly by earlier standards.

(SUSv1 doesn't have snprintf(). Once I needed to compile a glibc-oriented program on OSF/1 4.0E, which one might have consider a reference implementation of SUSv1, even though it wasn't formally certified. The program needed snprintf() and there was none, so I printed the string first to /dev/null (for the size), then fully to a malloc()'d area, then copied the bytes that had room, then free()'d the area. ... Sorry if this sounds trivial and/or retarded :))

strcpy() / strlcpy() / asprintf()

Posted Apr 5, 2012 8:36 UTC (Thu) by nix (subscriber, #2304) [Link]

Never thought of using vfprintf(). That's a good idea. Ah well. It would surely be more elegant than the longjmp() thing.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds