Bug 441945
| Summary: | glibc: [RFE] snprintf must not fail with ENOMEM | ||
|---|---|---|---|
| Product: | [Fedora] Fedora | Reporter: | Jim Meyering <meyering> |
| Component: | glibc | Assignee: | glibc team <glibc-bugzilla> |
| Status: | CLOSED UPSTREAM | QA Contact: | Fedora Extras Quality Assurance <extras-qa> |
| Severity: | low | Docs Contact: | |
| Priority: | low | ||
| Version: | rawhide | CC: | calimocho.fedora, codonell, fweimer, jim, law, maggu2810, rjones |
| Target Milestone: | --- | Keywords: | Reopened, Triaged |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | Bug Fix | |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2019-09-10 13:38:22 UTC | Type: | --- |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
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. 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 package has changed ownership in the Fedora Package Database. Reassigning to the new owner of this component. This is now being tracked upstream: https://sourceware.org/bugzilla/show_bug.cgi?id=24988 |
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: