Bug 92267 - [9 Regression] crash with a cppunit test case (built by GCC 9) and cpptest (built with GCC 8)
Summary: [9 Regression] crash with a cppunit test case (built by GCC 9) and cpptest (b...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 9.2.1
: P3 normal
Target Milestone: 9.3
Assignee: Jonathan Wakely
URL:
Keywords: ABI
Depends on:
Blocks:
 
Reported: 2019-10-29 13:32 UTC by Matthias Klose
Modified: 2020-02-25 17:44 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work: 8.3.0
Known to fail: 10.0, 9.2.0
Last reconfirmed: 2019-10-29 00:00:00


Attachments
abigail for cppunit (1.21 KB, text/plain)
2019-10-29 13:32 UTC, Matthias Klose
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2019-10-29 13:32:39 UTC
Created attachment 47126 [details]
abigail for cppunit

having a cppunit built with GCC 8, and building the testcase with GCC 9 crashes. Rebuild cppunit with GCC 9 as well, then the test runs as expected.

$ cat foo.cc
#include <stack>
#include <string>
#include <cppunit/TestAssert.h>

class X {
private:
        std::stack<std::string> s1;
        std::stack<unsigned int> s2;
};

int
main(int argc, char *argv[]) {
        X *x = new X();
//      delete x;
        std::string r;
        CPPUNIT_ASSERT(r.empty());
        return 0;
}
Comment 1 Jonathan Wakely 2019-10-29 13:43:39 UTC
Preprocessing with GCC 8 and then compiling with GCC 9 doesn't crash, so it's due to a change in libstdc++ headers.
Comment 2 Jonathan Wakely 2019-10-29 14:04:51 UTC
Seems to be due to r260380
Comment 3 Jonathan Wakely 2019-10-29 14:10:10 UTC
This change (to prevent a -Wdeprecated-copy warning) changes the copy constructor from non-trivial to trivial:

+#if __cplusplus < 201103L
+      // Conversion from iterator to const_iterator.
       _Deque_iterator(const iterator& __x) _GLIBCXX_NOEXCEPT
       : _M_cur(__x._M_cur), _M_first(__x._M_first),
        _M_last(__x._M_last), _M_node(__x._M_node) { }
+#else
+      // Conversion from iterator to const_iterator.
+      template<typename _Iter,
+              typename = _Require<is_same<_Self, const_iterator>,
+                                  is_same<_Iter, iterator>>>
+       _Deque_iterator(const _Iter& __x) noexcept
+       : _M_cur(__x._M_cur), _M_first(__x._M_first),
+         _M_last(__x._M_last), _M_node(__x._M_node) { }
+
+      _Deque_iterator(const _Deque_iterator&) = default;
+      _Deque_iterator& operator=(const _Deque_iterator&) = default;
+#endif

The fix is to define the copy constructor explicitly again:

-      _Deque_iterator(const _Deque_iterator&) = default;
+      _Deque_iterator(const _Deque_iterator& __x) noexcept
+       : _M_cur(__x._M_cur), _M_first(__x._M_first),
+        _M_last(__x._M_last), _M_node(__x._M_node) { }
+
Comment 4 Jonathan Wakely 2019-10-29 17:15:28 UTC
Author: redi
Date: Tue Oct 29 17:14:55 2019
New Revision: 277577

URL: https://gcc.gnu.org/viewcvs?rev=277577&root=gcc&view=rev
Log:
PR libstdc++/92267 fix ABI change in deque iterators

Defaulting the copy constructor on its first declaration made it change
from user-provided (and non-trivial) to implicitly-defined (and
trivial). This caused an ABI incompatibility between GCC 8 and GCC 9,
where functions taking a deque iterator disagree on the argument passing
convention.

	PR libstdc++/92267
	* include/bits/stl_deque.h (_Deque_iterator(const _Deque_iterator&)):
	Do not define as defaulted.
	* testsuite/23_containers/deque/types/92267.cc: New test.

Added:
    trunk/libstdc++-v3/testsuite/23_containers/deque/types/92267.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/stl_deque.h
Comment 5 Marek Polacek 2019-11-21 22:23:39 UTC
Can this be backported to 9 now, please?
Comment 6 Jonathan Wakely 2019-11-22 12:36:20 UTC
Done!
Comment 7 Jonathan Wakely 2019-11-22 12:36:50 UTC
Author: redi
Date: Fri Nov 22 12:36:18 2019
New Revision: 278614

URL: https://gcc.gnu.org/viewcvs?rev=278614&root=gcc&view=rev
Log:
PR libstdc++/92267 fix ABI change in deque iterators

Defaulting the copy constructor on its first declaration made it change
from user-provided (and non-trivial) to implicitly-defined (and
trivial). This caused an ABI incompatibility between GCC 8 and GCC 9,
where functions taking a deque iterator disagree on the argument passing
convention.

Backport from mainline
2019-10-29  Jonathan Wakely  <jwakely@redhat.com>

	PR libstdc++/92267
	* include/bits/stl_deque.h (_Deque_iterator(const _Deque_iterator&)):
	Do not define as defaulted.
	* testsuite/23_containers/deque/types/92267.cc: New test.

Added:
    branches/gcc-9-branch/libstdc++-v3/testsuite/23_containers/deque/types/92267.cc
Modified:
    branches/gcc-9-branch/libstdc++-v3/ChangeLog
    branches/gcc-9-branch/libstdc++-v3/include/bits/stl_deque.h
Comment 8 Romain Geissler 2020-02-25 17:10:45 UTC
Hi Jonathan,

Sorry to jump back into this old bug, but isn't it a issue that this was backported to gcc 9 after some releases of gcc 9 were in the wild yet ?

I mean, someone having built some binaries with gcc 9.1.0 or 9.2.0, mixing it later with a binary built with the upcoming gcc 9.3.0 will also see a similar crash, no ? I think (but I am not sure yet) this is actually happening to me (although I am not using gcc releases, but directly compile from git from gcc-9-branch, so I understand my right to complain is low, if not non legit at all). What is advocated in this case, that all binaries build with gcc 9.1.0 or 9.2.0 shall be rebuilt as well ? Or is there any way that somehow the gcc 9 branch (and not gcc 10 one) can support both ABIs to cope with past mistakes ?

Cheers,
Romain
Comment 9 Jonathan Wakely 2020-02-25 17:15:41 UTC
(In reply to Romain Geissler from comment #8)
> Sorry to jump back into this old bug, but isn't it a issue that this was
> backported to gcc 9 after some releases of gcc 9 were in the wild yet ?

Yes. The choice was to accept a break and say "starting with GCC 9 there's an ABI break, nothing before 9 is compatible with anything after that" or to consider 9.1.0 and 9.2.0 to be buggy and fix the mistake for 9.3.0.


> I mean, someone having built some binaries with gcc 9.1.0 or 9.2.0, mixing
> it later with a binary built with the upcoming gcc 9.3.0 will also see a
> similar crash, no ? I think (but I am not sure yet) this is actually
> happening to me (although I am not using gcc releases, but directly compile
> from git from gcc-9-branch, so I understand my right to complain is low, if
> not non legit at all). What is advocated in this case, that all binaries
> build with gcc 9.1.0 or 9.2.0 shall be rebuilt as well ? Or is there any way
> that somehow the gcc 9 branch (and not gcc 10 one) can support both ABIs to
> cope with past mistakes ?

I'm not aware of any way to make that work.

Once GCC 9.3.0 is released the solution is to upgrade to 9.3.0 and consider 9.1.0 and 9.2.0 to have a bug. If that bug affects you, you'll need to rebuild code built with those versions.
Comment 10 Romain Geissler 2020-02-25 17:41:12 UTC
Ok, I was not sure whether it was more important to have a given major branch (ie all gcc 9 releases) consistent or favor compatibility with the biggest number of gcc releases (cross branches). You replied to that.

Do you think this shall be somehow be listed as a known issue in the gcc 9 release notes https://gcc.gnu.org/gcc-9/changes.html ?
Comment 11 Jonathan Wakely 2020-02-25 17:44:39 UTC
Yes, I should add it there.