Bug 2109065
| Summary: | g++ -O2 compiles buggy code with union aliasing. | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 9 | Reporter: | Kirby Zhou <kirbyzhou> | ||||
| Component: | gcc | Assignee: | Marek Polacek <mpolacek> | ||||
| gcc sub component: | system-version | QA Contact: | qe-baseos-tools-bugs | ||||
| Status: | CLOSED UPSTREAM | Docs Contact: | |||||
| Severity: | high | ||||||
| Priority: | unspecified | CC: | ahajkova, bstinson, fweimer, jakub, jwboyer, ohudlick, sipoyare | ||||
| Version: | CentOS Stream | Keywords: | Reopened | ||||
| Target Milestone: | rc | ||||||
| Target Release: | --- | ||||||
| Hardware: | x86_64 | ||||||
| OS: | Linux | ||||||
| Whiteboard: | |||||||
| Fixed In Version: | Doc Type: | If docs needed, set a value | |||||
| Doc Text: | Story Points: | --- | |||||
| Clone Of: | Environment: | ||||||
| Last Closed: | 2022-07-22 13:17:43 UTC | Type: | Bug | ||||
| Regression: | --- | Mount Type: | --- | ||||
| Documentation: | --- | CRM: | |||||
| Verified Versions: | Category: | --- | |||||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
| Cloudforms Team: | --- | Target Upstream Version: | |||||
| Embargoed: | |||||||
| Attachments: |
|
||||||
|
Description
Kirby Zhou
2022-07-20 11:16:48 UTC
The bug happens at both x86_64 and aarch64 The bug wont happens at gcc-c++-10.3.1-1.2.el8_5 This changed with https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=d119f34c952f8718fdbabc63e2f369a16e92fa07, so the old behavior can be brought by -fno-ipa-modref. However, I think the program invokes undefined behavior. For clarity, this is the union after preprocessing: union Status { struct Wrapper { uint32_t value; }; Wrapper wrapper; Status(uint32_t v = 0) { wrapper.value = v; } Status &operator=(uint32_t v) { wrapper.value = v; return *this; } operator uint32_t &() { return wrapper.value; } operator uint32_t() const { return wrapper.value; } typedef uint32_t StorageType; BitFieldMember<StorageType, 0, 10> readers; BitFieldMember<StorageType, 10, 10> waitToRead; BitFieldMember<StorageType, 20, 10> writers; }; so this union has 4 members. [class.union] says that "At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time." Then the program does this: Status status; // activates .wrapper status.writers = 1; // activates .writers status.waitToRead = 1; // activates .waitToRead NonRecursiveRWLock lock; lock.m_status = status; // invokes Status::operator uint32_t&, which uses the non-active member .wrapper, which is UB So I think this program is invalid. But the union is actually a union of bitfields.
union {
int value;
struct {
int readers : 10;
int waitToRead : 10;
int writers : 10;
};
}
And this bit-field structure pattern is widely spread in years referred as "Safe Bitfields in C++".
Such as:
https://preshing.com/20150324/safe-bitfields-in-cpp/
https://zditect.com/code/cpp/safe-bitfields-in-c.html
https://m.blog.naver.com/framkang/220414843423
https://www.reddit.com/r/programming/comments/3i6q2w/safe_bitfields_in_c/
https://www.intensedebate.com/people/UUD
https://gfjiangly.github.io/cpu_parallel/you-can-do-any-kind-of-atomic-read-modify-write-operation.html
So if gcc-11 breaks this pattern, a lot of existing code will be hurt.
Ah, sorry; I missed that BitFieldMember and Wrapper actually *are* standard-layout classes, therefore the exception about a common initial sequence (here, a uint32_t) in [class.union.general] kicks in. I'm going to file an upstream bug, sorry again and thanks for the report. Upstream PR opened. We have to fix this upstream first. A workaround is to use -fno-strict-aliasing. (In reply to Marek Polacek from comment #4) > Ah, sorry; I missed that BitFieldMember and Wrapper actually *are* > standard-layout classes, therefore the exception > about a common initial sequence (here, a uint32_t) in [class.union.general] > kicks in. > > I'm going to file an upstream bug, sorry again and thanks for the report. Is there any progress in upstream? (In reply to Kirby Zhou from comment #8) > (In reply to Marek Polacek from comment #4) > > Ah, sorry; I missed that BitFieldMember and Wrapper actually *are* > > standard-layout classes, therefore the exception > > about a common initial sequence (here, a uint32_t) in [class.union.general] > > kicks in. > > > > I'm going to file an upstream bug, sorry again and thanks for the report. > > Is there any progress in upstream? It looks like the developers don't want to implement this rule; rather, users should use may_alias: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106389#c5 |