libstdc++: Another attempt to ensure g++ 13+ compiled programs enforce gcc 13.2+ libstdc++.so.6 [PR108969]

Message ID ZEt3EFFjFUijaFFx@tucnak
State Unresolved
Headers
Series libstdc++: Another attempt to ensure g++ 13+ compiled programs enforce gcc 13.2+ libstdc++.so.6 [PR108969] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek April 28, 2023, 7:34 a.m. UTC
  Hi!

GCC used to emit an instance of an empty ios_base::Init class in
every TU which included <iostream> to ensure it is std::cout etc.
is initialized, but thanks to Patrick work on some targets (which have
init_priority attribute support) it is now initialized only inside of
libstdc++.so.6/libstdc++.a.

This causes a problem if people do something that has never been supported,
try to run GCC 13 compiled C++ code against GCC 12 or earlier
libstdc++.so.6 - std::cout etc. are then never initialized because code
including <iostream> expects the library to initialize it and the library
expects code including <iostream> to do that.

The following patch is second attempt to make this work cheaply as the
earlier attempt of aliasing the std::cout etc. symbols with another symbol
version didn't work out due to copy relocation breaking the aliases appart.

The patch forces just a _ZSt21ios_base_library_initv undefined symbol
into all *.o files which include <iostream> and while there is no runtime
relocation against that, it seems to enforce the right version of
libstdc++.so.6.  /home/jakub/src/gcc/obj08i/usr/local/ is the install
directory of trunk patched with this patch, /home/jakub/src/gcc/obj06/
is builddir of trunk without this patch, system g++ is GCC 12.1.1.
$ cat /tmp/hw.C
#include <iostream>

int
main ()
{
  std::cout << "Hello, world!" << std::endl;
}
$ cd /home/jakub/src/gcc/obj08i/usr/local/bin
$ ./g++ -o /tmp/hw /tmp/hw.C
$ readelf -Wa /tmp/hw 2>/dev/null | grep initv
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZSt21ios_base_library_initv@GLIBCXX_3.4.32 (4)
    71: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZSt21ios_base_library_initv@GLIBCXX_3.4.32
$ /tmp/hw
/tmp/hw: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /tmp/hw)
$ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj08i/usr/local/lib64/ /tmp/hw
Hello, world!
$ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/ /tmp/hw
/tmp/hw: /home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /tmp/hw)
$ g++ -o /tmp/hw /tmp/hw.C
$ /tmp/hw
Hello, world!
$ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/ /tmp/hw
Hello, world!
$ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj08i/usr/local/lib64/ /tmp/hw
Hello, world!

Bootstrapped/regtested on x86_64-linux, i686-linux and sparc-sun-solaris2.11

On the last one I've actually checked a version which had
defined(_GLIBCXX_SYMVER_SUN) next to defined(_GLIBCXX_SYMVER_GNU), but
init_priority attribute doesn't seem to be supported there and so I couldn't
actually test how this works there.  Using gas and Sun ld, Rainer, does one
need to use gas + gld for init_priority or something else?

Ok for trunk and after a while for GCC 13.2?

2023-04-28  Jakub Jelinek  <jakub@redhat.com>

	PR libstdc++/108969
	* config/abi/pre/gnu.ver (GLIBCXX_3.4.32): Export
	_ZSt21ios_base_library_initv.
	* testsuite/util/testsuite_abi.cc (check_version): Add GLIBCXX_3.4.32
	symver and make it the latestp.
	* src/c++98/ios_init.cc (ios_base_library_init): New alias.
	* acinclude.m4 (libtool_VERSION): Change to 6:32:0.
	* include/std/iostream: If init_priority attribute is supported
	and _GLIBCXX_SYMVER_GNU, force undefined _ZSt21ios_base_library_initv
	symbol into the object.
	* configure: Regenerated.


	Jakub
  

Comments

Jonathan Wakely April 28, 2023, 8:35 a.m. UTC | #1
On Fri, 28 Apr 2023 at 08:34, Jakub Jelinek <jakub@redhat.com> wrote:

> Hi!
>
> GCC used to emit an instance of an empty ios_base::Init class in
> every TU which included <iostream> to ensure it is std::cout etc.
> is initialized, but thanks to Patrick work on some targets (which have
> init_priority attribute support) it is now initialized only inside of
> libstdc++.so.6/libstdc++.a.
>
> This causes a problem if people do something that has never been supported,
> try to run GCC 13 compiled C++ code against GCC 12 or earlier
> libstdc++.so.6 - std::cout etc. are then never initialized because code
> including <iostream> expects the library to initialize it and the library
> expects code including <iostream> to do that.
>
> The following patch is second attempt to make this work cheaply as the
> earlier attempt of aliasing the std::cout etc. symbols with another symbol
> version didn't work out due to copy relocation breaking the aliases appart.
>
> The patch forces just a _ZSt21ios_base_library_initv undefined symbol
> into all *.o files which include <iostream> and while there is no runtime
> relocation against that, it seems to enforce the right version of
> libstdc++.so.6.  /home/jakub/src/gcc/obj08i/usr/local/ is the install
> directory of trunk patched with this patch, /home/jakub/src/gcc/obj06/
> is builddir of trunk without this patch, system g++ is GCC 12.1.1.
> $ cat /tmp/hw.C
> #include <iostream>
>
> int
> main ()
> {
>   std::cout << "Hello, world!" << std::endl;
> }
> $ cd /home/jakub/src/gcc/obj08i/usr/local/bin
> $ ./g++ -o /tmp/hw /tmp/hw.C
> $ readelf -Wa /tmp/hw 2>/dev/null | grep initv
>      4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND
> _ZSt21ios_base_library_initv@GLIBCXX_3.4.32 (4)
>     71: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND
> _ZSt21ios_base_library_initv@GLIBCXX_3.4.32
> $ /tmp/hw
> /tmp/hw: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.32' not found
> (required by /tmp/hw)
> $ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj08i/usr/local/lib64/ /tmp/hw
> Hello, world!
> $
> LD_LIBRARY_PATH=/home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/
> /tmp/hw
> /tmp/hw:
> /home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6:
> version `GLIBCXX_3.4.32' not found (required by /tmp/hw)
> $ g++ -o /tmp/hw /tmp/hw.C
> $ /tmp/hw
> Hello, world!
> $
> LD_LIBRARY_PATH=/home/jakub/src/gcc/obj06/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/
> /tmp/hw
> Hello, world!
> $ LD_LIBRARY_PATH=/home/jakub/src/gcc/obj08i/usr/local/lib64/ /tmp/hw
> Hello, world!
>
> Bootstrapped/regtested on x86_64-linux, i686-linux and
> sparc-sun-solaris2.11
>
> On the last one I've actually checked a version which had
> defined(_GLIBCXX_SYMVER_SUN) next to defined(_GLIBCXX_SYMVER_GNU), but
> init_priority attribute doesn't seem to be supported there and so I
> couldn't
> actually test how this works there.  Using gas and Sun ld, Rainer, does one
> need to use gas + gld for init_priority or something else?
>
> Ok for trunk and after a while for GCC 13.2?
>

Yes, for both, thanks for the fix.

After it lands on the gcc-13 branch I'll also update the manual with:

--- a/libstdc++-v3/doc/xml/manual/abi.xml
+++ b/libstdc++-v3/doc/xml/manual/abi.xml
@@ -275,6 +275,7 @@ compatible.
    <listitem><para>GCC 11.1.0: libstdc++.so.6.0.29</para></listitem>
    <listitem><para>GCC 12.1.0: libstdc++.so.6.0.30</para></listitem>
    <listitem><para>GCC 13.1.0: libstdc++.so.6.0.31</para></listitem>
+    <listitem><para>GCC 13.2.0: libstdc++.so.6.0.32</para></listitem>
    </itemizedlist>
    <para>
      Note 1: Error should be libstdc++.so.3.0.3.




>
> 2023-04-28  Jakub Jelinek  <jakub@redhat.com>
>
>         PR libstdc++/108969
>         * config/abi/pre/gnu.ver (GLIBCXX_3.4.32): Export
>         _ZSt21ios_base_library_initv.
>         * testsuite/util/testsuite_abi.cc (check_version): Add
> GLIBCXX_3.4.32
>         symver and make it the latestp.
>         * src/c++98/ios_init.cc (ios_base_library_init): New alias.
>         * acinclude.m4 (libtool_VERSION): Change to 6:32:0.
>         * include/std/iostream: If init_priority attribute is supported
>         and _GLIBCXX_SYMVER_GNU, force undefined
> _ZSt21ios_base_library_initv
>         symbol into the object.
>         * configure: Regenerated.
>
> --- libstdc++-v3/config/abi/pre/gnu.ver.jj      2023-04-20
> 09:36:09.415371050 +0200
> +++ libstdc++-v3/config/abi/pre/gnu.ver 2023-04-27 17:58:44.599675359 +0200
> @@ -2514,6 +2514,10 @@ GLIBCXX_3.4.31 {
>
>  } GLIBCXX_3.4.30;
>
> +GLIBCXX_3.4.32 {
> +    _ZSt21ios_base_library_initv;
> +} GLIBCXX_3.4.31;
> +
>  # Symbols in the support library (libsupc++) have their own tag.
>  CXXABI_1.3 {
>
> --- libstdc++-v3/testsuite/util/testsuite_abi.cc.jj     2023-01-16
> 11:52:17.495713257 +0100
> +++ libstdc++-v3/testsuite/util/testsuite_abi.cc        2023-04-27
> 17:30:39.651173917 +0200
> @@ -213,6 +213,7 @@ check_version(symbol& test, bool added)
>        known_versions.push_back("GLIBCXX_LDBL_3.4.29");
>        known_versions.push_back("GLIBCXX_3.4.30");
>        known_versions.push_back("GLIBCXX_3.4.31");
> +      known_versions.push_back("GLIBCXX_3.4.32");
>        known_versions.push_back("GLIBCXX_LDBL_3.4.31");
>        known_versions.push_back("GLIBCXX_IEEE128_3.4.29");
>        known_versions.push_back("GLIBCXX_IEEE128_3.4.30");
> @@ -251,7 +252,7 @@ check_version(symbol& test, bool added)
>         test.version_status = symbol::incompatible;
>
>        // Check that added symbols are added in the latest pre-release
> version.
> -      bool latestp = (test.version_name == "GLIBCXX_3.4.31"
> +      bool latestp = (test.version_name == "GLIBCXX_3.4.32"
>           // XXX remove next 2 lines when baselines have been regenerated.
>                      || test.version_name == "GLIBCXX_IEEE128_3.4.31"
>                      || test.version_name == "GLIBCXX_LDBL_3.4.31"
> --- libstdc++-v3/src/c++98/ios_init.cc.jj       2023-01-16
> 11:52:16.995720625 +0100
> +++ libstdc++-v3/src/c++98/ios_init.cc  2023-04-27 18:34:46.121276617 +0200
> @@ -199,5 +199,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      return __ret;
>    }
>
> +#ifdef _GLIBCXX_SYMVER_GNU
> +  void ios_base_library_init (void)
> +  __attribute__((alias ("_ZNSt8ios_base4InitC1Ev")));
> +#endif
> +
>  _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace
> --- libstdc++-v3/acinclude.m4.jj        2023-02-02 09:53:31.745525704 +0100
> +++ libstdc++-v3/acinclude.m4   2023-04-27 17:27:51.071626279 +0200
> @@ -3841,7 +3841,7 @@ changequote([,])dnl
>  fi
>
>  # For libtool versioning info, format is CURRENT:REVISION:AGE
> -libtool_VERSION=6:31:0
> +libtool_VERSION=6:32:0
>
>  # Everything parsed; figure out what files and settings to use.
>  case $enable_symvers in
> --- libstdc++-v3/include/std/iostream.jj        2023-01-16
> 11:52:16.968721023 +0100
> +++ libstdc++-v3/include/std/iostream   2023-04-27 18:34:07.479837226 +0200
> @@ -77,6 +77,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    // in the compiled library instead (src/c++98/globals_io.cc).
>  #if !__has_attribute(__init_priority__)
>    static ios_base::Init __ioinit;
> +#elif defined(_GLIBCXX_SYMVER_GNU)
> +  __extension__ __asm (".globl _ZSt21ios_base_library_initv");
>  #endif
>
>  _GLIBCXX_END_NAMESPACE_VERSION
> --- libstdc++-v3/configure.jj   2023-02-02 09:53:31.795524981 +0100
> +++ libstdc++-v3/configure      2023-04-27 17:29:13.263429963 +0200
> @@ -68652,7 +68652,7 @@ $as_echo "$as_me: WARNING: === Symbol ve
>  fi
>
>  # For libtool versioning info, format is CURRENT:REVISION:AGE
> -libtool_VERSION=6:31:0
> +libtool_VERSION=6:32:0
>
>  # Everything parsed; figure out what files and settings to use.
>  case $enable_symvers in
>
>         Jakub
>
>
  
Jakub Jelinek April 28, 2023, 10:02 p.m. UTC | #2
On Fri, Apr 28, 2023 at 09:35:49AM +0100, Jonathan Wakely wrote:
> Yes, for both, thanks for the fix.
> 
> After it lands on the gcc-13 branch I'll also update the manual with:
> 
> --- a/libstdc++-v3/doc/xml/manual/abi.xml
> +++ b/libstdc++-v3/doc/xml/manual/abi.xml
> @@ -275,6 +275,7 @@ compatible.
>     <listitem><para>GCC 11.1.0: libstdc++.so.6.0.29</para></listitem>
>     <listitem><para>GCC 12.1.0: libstdc++.so.6.0.30</para></listitem>
>     <listitem><para>GCC 13.1.0: libstdc++.so.6.0.31</para></listitem>
> +    <listitem><para>GCC 13.2.0: libstdc++.so.6.0.32</para></listitem>
>     </itemizedlist>
>     <para>
>       Note 1: Error should be libstdc++.so.3.0.3.

Don't you need to change later parts too?
I mean adding
  GCC 13.2.0: GLIBCXX_3.4.32, CXXABI_1.3.14
entry.

	Jakub
  
Rainer Orth May 2, 2023, 11:20 a.m. UTC | #3
Hi Jakub,

> Bootstrapped/regtested on x86_64-linux, i686-linux and sparc-sun-solaris2.11
>
> On the last one I've actually checked a version which had
> defined(_GLIBCXX_SYMVER_SUN) next to defined(_GLIBCXX_SYMVER_GNU), but
> init_priority attribute doesn't seem to be supported there and so I couldn't
> actually test how this works there.  Using gas and Sun ld, Rainer, does one
> need to use gas + gld for init_priority or something else?

it's complicated, as usual ;-)  While Solaris 11.3 ld has basic
.init_priority etc. support, it doesn't know about priorities, so the
support is disabled.  This is what you see on gcc211 in the cfarm.

Solaris 11.4 ld on the other hand added everything to make the configure
test work, so HAVE_INITFINI_ARRAY_SUPPORT is enabled.  Unfortunately,
there's still PR c++/52477 (dup of PR c++/81337) where g++ makes
unwarranted assumptions which happen to hold on Linux/glibc (only?), but
often break other targets (Solaris, Darwin, FreeBSD) in unexpected
places (like libsanitizer).  I've made at least two attempts at a fix
which got me nowhere, so I'm considering disabling
HAVE_INITFINI_ARRAY_SUPPORT on Solaris for good.  This is purely a g++
issue, clang++ gets this right.

	Rainer
  
Jonathan Wakely May 2, 2023, 3:43 p.m. UTC | #4
On Fri, 28 Apr 2023 at 23:02, Jakub Jelinek <jakub@redhat.com> wrote:

> On Fri, Apr 28, 2023 at 09:35:49AM +0100, Jonathan Wakely wrote:
> > Yes, for both, thanks for the fix.
> >
> > After it lands on the gcc-13 branch I'll also update the manual with:
> >
> > --- a/libstdc++-v3/doc/xml/manual/abi.xml
> > +++ b/libstdc++-v3/doc/xml/manual/abi.xml
> > @@ -275,6 +275,7 @@ compatible.
> >     <listitem><para>GCC 11.1.0: libstdc++.so.6.0.29</para></listitem>
> >     <listitem><para>GCC 12.1.0: libstdc++.so.6.0.30</para></listitem>
> >     <listitem><para>GCC 13.1.0: libstdc++.so.6.0.31</para></listitem>
> > +    <listitem><para>GCC 13.2.0: libstdc++.so.6.0.32</para></listitem>
> >     </itemizedlist>
> >     <para>
> >       Note 1: Error should be libstdc++.so.3.0.3.
>
> Don't you need to change later parts too?
> I mean adding
>   GCC 13.2.0: GLIBCXX_3.4.32, CXXABI_1.3.14
> entry.
>

Yep, and regenerate the HTML versions.
  

Patch

--- libstdc++-v3/config/abi/pre/gnu.ver.jj	2023-04-20 09:36:09.415371050 +0200
+++ libstdc++-v3/config/abi/pre/gnu.ver	2023-04-27 17:58:44.599675359 +0200
@@ -2514,6 +2514,10 @@  GLIBCXX_3.4.31 {
 
 } GLIBCXX_3.4.30;
 
+GLIBCXX_3.4.32 {
+    _ZSt21ios_base_library_initv;
+} GLIBCXX_3.4.31;
+
 # Symbols in the support library (libsupc++) have their own tag.
 CXXABI_1.3 {
 
--- libstdc++-v3/testsuite/util/testsuite_abi.cc.jj	2023-01-16 11:52:17.495713257 +0100
+++ libstdc++-v3/testsuite/util/testsuite_abi.cc	2023-04-27 17:30:39.651173917 +0200
@@ -213,6 +213,7 @@  check_version(symbol& test, bool added)
       known_versions.push_back("GLIBCXX_LDBL_3.4.29");
       known_versions.push_back("GLIBCXX_3.4.30");
       known_versions.push_back("GLIBCXX_3.4.31");
+      known_versions.push_back("GLIBCXX_3.4.32");
       known_versions.push_back("GLIBCXX_LDBL_3.4.31");
       known_versions.push_back("GLIBCXX_IEEE128_3.4.29");
       known_versions.push_back("GLIBCXX_IEEE128_3.4.30");
@@ -251,7 +252,7 @@  check_version(symbol& test, bool added)
 	test.version_status = symbol::incompatible;
 
       // Check that added symbols are added in the latest pre-release version.
-      bool latestp = (test.version_name == "GLIBCXX_3.4.31"
+      bool latestp = (test.version_name == "GLIBCXX_3.4.32"
 	  // XXX remove next 2 lines when baselines have been regenerated.
 		     || test.version_name == "GLIBCXX_IEEE128_3.4.31"
 		     || test.version_name == "GLIBCXX_LDBL_3.4.31"
--- libstdc++-v3/src/c++98/ios_init.cc.jj	2023-01-16 11:52:16.995720625 +0100
+++ libstdc++-v3/src/c++98/ios_init.cc	2023-04-27 18:34:46.121276617 +0200
@@ -199,5 +199,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     return __ret;
   }
 
+#ifdef _GLIBCXX_SYMVER_GNU
+  void ios_base_library_init (void)
+  __attribute__((alias ("_ZNSt8ios_base4InitC1Ev")));
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
--- libstdc++-v3/acinclude.m4.jj	2023-02-02 09:53:31.745525704 +0100
+++ libstdc++-v3/acinclude.m4	2023-04-27 17:27:51.071626279 +0200
@@ -3841,7 +3841,7 @@  changequote([,])dnl
 fi
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:31:0
+libtool_VERSION=6:32:0
 
 # Everything parsed; figure out what files and settings to use.
 case $enable_symvers in
--- libstdc++-v3/include/std/iostream.jj	2023-01-16 11:52:16.968721023 +0100
+++ libstdc++-v3/include/std/iostream	2023-04-27 18:34:07.479837226 +0200
@@ -77,6 +77,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // in the compiled library instead (src/c++98/globals_io.cc).
 #if !__has_attribute(__init_priority__)
   static ios_base::Init __ioinit;
+#elif defined(_GLIBCXX_SYMVER_GNU)
+  __extension__ __asm (".globl _ZSt21ios_base_library_initv");
 #endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
--- libstdc++-v3/configure.jj	2023-02-02 09:53:31.795524981 +0100
+++ libstdc++-v3/configure	2023-04-27 17:29:13.263429963 +0200
@@ -68652,7 +68652,7 @@  $as_echo "$as_me: WARNING: === Symbol ve
 fi
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:31:0
+libtool_VERSION=6:32:0
 
 # Everything parsed; figure out what files and settings to use.
 case $enable_symvers in