[ovs-dev] [PATCH] dynamic-string: Fix a bug that leads to assertion fail
Ben Pfaff
blp at ovn.org
Tue Jul 24 22:55:36 UTC 2018
Some pre-ANSI C99 implementations of (v)snprintf() returned -1 if the
output was truncated, but C99 and SUSv3 require it to return the number
of bytes that would have been written if the buffer was large enough,
and for at least the last 10 years or so glibc has implemented it that
way.
Try building and running this program:
#include <stdio.h>
int
main(void)
{
char x[9];
return snprintf(x, sizeof x, "0123456789");
}
The exit status is 10, not 1.
The glibc manual talks about this:
-- Function: int snprintf (char *S, size_t SIZE, const char *TEMPLATE,
...)
Preliminary: | MT-Safe locale | AS-Unsafe heap | AC-Unsafe mem |
*Note POSIX Safety Concepts::.
The 'snprintf' function is similar to 'sprintf', except that the
SIZE argument specifies the maximum number of characters to
produce. The trailing null character is counted towards this
limit, so you should allocate at least SIZE characters for the
string S. If SIZE is zero, nothing, not even the null byte, shall
be written and S may be a null pointer.
The return value is the number of characters which would be
generated for the given input, excluding the trailing null. If
this value is greater or equal to SIZE, not all characters from the
result have been stored in S. You should try again with a bigger
output string. Here is an example of doing this:
/* Construct a message describing the value of a variable
whose name is NAME and whose value is VALUE. */
char *
make_message (char *name, char *value)
{
/* Guess we need no more than 100 chars of space. */
int size = 100;
char *buffer = (char *) xmalloc (size);
int nchars;
if (buffer == NULL)
return NULL;
/* Try to print in the allocated space. */
nchars = snprintf (buffer, size, "value of %s is %s",
name, value);
if (nchars >= size)
{
/* Reallocate buffer now that we know
how much space is needed. */
size = nchars + 1;
buffer = (char *) xrealloc (buffer, size);
if (buffer != NULL)
/* Try again. */
snprintf (buffer, size, "value of %s is %s",
name, value);
}
/* The last call worked, return the string. */
return buffer;
}
In practice, it is often easier just to use 'asprintf', below.
*Attention:* In versions of the GNU C Library prior to 2.1 the
return value is the number of characters stored, not including the
terminating null; unless there was not enough space in S to store
the result in which case '-1' is returned. This was changed in
order to comply with the ISO C99 standard.
On Tue, Jul 24, 2018 at 03:31:12PM -0700, Yifeng Sun wrote:
> Hi Ben,
>
> vsnprintf returns the size that was truncated. So we need at least
> ds->allocated + needed bytes to print the full string.
> needed = vsnprintf(&ds->string[ds->length], available, format,
> args);
>
> So ds_reserve should make sure ds contains at least ds->allocated + needed
> bytes.
> ds_reserve(ds, ds->allocated + needed);
>
> For example, if ds starts with:
> length = 4, allocated = 8
> Assume the to-be-printed string length = 10, then we got needed = 2
> In current code, ds_reserve(4 + 2 = 6) is called, if go into ds_reserve(),
> since (6 < 8), ds_reserve actually does nothing.
>
> Thanks,
> Yifeng
>
> On Tue, Jul 24, 2018 at 2:47 PM, Ben Pfaff <blp at ovn.org> wrote:
>
> > On Tue, Jul 24, 2018 at 08:37:08AM -0700, Yifeng Sun wrote:
> > > 'needed' should be size of needed memory space beyond allocated.
> > >
> > > Signed-off-by: Yifeng Sun <pkusunyifeng at gmail.com>
> > > Reported-by: Yun Zhou <yunz at nvidia.com>
> > > Reported-by: Girish Moodalbail <gmoodalbail at gmail.com>
> >
> > I don't see a bug here. Can you explain why you think that there is a
> > bug?
> >
> > (I note that this code dates back to before 2008.)
> >
> > Thanks,
> >
> > Ben.
> >
More information about the dev
mailing list