glibc 2.15 and later don't declare gets anymore for ISO C11 mode and if _GNU_SOURCE is defined. This causes problems with the cstdio header which unconditionally uses using ::gets; Something has to be done about this. If you want glibc to define a macro to signal that gets is not declared let me know. Otherwise recognize __USE_GNU. The problem still applies to the trunk.
I thought this was fixed in glibc: http://sourceware.org/bugzilla/show_bug.cgi?id=13566 ?
(In reply to comment #1) > I thought this was fixed in glibc: > http://sourceware.org/bugzilla/show_bug.cgi?id=13566 > ? AFAIU GLIBC BZ #13528 was fixed, but there is a new checkin from Ulrich which breaks libstdc++ build in a similar way: ... $ git show c3a87236702cb73be1dada3438bbd3c3934e83f8 commit c3a87236702cb73be1dada3438bbd3c3934e83f8 Author: Ulrich Drepper <drepper@gmail.com> Date: Sat Jan 7 10:41:00 2012 -0500 Do not declare gets in _GNU_SOURCE mode at all diff --git a/ChangeLog b/ChangeLog index 8f9558c..f089e19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2012-01-07 Ulrich Drepper <drepper@gmail.com> + * libio/stdio.h: Do not declare gets at all for _GNU_SOURCE. + * elf/tst-unique3.cc: Add explicit declaration of gets. * elf/tst-unique3lib.cc: Likewise. * elf/tst-unique3lib2.cc: Likewise. diff --git a/libio/stdio.h b/libio/stdio.h index d9cb573..28c98e9 100644 --- a/libio/stdio.h +++ b/libio/stdio.h @@ -629,7 +629,7 @@ extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream) __wur; #if !defined __USE_ISOC11 \ - || (defined __cplusplus && __cplusplus <= 201103L) + || (defined __cplusplus && __cplusplus <= 201103L && !defined __USE_GNU) /* Get a newline-terminated string from stdin, removing the newline. DO NOT USE THIS FUNCTION!! There is no limit on how much it will read. ...
This attempt at 'a glibc version check and defining the std::gets prototype in libstdc++' (PR 51773 comment 11) unbreaks the libstdc++ build: ... Index: libstdc++-v3/include/c_std/cstdio =================================================================== --- libstdc++-v3/include/c_std/cstdio (revision 183073) +++ libstdc++-v3/include/c_std/cstdio (working copy) @@ -88,6 +88,12 @@ #undef vprintf #undef vsprintf +#if __GLIBC_PREREQ (2,15) +extern "C" { + extern char *gets (char *__s) __attribute__((deprecated)); +} +#endif + namespace std { using ::FILE; Index: libstdc++-v3/include/c_global/cstdio =================================================================== --- libstdc++-v3/include/c_global/cstdio (revision 183073) +++ libstdc++-v3/include/c_global/cstdio (working copy) @@ -89,6 +89,12 @@ #undef vprintf #undef vsprintf +#if __GLIBC_PREREQ (2,15) +extern "C" { + extern char *gets (char *__s) __attribute__((deprecated)); +} +#endif + namespace std { using ::FILE; ...
Thanks - I can't test this myself as I don't have the latest glibc sources but will confirm it and change component to libstdc++ Ulrich, G++ unconditionally defines _GNU_SOURCE so __USE_GNU will always be defined when <cstdio> includes <stdio.h>, so there's no point checking for it. I think Tom's fix is along the right lines, but we probably want to check for the gets() declaration using autoconf and define a _GLIBCXX macro rather than having __GLIBC_PREREQ in the headers, then do: #ifdef _GLIBCXX_NEED_GETS_DECL extern "C" { extern char *gets (char *__s) __attribute__((deprecated)); } #endif At some point we might need to handle the case where the underlying platform doesn't provide gets() at all (e.g. if libstdc++ is used on a platform which only supports C11) but that's not the case for GNU libc and we can worry about that if/when it happens.
If we are just going to declare gets when glibc doesn't, the easiest solution is a fixinclude that reverts Ulrich's latest glibc commit. Somehow that doesn't feel right...
Yeah, IMHO the removal of gets (== ::gets) for _GNU_SOURCE is very much intentional. C++ probably only talks about std::gets, doesn't it? So IMHO then should libstdc++ just for glibc versions that don't provide gets prototype with _GNU_SOURCE defined instead add namespace std { char *gets (char *) __asm ("gets"); };
(In reply to comment #6) > Yeah, IMHO the removal of gets (== ::gets) for _GNU_SOURCE is very much > intentional. C++ probably only talks about std::gets, doesn't it? No, std::gets must be declared by <cstdio> and ::gets must be declared by <stdio.h>
Though personally I'm not concerned if libstdc++ doesn't define gets(), noone should be using it, I am concerned that libstdc++ fails to build because of the using decl.
I ran into this failure today when upgrading my copy of (e)glibc in my cross-environment. What's the best way of progressing this further ? Doesn't this mean that trunk is broken for building with anything later than glibc-2.15 ? Ramana
If the libstdc++ people are going to do something for 4.7, it really needs to be done very soon. Let's assume glibc should at least get a further change for the sake of older GCC versions - changing !defined __USE_GNU to (!defined __USE_GNU || (defined __GNUC__ && !__GNUC_PREREQ (4, 7))). But if this isn't fixed for 4.7, that conditional in stdio.h would need to use __GNUC_PREREQ (4, 8) instead.
If the release managers agree, I would be in favor of a quick fix per Comment 3, with a huge comment in the code explaining the issue. But I can't test it right now.
(In reply to comment #10) > If the libstdc++ people are going to do something for 4.7, it really needs > to be done very soon. The question is: what do the glibc people want? By removing the gets prototype, they are explicitly going against the C++ standard. Seems to me that libstdc++ should respect that choice (add a test in configure to see if gets is provided, and protect "using ::gets;" with #ifdef) and not provide gets. The alternative is to disagree with the glibc developers and fixinclude stdio.h.
I'm ok with #c3 patch + comment if it works, using special configure macro instead of __GLIBC_PREREQ is IMHO undesirable, because then if you build gcc against glibc 2.14 and afterwards upgrade glibc to 2.15, it will suddenly break.
I can confirm that a build for arm-linux-gnueabi completes and do some cross-testing on qemu if that's deemed to be enough. Any other ideas for testing. Ramana Here's a suggestion for the comments in this patch. diff --git a/libstdc++-v3/include/c_global/cstdio b/libstdc++-v3/include/c_global/cstdio index 049704d..76755ac 100644 --- a/libstdc++-v3/include/c_global/cstdio +++ b/libstdc++-v3/include/c_global/cstdio @@ -89,6 +89,17 @@ #undef vprintf #undef vsprintf +/* glibc 2.15 and later do not declare gets anymore for + ISO C11 mode and if __GNU_SOURCE is defined. See + http://gcc.gnu.org/PR51785 for more on this topic. If + this is being changed an equivalent change has to be made + in include/c_std/c_stdio. */ +#if __GLIBC_PREREQ (2,15) +extern "C" { + extern char *gets (char *__s) __attribute__((deprecated)); +} +#endif + namespace std { using ::FILE; diff --git a/libstdc++-v3/include/c_std/cstdio b/libstdc++-v3/include/c_std/cstdio index 510f599..29142bb 100644 --- a/libstdc++-v3/include/c_std/cstdio +++ b/libstdc++-v3/include/c_std/cstdio @@ -88,6 +88,17 @@ #undef vprintf #undef vsprintf +/* glibc 2.15 and later do not declare gets anymore for + ISO C11 mode and if __GNU_SOURCE is defined. See + http://gcc.gnu.org/PR51785 for more on this topic. If + this hunk below is being changed please also investigate + the change for include/c_global/cstdio. */ +#if __GLIBC_PREREQ (2,15) +extern "C" { + extern char *gets (char *__s) __attribute__((deprecated)); +} +#endif + namespace std { using ::FILE;
Ideally, when using #define _GNU_SOURCE #include <stdio.h> in a C++ program ::gets wouldn't be available (the _GNU_SOURCE requests GNU namespace rather than standard C++ one), but when using #include <list> #include <stdio.h> it would provide it (with deprecated attribute), because then the user didn't request _GNU_SOURCE. But for that we'd need some new macro to request additional prototype for STL needs.
I suppose that post 4.7.0 we have to revisit this issue anyway, because C++11 definitely wants to declare std::gets, irrespective of C11. I'm wondering if it would be possible to just take this into account in <stdio.h>, I seem to remember that the glibc headers in a few places already use __cplusplus, right? We also have the __CORRECT_ISO_CPP_STRING_H_PROTO story as an example of interaction between glibc and C++. That said, for 4.7.0, I think that in any case we want: 1- To fully run the testsuite on a GNU/Linux system using glibc2.15; 2- Convince ourselves that whatever we do in the C++ library is not going to interact badly with further tweaks at the glibc level..
2.15 has the gets prototype. It's 2.16 where it has been removed (but the version in the headers only changes from 2.15 to 2.16 when the final 2.16 release is made so you can't distinguish 2.15 from 2.16 development versions simply by examining preprocessor macros).
Ah, thanks Joseph. Thus, to repeat, anything we do in terms of macros has to be for *2.16* and later.
Created attachment 26794 [details] gets conditionally declared/used Here's a way to deal with gets that is pretty simple. If it's around at configure time, it's used. If not, it's dropped from <cstdio>. This uses the same configure bits and approach used for math. This should prevent any compile error at bootstrap time. That seems sufficient for gcc-4.7 release. RMs? Note, I'm on f17 and I'm not running into this during make/check of trunk gcc. If somebody can give me self-contained sources that fail on f17 it would be appreciated. Please don't put in GLIBC macros to cstdio. Boo. Instead, if you need to layer on a glibc part to this, you should start with this patch, and then conditionally define/undefine _GLIBCXX_HAVE_GETS in libstdc++-v3/config/os/gnu-linux/os_defines.h based on the glibc prerequisites and version checks. -benjamin
f17 doesn't include glibc 2.16, just patched glibc 2.15, which doesn't have these header changes yet. The thing I don't like on the last patch is that it hardcodes configure time tests, so when glibc is upgraded say from 2.15 to 2.16, but gcc isn't upgraded, suddenly anything that includes <cstdio> fails to compile. So I'd prefer something like #c14 patch instead, perhaps testing a macro that is depending on __GLIBC_PREREQ defined in linux os-defines.h. Can you please resolve this either way till tomorrow noon UTC (4.7 branching/4.7.0-rc1)? Thanks.
Wouldn't an unconditional #if _GNU_SOURCE extern char *gets (char *__s); using ::gets; #endif work as well? alternatively the FE could provide a language extension that would allow __using_if_available ::gets; ;) Anyway, we don't need to rush anything for 4.7.0, fixing this for 4.7.1 and in a correct way is enough IMHO.
(In reply to comment #21) > Wouldn't an unconditional > > #if _GNU_SOURCE > extern char *gets (char *__s); > using ::gets; > #endif > > work as well? extern "C" or extern "C++" ? What if someone defines _GNU_SOURCE on a non-glibc platform (maybe defined unconditionally in a makefile, expecting it to do nothing) but it causes gets() to be declared with a different language linkage to the one in the system's stdio.h?
Created attachment 26807 [details] gets conditionally declared/used v2 As per Jakub's comments. Since time is an issue I'm going to check this in after regression tests complete.
Author: bkoz Date: Fri Mar 2 07:13:55 2012 New Revision: 184774 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184774 Log: 2012-03-01 Benjamin Kosnik <bkoz@redhat.com> Ramana Radhakrishnan <ramana@gcc.gnu.org> PR libstdc++/51785 * acinclude.m4 (GLIBCXX_CHECK_STDIO_PROTO): New. * configure.ac: Call it. * configure: Regenerate. * config.h.in: Same. * config/os/gnu-linux/os_defines.h: Conditionally undefine _GLIBCXX_HAVE_GETS. * include/c_global/cstdio: Conditionally declare deprecated gets. * include/c_std/cstdio: Same. Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/acinclude.m4 trunk/libstdc++-v3/config.h.in trunk/libstdc++-v3/config/os/gnu-linux/os_defines.h trunk/libstdc++-v3/configure trunk/libstdc++-v3/configure.ac trunk/libstdc++-v3/include/c_global/cstdio trunk/libstdc++-v3/include/c_std/cstdio
extern "C" extern (twice) - too many externs?
The __USE_GNU conditional has now been removed from glibc after further discussion on libc-alpha, so the libstdc++ changes can be reverted (probably after 4.7.0).
Thanks a lot Joseph, a very good solution.
Erm, am I the first to notice that this "solution" is broken? The os_defines.h include that undefines _GLIBCXX_HAVE_GETS is included before _GLIBCXX_HAVE_GETS is (re)defined inside c++config.h. Therefore, _GLIBCXX_HAVE_GETS is still defined when we get to <cstdio>. Seems still to be broken even in trunk.
(In reply to andyg1001 from comment #28) > Erm, am I the first to notice that this "solution" is broken? No, see https://gcc.gnu.org/ml/libstdc++/2016-09/msg00228.html > The os_defines.h include that undefines _GLIBCXX_HAVE_GETS is included > before _GLIBCXX_HAVE_GETS is (re)defined inside c++config.h. > > Therefore, _GLIBCXX_HAVE_GETS is still defined when we get to <cstdio>. > > Seems still to be broken even in trunk. PR 77795 improved things. What's still broken? We need a testcase showing the problem.
Is there anything still broken in supported releases? (i.e. gcc-6 or later)
I don't think there is any thing more to fix here. gets works correctly as far as I Know.