assertion failure in snprntffuns.c:79 for i686-w64-mingw32

Vincent Lefevre vincent at vinc17.net
Fri Jan 10 13:12:01 UTC 2020


On 2020-01-10 08:44:13 +0100, Niels Möller wrote:
> Vincent Lefevre <vincent at vinc17.net> writes:
> 
> > Under Debian/unstable, I've configured GMP with:
> >
> >   ./configure --host=i686-w64-mingw32 --disable-shared --enable-assert
> >
> > but "make check LOG_COMPILER=wine" gives:
> >
> > FAIL: t-printf
> > ==============
> >
> > snprntffuns.c:79: GNU MP assertion failed: strlen (d->buf) == avail-1
> > FAIL t-printf.exe (exit status: 3)
> >
> > The failing code is
> >
> >       ret = vsnprintf (d->buf, avail, fmt, ap);
> >       if (ret == -1)
> >         {
> >           ASSERT (strlen (d->buf) == avail-1);
> >           ret = avail-1;
> >         }
> 
> Does it make a difference if you add CPPFLAGS=-D__USE_MINGW_ANSI_STDIO
> to the configuration?

I get no failures.

> > I don't understand the ASSERT. A return value of -1 means an output
> > error, so that you cannnot deduce anything about the contents stored
> > in d->buf.
> 
> Non-standard versions of snprintf returned -1 for truncation (including
> old glibc, and likely windows libc too). And the way I read the ASSERT,
> it says that truncation is the only expected reason for vsnprintf to
> return -1. What was fmt? It would be helpful to understand the reason
> for the -1 return in the failing case.

Here's what I get for i = 3 to 7:

i = 3, limb = 7 (1)
avail = 2, fmt = "%lu", ret = 1, buf = "7"

i = 4, limb = 15 (1)
avail = 2, fmt = "%lu", ret = 2, buf = "15!"

i = 5, limb = 31 (1)
avail = 2, fmt = "%lu", ret = 2, buf = "31!"

i = 6, limb = 63 (1)
avail = 2, fmt = "%lu", ret = 2, buf = "63!"

i = 7, limb = 127 (1)
avail = 2, fmt = "%lu", ret = -1, buf = "12!7"

So, one gets a truncation because avail = 2 is too small for 127,
and like with old glibc, one gets ret = -1. GMP expects that a \0
at the end is written in this case, and perhaps old glibc did, but
not mingw.

Note that the "7" after the sentinel is just old data. If I add

      d->buf[avail+1] = '\0';

before the

      ret = vsnprintf (d->buf, avail, fmt, ap);

I get:

avail = 2, fmt = "%lu", ret = -1, buf = "12!"

So, without -D__USE_MINGW_ANSI_STDIO, this is non-conforming (perhaps
for compatibility if vsnprintf was implemented in MS Windows before
it got standardized in ISO C99). I think that a fix should be easy:
write a \0 before the sentinel, and if ret = -1 and this \0 has been
replaced by vsnprintf, this probably means truncation.

-- 
Vincent Lefèvre <vincent at vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


More information about the gmp-bugs mailing list