On 20/04/20 07:01 +0200, Helmut Grohne wrote:
The <cmath> and <cstdlib> headers need their counter parts <math.h> and
<stdlib.h> from the libc respectively, but libstdc++ wraps these
headers. Now <cmath> and <cstdlib> include these headers using

$ echo '#include <cstdlib>' | g++ -x c++ -E - -isystem /usr/include >/dev/null
In file included from <stdin>:1:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or 
  75 | #include_next <stdlib.h>
     |               ^~~~~~~~~~
compilation terminated.

What happens here is that g++ includes
libstdc++-v3/include/c_global/cstdlib. That header temporarily #defines
_GLIBCXX_INCLUDE_NEXT_C_HEADERS and then does #include_next <stdlib.h>.
libstdc++-v3's replacement libstdc++-v3/include/c_comaptibility/stdlib.h
happens to come earlier and is not considered.  Unfortunately, the
-isystem above inserted glibc's header before the location containing
<cstdlib>, so the #include_next continues searching and fails to find

Now you are probably going to say that "-isystem /usr/include" is a bad
idea and that you shouldn't do that.


I'm inclined to agree. This isn't a
problem just yet. Debian wants to move /usr/include/stdlib.h to
/usr/include/<multiarch>/stdlib.h. After that move, the problematic flag
becomes "-isystem /usr/include/<multiarch>". Unfortunately, around 30
Debian packages[1] do pass exactly that flag. Regardless whether doing
so is a bad idea, I guess we will have to support that.

Or Debian should fix what they're going to break.

I am proposing to replace those two #include_next with plain #include.
That'll solve the problem described above, but it is not entirely
obvious that doing so doesn't break something else.

After switching those #include_next to #include,
libstdc++-v3/include/c_global/cstdlib will continue to temporarily
will #include <stdlib.h>. Now, it'll search all include directories. It
may find libstdc++-v3/include/c_comaptibility/stdlib.h or the libc's
version. We cannot tell which. If it finds the one from libstdc++-v3,
the header will notice the _GLIBCXX_INCLUDE_NEXT_C_HEADERS macro and
immediately #include_next <stdlib.h> skipping the rest of the header.
That in turn will find the libc version. So in both cases, it ends up
using the right one. Precisely what we wanted.

As Marc said, this doesn't work.

If a program tries to include <stdlib.h> it needs to get the libstdc++
version, otherwise only the libc versions of certain functions are
defined. That means the additional C++ overloads such as ::abs(long)
and ::abs(long long) won't be defined. That is the reason why
libstdc++ provides its own <stdlib.h>.

And if you do -isystem /usr/include (or any other option that causes
libstdc++'s <stdlib.h> to be skipped) that doesn't work. Only
::abs(int) gets defined.

So -isystem /usr/include breaks code, with or without your patch.

Reply via email to