Description of problem: snprintf can fail with ENOMEM Printing into a 200-byte buffer should never have to allocate an arbitrarily large amount of memory. In fact, snprintf should never allocate memory in a manner that can fail, period. Version-Release number of selected component (if applicable): glibc-2.7.90-13.x86_64 How reproducible: every time Steps to Reproduce: cat <<\EOF > k.c /* snprintf should not allocate memory, *ever*. POSIX says that snprintf may fail with EOVERFLOW (n > INT_MAX or size of output would exceed INT_MAX). It appears not to allow failure with ENOMEM, as happens here: $ zsh -c 'ulimit -v 5000; ./a.out %$[5*2**20]d' fmt: %5242880d retval=-1 errno=Cannot allocate memory # Same with bash, but it requires more memory: $ bash -c 'ulimit -v 12000; ./a.out %$[12*2**20]d' */ #include <stdio.h> #include <string.h> #include <errno.h> int main(int argc, char **argv) { char buf[200]; char *fmt = argv[1]; if (argc < 2) return 1; int n = snprintf (buf, sizeof buf, fmt, 1); int saved_errno = errno; printf ("fmt: %s retval=%d errno=%s\n", fmt, n, n < 0 ? strerror(saved_errno) : ""); return 0; } EOF gcc k.c zsh -c 'ulimit -v 5000; ./a.out %$[5*2**20]d' Actual results: fmt: %5242880d retval=-1 errno=Cannot allocate memory Expected results: fmt: %5242880d retval=5242880 errno= Additional info:
Regarding POSIX conformance, consider this: snprintf (NULL, 0, fmt, 1); currently, that fails just like the example above. However, POSIX requires something else: If the value of n is zero on a call to snprintf(), nothing shall be written, the number of bytes that would have been written had n been sufficiently large excluding the terminating null shall be returned, and s may be a null pointer.
That applies only upon successful completion. Even for n 0 if there are errors snprintf is supposed to return -1 and set errno. For cases like: #include <errno.h> #include <locale.h> #include <stdio.h> int main (void) { setlocale (LC_ALL, "en_US.ISO-8859-1"); int ret = snprintf (NULL, 0, "%lC\n", (wint_t) 0x10c); printf ("%d %m\n", ret); return 0; } where ret should be -1 and errno EILSEQ, but even cases where memory was needed and -1/ENOMEM is returned.
Hi Jakub, That's a fine example, but it merely suggests that the crystal clear wording in POSIX (quoted above) should be relaxed to allow snprintf to return -1 upon EILSEQ. There is already explicit language that implies snprintf w/n=0 will not fail with ENOMEM, so at least in that latter case, glibc violates the intent of the standard.
Hi guys, Please do not close this until snprintf stops allocating from the heap at least for integer and string formats. If you prefer, I can change the title to a request for improved QoI, so it doesn't look like a bug, but imho, it should be considered a bug for snprintf(NULL,0, ...) to allocate memory when the format involves no floating point conversion specifier. http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/23838 As I said there, FreeBSD's snprintf appears to get this right, so glibc's should, too.
This package has changed ownership in the Fedora Package Database. Reassigning to the new owner of this component.
Just changing status so this pops up in my searches for bugs needing my attention
This is now being tracked upstream: https://sourceware.org/bugzilla/show_bug.cgi?id=24988