mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] Bug report: fcvt seems dysfunctional
@ 2022-09-06  9:27 Gabriel Ravier
  2022-09-06 10:12 ` [musl] ecvt(0, 0, ...) is broken Gabriel Ravier
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriel Ravier @ 2022-09-06  9:27 UTC (permalink / raw)
  To: musl

Executing something like `fcvt(0.01, 1, &decpt, &sign)` under musl 
results in a return value of "00", decpt == 1 and sign == 0.

glibc instead returns an empty string, decpt == -1 and sign == 0.

I believe glibc's behavior is the correct one as mandated by POSIX.2004 
because it specifies that the high-order digit shall be non-zero unless 
the value is 0, which is not the case here, meaning that musl cannot 
return a string containing '0' as the first character.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [musl] ecvt(0, 0, ...) is broken
  2022-09-06  9:27 [musl] Bug report: fcvt seems dysfunctional Gabriel Ravier
@ 2022-09-06 10:12 ` Gabriel Ravier
  2022-09-06 12:13   ` Joakim Sindholt
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriel Ravier @ 2022-09-06 10:12 UTC (permalink / raw)
  To: musl

Executing ecvt(0, 0, &decpt, &sign) results in musl returning 
"000000000000000".

This seems highly likely to be a bug considering that glibc returns "" 
and I see no plausible reasoning for musl's behavior that could be 
justified by the standard.

This seems to be caused by musl's ecvt containing this line of code:

if (n-1U > 15) n = 15;

which I would assume was not intended to match n == 0.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 10:12 ` [musl] ecvt(0, 0, ...) is broken Gabriel Ravier
@ 2022-09-06 12:13   ` Joakim Sindholt
  2022-09-06 12:21     ` Gabriel Ravier
  0 siblings, 1 reply; 10+ messages in thread
From: Joakim Sindholt @ 2022-09-06 12:13 UTC (permalink / raw)
  To: musl

On Tue, 6 Sep 2022 12:12:48 +0200, Gabriel Ravier <gabravier@gmail.com> wrote:
> Executing ecvt(0, 0, &decpt, &sign) results in musl returning 
> "000000000000000".
> 
> This seems highly likely to be a bug considering that glibc returns "" 
> and I see no plausible reasoning for musl's behavior that could be 
> justified by the standard.

POSIX.1-2001 said:
> The ecvt() function shall convert value to a null-terminated string of
> ndigit digits (where ndigit is reduced to an unspecified limit
> determined by the precision of a double) and return a pointer to the
> string. The high-order digit shall be non-zero, unless the value is 0.

The first part would imply that ndigit=0 should return the string "" but
the second part makes no provision for a zero-digit-long string.
I would say ndigit=0 is UB.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 12:13   ` Joakim Sindholt
@ 2022-09-06 12:21     ` Gabriel Ravier
  2022-09-06 14:17       ` Rich Felker
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriel Ravier @ 2022-09-06 12:21 UTC (permalink / raw)
  To: musl, Joakim Sindholt

On 9/6/22 14:13, Joakim Sindholt wrote:
> On Tue, 6 Sep 2022 12:12:48 +0200, Gabriel Ravier <gabravier@gmail.com> wrote:
>> Executing ecvt(0, 0, &decpt, &sign) results in musl returning
>> "000000000000000".
>>
>> This seems highly likely to be a bug considering that glibc returns ""
>> and I see no plausible reasoning for musl's behavior that could be
>> justified by the standard.
> POSIX.1-2001 said:
>> The ecvt() function shall convert value to a null-terminated string of
>> ndigit digits (where ndigit is reduced to an unspecified limit
>> determined by the precision of a double) and return a pointer to the
>> string. The high-order digit shall be non-zero, unless the value is 0.
> The first part would imply that ndigit=0 should return the string "" but
> the second part makes no provision for a zero-digit-long string.
> I would say ndigit=0 is UB.
Wouldn't that then mean that any request call of fcvt with a small 
ndigits but very small value that isn't 0, as in my previous email, 
would also be UB (since if my logic is correct, the string cannot start 
with a 0 but it also cannot start with any other value, which forces it 
to be empty) ? That seems rather excessive...

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 12:21     ` Gabriel Ravier
@ 2022-09-06 14:17       ` Rich Felker
  2022-09-06 18:48         ` Markus Wichmann
  0 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2022-09-06 14:17 UTC (permalink / raw)
  To: Gabriel Ravier; +Cc: musl, Joakim Sindholt

On Tue, Sep 06, 2022 at 02:21:52PM +0200, Gabriel Ravier wrote:
> On 9/6/22 14:13, Joakim Sindholt wrote:
> >On Tue, 6 Sep 2022 12:12:48 +0200, Gabriel Ravier <gabravier@gmail.com> wrote:
> >>Executing ecvt(0, 0, &decpt, &sign) results in musl returning
> >>"000000000000000".
> >>
> >>This seems highly likely to be a bug considering that glibc returns ""
> >>and I see no plausible reasoning for musl's behavior that could be
> >>justified by the standard.
> >POSIX.1-2001 said:
> >>The ecvt() function shall convert value to a null-terminated string of
> >>ndigit digits (where ndigit is reduced to an unspecified limit
> >>determined by the precision of a double) and return a pointer to the
> >>string. The high-order digit shall be non-zero, unless the value is 0.
> >The first part would imply that ndigit=0 should return the string "" but
> >the second part makes no provision for a zero-digit-long string.
> >I would say ndigit=0 is UB.
> Wouldn't that then mean that any request call of fcvt with a small
> ndigits but very small value that isn't 0, as in my previous email,
> would also be UB (since if my logic is correct, the string cannot
> start with a 0 but it also cannot start with any other value, which
> forces it to be empty) ? That seems rather excessive...

These functions are highly underspecified but have been obsolete and
deprecated for decades and there is really no plausible motivation for
using them. So I don't see much value in language-lawyering over them.

I don't see how the condition on ecvt implies ndigit==0 is UB.

    "The high-order digit shall be non-zero, unless the value is 0"

arguably is undefined in the case where there is no high-order digit,
but imposes no requirements if the value is zero. However this reading
depends a lot on phrasing and how the phrasing interacts with vacuous
conditions, which was probably not the intent.

I think it would be perfectly fine to fix ecvt to return "" when
ndigit==0. I don't see any way the fcvt case is well-defined though.
There are just conflicting requirements. The number of characters in
the resulting string is not allowed to be fewer than specified just
because it conflicts with the leading digit condition.

We're not going to get an interpretation on this because the functions
were removed from POSIX over a decade ago. I guess someone who really
cares about it could research the original Unix implementations and
what they did and if there was any rhyme or reason to it, and make a
proposal to align with that. But these are garbage functions. The
right answer is to fix whatever is using them to use snprintf and move
on.

Rich



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 14:17       ` Rich Felker
@ 2022-09-06 18:48         ` Markus Wichmann
  2022-09-06 19:19           ` Rich Felker
  0 siblings, 1 reply; 10+ messages in thread
From: Markus Wichmann @ 2022-09-06 18:48 UTC (permalink / raw)
  To: musl; +Cc: Gabriel Ravier, Joakim Sindholt

On Tue, Sep 06, 2022 at 10:17:36AM -0400, Rich Felker wrote:
> But these are garbage functions. The
> right answer is to fix whatever is using them to use snprintf and move
> on.
>
> Rich
>
>

Well, then why not remove them from the lib? Any program using them
would invoke a link failure. Indeed, for GCC, the declarations could be
retained and an error attribute be added. Configure tests would fail to
find these functions and possibly switch on alternative paths.

Of course, that is not ABI compatible. But isn't excising broken
functions better than retaining them? Because as the OP showed, our
implementations are not behaving as some callers would expect.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 18:48         ` Markus Wichmann
@ 2022-09-06 19:19           ` Rich Felker
  2022-09-07  3:39             ` Markus Wichmann
  0 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2022-09-06 19:19 UTC (permalink / raw)
  To: Markus Wichmann; +Cc: musl, Gabriel Ravier, Joakim Sindholt

On Tue, Sep 06, 2022 at 08:48:26PM +0200, Markus Wichmann wrote:
> On Tue, Sep 06, 2022 at 10:17:36AM -0400, Rich Felker wrote:
> > But these are garbage functions. The
> > right answer is to fix whatever is using them to use snprintf and move
> > on.
> 
> Well, then why not remove them from the lib? Any program using them
> would invoke a link failure. Indeed, for GCC, the declarations could be
> retained and an error attribute be added. Configure tests would fail to
> find these functions and possibly switch on alternative paths.
> 
> Of course, that is not ABI compatible. But isn't excising broken
> functions better than retaining them?

If that were the case we would have removed gets, so no.

> Because as the OP showed, our
> implementations are not behaving as some callers would expect.

If they're behaving as some caller expects, and we break that caller
by breaking ABI stability policy, we're in the wrong. If that caller
is making assumptions about what these functions do contrary to how
they were ever documented to behave, they're in the wrong. Having
clear position/policy on this, *even if it's on utter junk functions
that are probably not used in any real world software*, is part of
what makes folks trust musl.

Rich

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-06 19:19           ` Rich Felker
@ 2022-09-07  3:39             ` Markus Wichmann
  2022-09-07  3:51               ` Jeffrey Walton
  0 siblings, 1 reply; 10+ messages in thread
From: Markus Wichmann @ 2022-09-07  3:39 UTC (permalink / raw)
  To: musl; +Cc: Gabriel Ravier, Joakim Sindholt

On Tue, Sep 06, 2022 at 03:19:51PM -0400, Rich Felker wrote:
> On Tue, Sep 06, 2022 at 08:48:26PM +0200, Markus Wichmann wrote:
> > On Tue, Sep 06, 2022 at 10:17:36AM -0400, Rich Felker wrote:
> > > But these are garbage functions. The
> > > right answer is to fix whatever is using them to use snprintf and move
> > > on.
> >
> > Well, then why not remove them from the lib? Any program using them
> > would invoke a link failure. Indeed, for GCC, the declarations could be
> > retained and an error attribute be added. Configure tests would fail to
> > find these functions and possibly switch on alternative paths.
> >
> > Of course, that is not ABI compatible. But isn't excising broken
> > functions better than retaining them?
>
> If that were the case we would have removed gets, so no.
>

That would have been the next function on my hit list.

Alright, next idea then: Could we put a linker warning on these
functions to encourage users to switch? That would not break ABI, as all
symbols are still there and the functions do what they are supposed to
(as well as we ever implemented them, at least). But new compilations
would get a nag to make them stop.

Unfortunately, it is possible that a configure script may misinterpret
these warnings as errors, and if it was set up to test for a function's
existence and the function is mandatory, then that script would fail
when previously, it would succeed.

What I'm trying to get at more generally here is a mechanism for
deprecating libc functions. Because apparently we have amassed a few
junk functions that people should not keep using. And experience
suggests that merely documenting this state of affairs will not change
it, since developers only ever read documentation after things go wrong.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-07  3:39             ` Markus Wichmann
@ 2022-09-07  3:51               ` Jeffrey Walton
  2022-09-07 13:44                 ` Rich Felker
  0 siblings, 1 reply; 10+ messages in thread
From: Jeffrey Walton @ 2022-09-07  3:51 UTC (permalink / raw)
  To: musl

On Tue, Sep 6, 2022 at 11:39 PM Markus Wichmann <nullplan@gmx.net> wrote:
>
> On Tue, Sep 06, 2022 at 03:19:51PM -0400, Rich Felker wrote:
> > On Tue, Sep 06, 2022 at 08:48:26PM +0200, Markus Wichmann wrote:
> > > On Tue, Sep 06, 2022 at 10:17:36AM -0400, Rich Felker wrote:
> > > > But these are garbage functions. The
> > > > right answer is to fix whatever is using them to use snprintf and move
> > > > on.
> > >
> > > Well, then why not remove them from the lib? Any program using them
> > > would invoke a link failure. Indeed, for GCC, the declarations could be
> > > retained and an error attribute be added. Configure tests would fail to
> > > find these functions and possibly switch on alternative paths.
> > >
> > > Of course, that is not ABI compatible. But isn't excising broken
> > > functions better than retaining them?
> >
> > If that were the case we would have removed gets, so no.
> >
>
> That would have been the next function on my hit list.
>
> Alright, next idea then: Could we put a linker warning on these
> functions to encourage users to switch? That would not break ABI, as all
> symbols are still there and the functions do what they are supposed to
> (as well as we ever implemented them, at least). But new compilations
> would get a nag to make them stop.
>
> Unfortunately, it is possible that a configure script may misinterpret
> these warnings as errors, and if it was set up to test for a function's
> existence and the function is mandatory, then that script would fail
> when previously, it would succeed.
>
> What I'm trying to get at more generally here is a mechanism for
> deprecating libc functions. Because apparently we have amassed a few
> junk functions that people should not keep using. And experience
> suggests that merely documenting this state of affairs will not change
> it, since developers only ever read documentation after things go wrong.

Make it a configure option, like --no-xxx or --disablke-xxx. Recommend
the distros build with the option.

Now the problem is transferred to the distros. When a user uses a
deprecated function that's no longer supported by the standard, the
distros can decide what to do. They can help users move away from the
functions, supply patches for the deprecated functions, etc.

Jeff

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [musl] ecvt(0, 0, ...) is broken
  2022-09-07  3:51               ` Jeffrey Walton
@ 2022-09-07 13:44                 ` Rich Felker
  0 siblings, 0 replies; 10+ messages in thread
From: Rich Felker @ 2022-09-07 13:44 UTC (permalink / raw)
  To: Jeffrey Walton; +Cc: musl

On Tue, Sep 06, 2022 at 11:51:35PM -0400, Jeffrey Walton wrote:
> On Tue, Sep 6, 2022 at 11:39 PM Markus Wichmann <nullplan@gmx.net> wrote:
> >
> > On Tue, Sep 06, 2022 at 03:19:51PM -0400, Rich Felker wrote:
> > > On Tue, Sep 06, 2022 at 08:48:26PM +0200, Markus Wichmann wrote:
> > > > On Tue, Sep 06, 2022 at 10:17:36AM -0400, Rich Felker wrote:
> > > > > But these are garbage functions. The
> > > > > right answer is to fix whatever is using them to use snprintf and move
> > > > > on.
> > > >
> > > > Well, then why not remove them from the lib? Any program using them
> > > > would invoke a link failure. Indeed, for GCC, the declarations could be
> > > > retained and an error attribute be added. Configure tests would fail to
> > > > find these functions and possibly switch on alternative paths.
> > > >
> > > > Of course, that is not ABI compatible. But isn't excising broken
> > > > functions better than retaining them?
> > >
> > > If that were the case we would have removed gets, so no.
> > >
> >
> > That would have been the next function on my hit list.
> >
> > Alright, next idea then: Could we put a linker warning on these
> > functions to encourage users to switch? That would not break ABI, as all
> > symbols are still there and the functions do what they are supposed to
> > (as well as we ever implemented them, at least). But new compilations
> > would get a nag to make them stop.
> >
> > Unfortunately, it is possible that a configure script may misinterpret
> > these warnings as errors, and if it was set up to test for a function's
> > existence and the function is mandatory, then that script would fail
> > when previously, it would succeed.
> >
> > What I'm trying to get at more generally here is a mechanism for
> > deprecating libc functions. Because apparently we have amassed a few
> > junk functions that people should not keep using. And experience
> > suggests that merely documenting this state of affairs will not change
> > it, since developers only ever read documentation after things go wrong.
> 
> Make it a configure option, like --no-xxx or --disablke-xxx.

Having multiple build-time configurations with different
functionality, especially different symbol sets (ABI-breaking), is
something musl very intentionally does not do.

> Recommend
> the distros build with the option.

I very much do not recommend that distros build with incompatible ABI
changes. This not only makes it impossible (in general, without
assumptions on what symbols it's using/not-using) to take a
dynamic-linked musl binary that was not built for the particular
distro and use it there, but can even break binaries the user
themselves compiled *on the distro* when they perform an upgrade.
There is utterly no value in doing this, and huge platform reputation
destroying cost.

If a distro has a policy of not wanting to build packages that use
fcnv or ecnv or gets, all it takes is a recipe to check the symbol
tables along with other checks they should already be doing (like
checking that the package did not create suid-root files without being
flagged as allowed to do so) as part of packaging a distro. This does
not need an intentionally-compat-breaking libc to do it.

Note that distros are very much on board with all this, and that's why
we have a healthy ecosystem. For example when there are new interfaces
proposed for inclusion in musl, the Alpine folks always reach out to
confirm that they're actually going to be going upstream before
patching them in early to support the need of some software they're
trying to package. This ensures that we don't end up with ABI
mismatches and a fragmented platform.

> Now the problem is transferred to the distros. When a user uses a
> deprecated function that's no longer supported by the standard, the
> distros can decide what to do. They can help users move away from the
> functions, supply patches for the deprecated functions, etc.

I'm confused who the "users" are here. Distros generally deal with the
bad decisions of upstream software providers, not of their users, in
the course of what they do -- it's upstreams they have to convince to
stop doing stuff that's deprecated or nonportable. I guess there may
also be some value in pointing out to users building in-house software
(that they compile themselves) on top of the distro that certain
functions they're using are deprecated/bad-to-use, which could
probably be achieved by some sort of warning, without breaking
anything.

Rich

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-09-07 13:44 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06  9:27 [musl] Bug report: fcvt seems dysfunctional Gabriel Ravier
2022-09-06 10:12 ` [musl] ecvt(0, 0, ...) is broken Gabriel Ravier
2022-09-06 12:13   ` Joakim Sindholt
2022-09-06 12:21     ` Gabriel Ravier
2022-09-06 14:17       ` Rich Felker
2022-09-06 18:48         ` Markus Wichmann
2022-09-06 19:19           ` Rich Felker
2022-09-07  3:39             ` Markus Wichmann
2022-09-07  3:51               ` Jeffrey Walton
2022-09-07 13:44                 ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).