bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

glibc's snprintf is a pig; fix or replace ?


From: Jim Meyering
Subject: glibc's snprintf is a pig; fix or replace ?
Date: Wed, 03 Nov 2010 10:13:23 +0100

glibc's snprintf is next-to-useless in an application that must accept
arbitrary inputs and/or arbitrary format strings, and that cannot afford
to allocate 2GiB of heap.

Did you know that glibc's snprintf can fail due to ENOMEM?  Your reaction
to that possibility should be disbelief.  But it's true.  Why does
snprintf allocate space from the heap for a format string like "%*d"?
I reported it as http://bugzilla.redhat.com/441945, but amazingly
enough, it was closed "NOTABUG".  The justification was that the POSIX
specification permits the current senseless behavior.  The letter of the
spec may permit it, but the spirit must not, so if indeed POSIX allows
the current behavior, the spec should be adjusted.

What's the problem?
Consider a single format directive.
If I give snprintf a buffer to print into, should it first allocate
(potentially from the heap) enough space to render the entire result,
and then copy that (or whatever fits) into the user-supplied buffer?
In many cases it's ok, albeit wasteful (unwarranted allocation and
an extra copy).  In others, it's a needless source of failure, and
a ridiculous abuse of resources.  Do you want your code to take 10-30
seconds to allocate 2GiB of heap and fill that space with 2 billion '0's
only to learn that snprintf(NULL, 0, "%0*d", INT_MAX, 0) returns INT_MAX ?
Often, when I use snprintf, it's because I want to avoid using as*printf.

More reasonably, imagine a low-memory scenario.
You want to determine whether a small static buffer
is large enough to hold the result of an snprintf call.
If not, you must take other measures, but you cannot allocate
memory from the heap.  You would use
  n = snprintf(NULL, 0, fmt, ...)
to compute the length of the result and compare that to
the size of your small static buffer.
But with glibc's snprintf you've already lost, since it may
allocate an arbitrarily large amount of space just to determine
the desired length.  This is more than a "quality of implementation"
issue.

Is simply avoiding snprintf enough?  No, because every *printf function
uses snprintf under the covers, even if you use gnulib replacements.
They all end up going through the system-supplied snprintf function.

Fixing it in glibc is not trivial.
Handling %c, %s and %[xoiud] would be easy,
but floating point can be tricky; for some values,
you may need additional space for multiple-precision arithmetic
to determine the precise width of the printed representation.
While it'd be nice to have an all-around fix, even fixing it for
integer and string formats would be a most welcome improvement.
There are far fewer applications that care about floating point formats.

FreeBSD's snprintf appears to work fine on this front.
glibc's should, too.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]