public inbox for gcc-bugs@sourceware.org help / color / mirror / Atom feed
From: "rascmoo at gmail dot com" <gcc-bugzilla@gcc.gnu.org> To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/97273] New: Strange behaviour of unordered_set when vector is included (i686) Date: Fri, 02 Oct 2020 15:00:54 +0000 [thread overview] Message-ID: <bug-97273-4@http.gcc.gnu.org/bugzilla/> (raw) https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97273 Bug ID: 97273 Summary: Strange behaviour of unordered_set when vector is included (i686) Product: gcc Version: 10.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: rascmoo at gmail dot com Target Milestone: --- Created attachment 49302 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=49302&action=edit A few simple source files demonstrating the problem, plus a .ii file generated on my system Hello, I have recently been diagnosing a fault with the 32-bit build of an application, and this has led me to find some strange behaviour with unordered_set, when compiling for 32-bit x86 (i686). I have included an example which demonstrates the behaviour. Consider the following small program: #include <unordered_set> #include <cstdint> uint64_t getBegin(const std::unordered_set<uint64_t> & set) { return *set.begin(); } It returns the first value in a uint64_t unordered_set. This can be compiled into a shared library with the following command: g++ -Wall -Wextra -fpic -shared -Os Working.cpp -o libworking.so This works as intended on all 32 and 64 bit systems which I have tested it on, and on all optimisation levels. However, consider the next small program: #include <vector> #include <unordered_set> #include <cstdint> uint64_t getBegin(const std::unordered_set<uint64_t> & set) { return *set.begin(); } The only change is the addition of a "#include <vector>". This ought not to have any impact on the program, and it ought to work exactly the same. It can also be compiled into a shared library with the following command: g++ -Wall -Wextra -fpic -shared -Os Broken.cpp -o libbroken.so Indeed, when compiled on a 64 bit x86 system there is no difference - both functions work as intended. However, when compiled either natively on a 32-bit x86 system, or cross compiled to 32-bit using the "-m32" flag, "*set.begin()" returns an incorrect value. I tested both of these with the following simple test program: #include <unordered_set> #include <iostream> uint64_t getBegin(const std::unordered_set<uint64_t> & set); int main(void) { std::unordered_set<uint64_t> set({1, 2, 3, 4, 5, 6, 7}); std::cout << getBegin(set) << "\n"; } Which can be compiled using the following commands (linking to either working or broken versions respectively): g++ -Wall -Wextra -Os test.cpp -L. -lworking -o test g++ -Wall -Wextra -Os test.cpp -L. -lbroken -o test Both versions work correctly when compiled and running natively on a 64-bit x86 system, (they print "7"). But, when when either compiled with "-m32" on a 64-bit system, or compiled and running natively on a 32-bit x86 system, the second (broken) variant prints "30064771072". This is certainly not one of the numbers in the unordered_set. I have reproduced the problem across several different 32-bit and 64-bit systems. These are the versions reported by g++ --version, on the systems which I have tried: Debian 10 (stable): g++ (Debian 8.3.0-6) 8.3.0 Debian 11 (testing): g++ (Debian 10.2.0-9) 10.2.0 Fedora 32 (Workstation Edition): g++ (GCC) 10.2.1 20200723 (Red Hat 10.2.1-1) Some source files and a simple makefile, which can reproduce the problem, are attached. I have also included the .ii file which is produced when running the following command, on the broken variant of the function: g++ -save-temps -m32 -Wall -Wextra -fpic -shared -Os Broken.cpp -o libbroken.so Other things which I have noticed: > The problem happens with optimisation levels O1, O2, O3, Os and Ofast, but does not occur with O0. > The problem occurs whenever vector is included BEFORE unordered_set. If vector is included after unordered_set, behaviour is correct. > When broken, the memory address pointed to by the iterator returned by begin(), seems to always be wrong by 4 bytes, (4 bytes before the address which it should be). > When I compared the assembly output of the two functions, the offsets in three movl instructions differ - see below. I assume this is causing the wrong address to be returned. Working version: movl 8(%eax), %eax # MEM[(struct _Hash_node_base * *)set_2(D) + 8B], MEM[(struct _Hash_node_base * *)set_2(D) + 8B] movl 12(%eax), %edx # MEM[(const long long unsigned int &)_4 + 8], MEM[(const long long unsigned int &)_4 + 8] movl 8(%eax), %eax # MEM[(const long long unsigned int &)_4 + 8], MEM[(const long long unsigned int &)_4 + 8] Broken version: movl 8(%eax), %eax # MEM[(struct _Hash_node_base * *)set_2(D) + 8B], MEM[(struct _Hash_node_base * *)set_2(D) + 8B] movl 8(%eax), %edx # MEM[(const long long unsigned int &)_4 + 4], MEM[(const long long unsigned int &)_4 + 4] movl 4(%eax), %eax # MEM[(const long long unsigned int &)_4 + 4], MEM[(const long long unsigned int &)_4 + 4] If there is any more information about this problem which you require, then please let me know. Thank you very much, Dan Wilson.
next reply other threads:[~2020-10-02 15:00 UTC|newest] Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-10-02 15:00 rascmoo at gmail dot com [this message] 2020-10-02 16:55 ` [Bug libstdc++/97273] [8/9/10/11 Regression] " redi at gcc dot gnu.org 2020-10-03 4:31 ` ppalka at gcc dot gnu.org 2020-10-03 22:07 ` ppalka at gcc dot gnu.org 2020-10-05 3:33 ` ppalka at gcc dot gnu.org 2020-10-07 14:52 ` cvs-commit at gcc dot gnu.org 2020-10-08 23:32 ` cvs-commit at gcc dot gnu.org 2020-10-08 23:33 ` [Bug libstdc++/97273] [8/9 " ppalka at gcc dot gnu.org 2020-11-13 14:23 ` cvs-commit at gcc dot gnu.org 2021-04-21 12:08 ` cvs-commit at gcc dot gnu.org 2021-04-21 12:08 ` ppalka at gcc dot gnu.org
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=bug-97273-4@http.gcc.gnu.org/bugzilla/ \ --to=gcc-bugzilla@gcc.gnu.org \ --cc=gcc-bugs@gcc.gnu.org \ /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: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
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 read-only IMAP folder(s) and NNTP newsgroup(s).