Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20120309163853.GF184@brightrain.aerifal.cx>
Date: Fri, 9 Mar 2012 11:38:53 -0500
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: Re: [PATCH 0/4] Fix function definitions.

On Fri, Mar 09, 2012 at 09:11:05AM -0600, Rob Landley wrote:
> Why are you doing feature test macros at _all_ in a 2012 Linux libc?  If
> you don't #define any of them (which most code doesn't), you get (from
> /usr/lib/features.h):

features.h is part of glibc, and not a part I like, for several
reasons:

1. Each additional nested header increases base compile time
significantly, and makes a big difference for small translation units
that only includes one header themselves, due to extra path search,
open, read, parse, close, etc.

2. The way glibc does features.h, with _xxx_SOURCE macros as the input
and __USE_xxx macros as the output, obfuscates in the actual headers
which macros are necessary or sufficient to get the desired interface
declared. This makes them less useful as documentation, and encourages
programmers both to define extraneous/unwanted feature test macros due
to lack of awareness that one implies another, and (much worse) to
actually #define __USE_POSIX, etc. in their own sources rather than
defining the correct feature test macro.

3. Others I'm forgetting at the moment.. :-)

> /* If nothing (other than _GNU_SOURCE) is defined,
>    define _BSD_SOURCE and _SVID_SOURCE.  */
> #if (!defined __STRICT_ANSI__ && !defined _ISOC99_SOURCE && \
>      !defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE && \
>      !defined _XOPEN_SOURCE && !defined _XOPEN_SOURCE_EXTENDED && \
>      !defined _BSD_SOURCE && !defined _SVID_SOURCE)
> # define _BSD_SOURCE    1
> # define _SVID_SOURCE   1
> #endif
> 
> and then a bit later...
> 
> /* If none of the ANSI/POSIX macros are defined, use POSIX.1 and POSIX.2
>    (and IEEE Std 1003.1b-1993 unless _XOPEN_SOURCE is defined).  */
> #if ((!defined __STRICT_ANSI__ || (_XOPEN_SOURCE - 0) >= 500) && \
>      !defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE)
> # define _POSIX_SOURCE  1
> # if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 500
> #  define _POSIX_C_SOURCE       2
> # elif defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 600
> #  define _POSIX_C_SOURCE       199506L
> # elif defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 700
> #  define _POSIX_C_SOURCE       200112L
> # else
> #  define _POSIX_C_SOURCE       200809L
> # endif
> # define __USE_POSIX_IMPLICITLY 1
> #endif
> 
> I.E. you get _BSD_SOURCE, _SVID_SOURCE, _POSIX_SOURCE, and
> _POSIX_C_SOURCE=200809L all #defined _FOR_ you if you just avoid
> mentioning any of these macros ever.

Relying on that is not portable, and musl does not do it. On
Linux/glibc you get the kitchen sink when you define nothing. On most
other unices, you get an intentionally-broken legacy environment
that's not conformant to modern standards.

All projects should explicitly define the feature test macros they
want. This also assists you in profiling the portability of your code
(switching out _GNU_SOURCE and you see exactly what extensions you're
using). Thankfully for ones that fail to do this, you can just add the
appropriate -D's to CPPFLAGS.

There's been some discussion of the "kitchen sink by default" approach
in musl, and I'm not entirely opposed to it, but the main issue is
that there's no portable way to select "plain ISO C" with a feature
test macro. There are glibc/gcc ways to request specific versions of
ISO C with feature test macros, but they took the silly approach of
renaming the macro for each version rather than something like #define
_ISO_C_SOURCE 199901L which would have been much cleaner...

Also note that glibc's version of "kitchen sink by default" is broken.
Several functions like strerror_r, basename, and perhaps still scanf
get *broken* GNU versions by default unless you specify an appropriate
feature test macro. So if you want to use them, you're stuck; you have
to use _POSIX_C_SOURCE or _XOPEN_SOURCE and then define some
additional macros to try to get back what you lost. And I'm not even
sure it's possible without breaking the standard functions again...

> And that's exactly what my code did before Georgi tried to build it
> against musl and suddenly that didn't work anymore because musl is weird.
> 
> (A sane development team would have implemented _negative_ macros, ala
> _ANSI_ONLY, to switch stuff _off_.)

There are very good reasons why this was not done; you could ask the
committees if you care.

> >> At present musl makes no attempt to support(*) the _BSD_SOURCE or
> >> _SVID_SOURCE feature test macros; every nonstandard (non-POSIX)
> >> extention offered by glibc is grouped together under _GNU_SOURCE, and
> >> this works for musl because (unlike with glibc), musl's _GNU_SOURCE
> >> only enables features; it does not alter standard interfaces like
> >> strerror_r or basename to be broken GNU versions of the functions.
> 
> A lot of those "nonstandard" things were in BSD circa 1982, before the
> FSF even existed.

I agree. But most of them were omitted from the standards for good
reasons, and even many of the ones that were included (like bcopy)
were redundant.

Anyway, the reason I've not focused on adding _BSD_SOURCE is mainly
lack of necessity. I don't think I've encountered a single package
that was defining _BSD_SOURCE and failed to build because of things it
expected to get from _BSD_SOURCE. If there are major packages that
could be made easier to build by adding it, I'd be a lot more
interested in doing so.

> I don't care about granularity, I just want my code to work.  But I
> refuse to #define _ALL_HAIL_RICHARD_STALLMAN as a condition of using
> standard Linux functions.
> 
> I will not say _GNU_SOURCE when implementing a project that has nothing
> whatsoever to do with the FSF's GNU project, and acts to replace large
> chunks of its' userspace.

OK, so basically you want alternate macros to request the kitchen sink
to avoid writing the word "GNU" anywhere in your project. :-)

All joking aside, at least this is the first *reason* I've seen for
possible changes in this area, so it's worth considering.

> >> I think there's a good (nontrivial) discussion to be had about whether
> >> it's worthwhile to have the _BSD_SOURCE and _SVID_SOURCE feature test
> >> macros supported in musl.
> 
> Given that the "nothing is #defined" behavior gives you most of this
> anyway on both glibc and uClibc, why musl is bothering with it at _all_
> is kinda inexplicable to me.

Because unlike uClibc, musl does not just copy all the mess from
glibc. I like the uClibc project and the people involved, but I don't
like the fact that basically everything but the internal
implementation details of stdio and locale are nearly direct copies
from glibc.

> Yes, I'm aware that Posix 2008 mentions feature test macros:
> 
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02
> 
> And silently ignoring them is reasonably compliant behavior.  (You can
> even be technically compliant with Item 3 under _POSIX_C_SOURCE if you
> consider __linux__ a feature test macro.  It's got the double underscore!)

As long as you don't define additional things outside the reserved
namespace, it's compliant to ignore them. I agree totally.

Of course then your implementation complies only to POSIX, but not to
ISO C. For instance, this strictly conforming program cannot be
compiled (intentionally detailed to make it plausible):

#include <stdio.h>
#include <stdarg.h>
int debugging = 1;
int dprintf(const char *fmt, ...)
{
	int ret;
	if (debugging) return 0;
	va_list ap = va_start(fmt);
	ret = vprintf(fmt, ap);
	va_end(ap);
	return ret;
}
int main()
{
	dprintf("hello, world\n");
}

The same issue happens with conforming POSIX programs if you add
extensions outside the reserved namespaces.

> Which shows you all the compiler builtin #defines.  See __linux__ in
> that list?  If you _have_ to test for something, what's wrong with
> testing for __linux__?

This is not POSIX conformant. POSIX requires invoking the compiler
with -D_POSIX_C_SOURCE=200809L to respect the namespace. With your
suggestion, it would also be necessary to add -U__linux__ to the
command line.

In other words, your proposed change would break all correct programs
that are using feature test macros properly, for the sake of avoiding
adding a -D option to the CPPFLAGS of programs that aren't doing it
right.

> >>> Should the headers be filled with feature checks (that would make them
> >>> quite ugly) or assume we have _GNU_SOURCE defined and remove any
> >>> _GNU_SOURCE
> >>> checks?
> >>
> >> I'm confused what you mean by "assume we have _GNU_SOURCE defined".
> > 
> > Well, ignore my suggestion. I was thinking of removing most _GNU_SOURCE
> > checks in headers (except for pure GNU extensions) but reading what you
> > wrote above I remembered what PITA feature_macros were. Unfortunately
> > it seems that defining _GNU_SOURCE to get the kitchen sink is easier...
> 
> It's also wrong.  And it means that Musl can't build code that not just
> glibc and uClibc can build out of the box, but BSD can too.  (chroot()
> was _not_ invented by the gnu/dammit project.)

It's not my intent to imply that any of these features were invented
by the GNU project. Rather, _GNU_SOURCE is simply the only existing
feature test macro for "kitchen sink" that exists on Linux systems.
(Blame glibc for naming it this rather than _LINUX_SOURCE!) As such,
existing real-world software that's conforming to the standards and
using _POSIX_C_SOURCE or _XOPEN_SOURCE is already testing for the
availability of _GNU_SOURCE and adding that when it wants the kitchen
sink. While using a different name would be *cosmetically* better, it
would simply have the effect of making you add -D_BETTER_NAME_HERE to
all apps' CPPFLAGS since they'd no longer be able to find a working
option themselves...

> The feature test macros actually means that musl goes out of its _way_
> not to build them. You have extra code that's just there to break stuff.

One could also say that not having the internals of FILE defined in
stdio.h, and not using the same struct member names as glibc, is
"going out of its way" to break stuff...

In any case, the feature test macro issue is easily solved, if you
always want full extensions, by just using "CC=gcc -D_GNU_SOURCE".

If there's demand for a way to do this without ever having to write
that dirty word "GNU", we could consider adding an alias..

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.