From: James Y Knight <jyknight@google.com>
To: musl@lists.openwall.com
Subject: Re: [PATCH] Define NULL as __null in C++ mode when using GCC or Clang.
Date: Wed, 10 Jul 2019 12:01:17 -0400 [thread overview]
Message-ID: <CAA2zVHop_6g+piZxCoSHTy9ODhyZP4FdNPdbC8nYXhb6nscyag@mail.gmail.com> (raw)
In-Reply-To: <20190710020357.GI21055@port70.net>
[-- Attachment #1: Type: text/plain, Size: 5696 bytes --]
On Tue, Jul 9, 2019 at 10:04 PM Szabolcs Nagy <nsz@port70.net> wrote:
> * James Y Knight <jyknight@google.com> [2019-07-09 19:04:13 -0400]:
> > On Tue, Jul 9, 2019 at 3:38 PM Rich Felker <dalias@libc.org> wrote:
> > > On Tue, Jul 09, 2019 at 03:19:00PM -0400, James Y Knight wrote:
> > > > Both GCC and Clang ship their own stddef.h which does this (musl's
> > > > stddef.h is simply ignored). But, musl also defines the macro in a
> > > > number of other headers.
> > >
> > > This was intentional at the time it was done. At least in the present
> > > version of C++ at the time, __null was not a conforming definition.
> > > For example, conforming applications could parse the stringification
> > > of NULL and expect to get something that's a valid null pointer
> > > constant. This could possibly be revisited, if it's changed, and if it
> > > can be done in a way that doesn't involve compiler-specific stuff.
> > >
> >
> > The C++11 standard simply says "The macro NULL is an
> implementation-defined
> > C++ null pointer constant in this International Standard." (and links to
> > the definition of null pointer constant -- "A null pointer constant is an
> > integral constant expression (5.19) prvalue of integer type that
> evaluates
> > to zero or a prvalue of type std::nullptr_t").
> >
> > If the implementation defines __null to be a null pointer constant, which
> > is an integral constant expression of integer type that evaluates to zero
> > (which it does), that seems entirely valid. I see nothing that restricts
> > what it may stringify to.
>
> it is clear that 0L is a conforming definition for all
> conforming c++ compilers.
>
> it is less clear if __null is so in all compilers that
> define __GNUC__.
Sure, it's theoretically possible that some unknown compiler pretends to be
GCC, but then implements __null incorrectly. But if it does, why does musl
care? A conforming C++ implementation certainly requires a great many
components to be implemented correctly, not least of which is the compiler.
so normally one would expect a compelling reason to do
such change.
The warning when you're using NULL as a "long" instead of a pointer is a
very important warning -- so important it's on by default without any
warning flags. It's _extremely_ surprising behavior for most developers
that foo(NULL) can call a foo(long) overload in preference to a foo(int*)
overload. This is why the compiler went to the trouble of implementing
__null in the first place. It's only somewhat less important, now that
'nullptr' is becoming more prevalent.
> > > Mostly, getting musl's definition simply degrades warning diagnostics
>
> > > in C++ slightly -- e.g. GCC can no longer emit this warning:
> > > > warning: passing NULL to non-pointer argument 1 of 'int foo(long
> int)'
> > > > [-Wconversion-null]
> > >
> > > The current definition however catches bugs where NULL is wrongly used
> > > to terminate a variadic argument list where (void*)0 or (char*)0 is
> > > actually needed. See commits 41d7c77d6a2e74294807d35062e4cd1d48ab72d3
> > > and c8a9c22173f485c8c053709e1dfa0a617cb6be1a. So both choices are a
> > > tradeoff in diagnostic capability.
> >
> >
> > Ehh. Actually musl's definition actually breaks the intended semantics of
> > that warning as well. The following program:
> > #include <unistd.h>
> > int main() {
> > execl("foo", "bar", NULL);
> > }
> > does indeed not warn with "g++ -Wall foo.cc" when NULL is __null, and it
> > does warn if NULL is 0L.
> >
> > However, it was an intentional choice, not an accident, to suppress the
> > warning in the former case. This kind of usage is widespread,, and in
> > practice it does not trigger buggy behavior (because __null is guaranteed
> > to be the same size as a pointer). GCC does have a separate
> > "-Wstrict-null-sentinel" warning flag, if you want to be more pedantic
> > about this not-standards-compliant code.
>
> if a variadic function implementation calls va_arg(ap,char*)
> on a NULL argument then the behaviour is undefined in c++,
> but it is well-defined in posix! so the pattern is legitimately
> widespread but users often mistakenly compile c code as c++.
>
While it's not defined by C++, I do not believe there are any platforms GCC
or Clang supports where passing __null to a varargs function instead of
(void*)0 causes a problem. The intent is certainly that it's in-practice
safe to use as a varargs-terminator, by being defined to be the correct
size.
> how can we ensure that an optimizing c++ compiler won't
> silently break such code? gcc rutinely eliminates code if
> it can spot that a null pointer is passed to a library
> function where that is undefined.
not diagnosing such correctness issues when you can is bad
> practice: it leaves around ticking time bombs.
There's always a trade-off between which warnings should be enabled by
default or in -Wall. If this were an _actual_ codegen problem, for sure
-Wstrict-null-sentinel should be enabled by default. However, as a
very-common idiom which does not cause an actual problem, having this not
emit a warning in the default flag sets seems justifiable.
> (the warnings __null can provide are rarely time bombs)
>
Without the warning, developers may not realize that the wrong overload is
being called. And maybe their software is working anyways, for whatever
reason -- until someone converts NULL to nullptr, causing an unexpected
behavior change.
> but i think NULL is dangerously broken in c++ either way,
> so both the current and the proposed definition is fine by me,
> i just slightly prefer the current definition.
>
I think everyone agrees NULL is broken in C++, which is why we now have
nullptr.
[-- Attachment #2: Type: text/html, Size: 8029 bytes --]
prev parent reply other threads:[~2019-07-10 16:01 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-09 19:19 James Y Knight
2019-07-09 19:38 ` Rich Felker
2019-07-09 23:04 ` James Y Knight
2019-07-10 2:03 ` Szabolcs Nagy
2019-07-10 6:34 ` Florian Weimer
2019-07-10 8:46 ` Szabolcs Nagy
2019-07-10 16:18 ` James Y Knight
2019-07-10 16:44 ` Rich Felker
2019-07-10 17:35 ` James Y Knight
2019-07-10 20:11 ` A. Wilcox
2019-07-10 20:19 ` Michael Everitt
2019-07-10 20:45 ` Rich Felker
2019-07-10 20:48 ` Rich Felker
2019-07-10 21:11 ` Szabolcs Nagy
2019-07-10 21:16 ` Rich Felker
2019-07-10 21:44 ` Szabolcs Nagy
2019-07-10 16:01 ` James Y Knight [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAA2zVHop_6g+piZxCoSHTy9ODhyZP4FdNPdbC8nYXhb6nscyag@mail.gmail.com \
--to=jyknight@google.com \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).