public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug middle-end/105204] New: -Wuse-after-free=1 inconsistency with conditional free
@ 2022-04-08 14:47 piotr.grabowski at scylladb dot com
2022-04-08 14:48 ` [Bug middle-end/105204] " piotr.grabowski at scylladb dot com
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: piotr.grabowski at scylladb dot com @ 2022-04-08 14:47 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105204
Bug ID: 105204
Summary: -Wuse-after-free=1 inconsistency with conditional free
Product: gcc
Version: 12.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: piotr.grabowski at scylladb dot com
Target Milestone: ---
Created attachment 52772
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52772&action=edit
two examples of conditional free
Below, I added two examples of conditional free(), which cause inconsistent
behavior of -Wuse-after-free=1.
In the first case, GCC 12 does not issue -Wuse-after-free=1 warning, but in the
second similar example, the warning is triggered.
// Compile with: g++ -Wuse-after-free=1 -O2 -c example-inconsistency.cpp
void example1(int* ptr, bool condition) {
if (condition) {
free(ptr);
}
++*ptr; // No -Wuse-after-free=1 warning
}
void example2(int* ptr) {
if (*ptr == 1234) {
free(ptr);
}
++*ptr; // -Wuse-after-free=1 warning issued
}
Compiled with: g++ (GCC) 12.0.1 20220404 (experimental)
We hit that second case in our production code in our implementation of shared
pointer in Seastar
(https://github.com/scylladb/seastar/blob/05cdfc2d30c553ec73b5cdbfb6c4318c232b3a6d/include/seastar/core/shared_ptr.hh#L255).
Below is a simplified version of it, which triggers -Wuse-after-free=1:
// Compile with: g++ -Wuse-after-free=1 -O2 -c example-shared-ptr.cpp
struct shared_ptr {
size_t* ref_count;
public:
shared_ptr(const shared_ptr& other) : ref_count(other.ref_count) {
(*ref_count)++;
}
~shared_ptr() {
if (--(*ref_count) == 0) {
free(ref_count);
}
}
};
void example3(shared_ptr& sp) {
shared_ptr sp2(sp);
shared_ptr sp3(sp);
// -Wuse-after-free=1 is issued
}
Is this the expected behavior of -Wuse-after-free=1 and we should work around
it in our code?
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug middle-end/105204] -Wuse-after-free=1 inconsistency with conditional free
2022-04-08 14:47 [Bug middle-end/105204] New: -Wuse-after-free=1 inconsistency with conditional free piotr.grabowski at scylladb dot com
@ 2022-04-08 14:48 ` piotr.grabowski at scylladb dot com
2022-04-11 7:12 ` rguenth at gcc dot gnu.org
2022-12-01 14:50 ` avi at scylladb dot com
2 siblings, 0 replies; 4+ messages in thread
From: piotr.grabowski at scylladb dot com @ 2022-04-08 14:48 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105204
--- Comment #1 from Piotr Grabowski <piotr.grabowski at scylladb dot com> ---
Created attachment 52773
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52773&action=edit
example shared pointer implementation
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug middle-end/105204] -Wuse-after-free=1 inconsistency with conditional free
2022-04-08 14:47 [Bug middle-end/105204] New: -Wuse-after-free=1 inconsistency with conditional free piotr.grabowski at scylladb dot com
2022-04-08 14:48 ` [Bug middle-end/105204] " piotr.grabowski at scylladb dot com
@ 2022-04-11 7:12 ` rguenth at gcc dot gnu.org
2022-12-01 14:50 ` avi at scylladb dot com
2 siblings, 0 replies; 4+ messages in thread
From: rguenth at gcc dot gnu.org @ 2022-04-11 7:12 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105204
Richard Biener <rguenth at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Keywords| |diagnostic
CC| |rguenth at gcc dot gnu.org
--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
The diagnostic is confused about a PRE where we transform
<bb 2> [local count: 1073741824]:
_8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
_9 = *_8;
_20 = _9 + 1;
*_8 = _20;
if (_20 == 0)
goto <bb 3>; [33.00%]
else
goto <bb 4>; [67.00%]
<bb 3> [local count: 354334800]:
free (_8);
<bb 4> [local count: 1073741824]:
_16 = *_8;
_17 = _16 + 18446744073709551615;
*_8 = _17;
to
<bb 2> [local count: 1073741824]:
_8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
_9 = *_8;
_20 = _9 + 1;
*_8 = _20;
if (_20 == 0)
goto <bb 3>; [33.00%]
else
goto <bb 4>; [67.00%]
<bb 3> [local count: 354334800]:
free (_8);
pretmp_5 = *_8;
_25 = pretmp_5 + 18446744073709551615;
<bb 4> [local count: 1073741824]:
# prephitmp_10 = PHI <_9(2), _25(3)>
*_8 = prephitmp_10;
I think this is both a missed diagnostic without PRE (the free () falls
through to a dereference to the freed pointer) and a missed optimization
where the
_8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
_9 = *_8;
_20 = _9 + 1;
*_8 = _20;
if (_20 == 0)
test is not constant folded. Note this is because your code is not
resilent against overflow of ref_count and also not resilent against
a ref_count of zero incoming into the copy ctor. The latter is what
provokes the diagnostic in the end and also causes the missed
optimization.
changing the CTOR to sth like
shared_ptr(const shared_ptr& other) : ref_count(other.ref_count) {
if (*ref_count == 0)
__builtin_unreachable ();
(*ref_count)++;
}
avoids the diagnostic and optimizes the example3 to an empty function
(since we never will need to free the reference count).
So what this bug shows is a missed diagnostic without PRE, but otherwise
it works as expected.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug middle-end/105204] -Wuse-after-free=1 inconsistency with conditional free
2022-04-08 14:47 [Bug middle-end/105204] New: -Wuse-after-free=1 inconsistency with conditional free piotr.grabowski at scylladb dot com
2022-04-08 14:48 ` [Bug middle-end/105204] " piotr.grabowski at scylladb dot com
2022-04-11 7:12 ` rguenth at gcc dot gnu.org
@ 2022-12-01 14:50 ` avi at scylladb dot com
2 siblings, 0 replies; 4+ messages in thread
From: avi at scylladb dot com @ 2022-12-01 14:50 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105204
--- Comment #3 from Avi Kivity <avi at scylladb dot com> ---
Does one have to declare all preconditions? I happen to know that shared_ptr
with a reference count of zero is impossible, and I can understand the compiler
not being able to infer it, but just because it's unable to infer it doesn't
mean my code is wrong.
Maybe the warning should be renamed -Wmaybe-use-after-free to indicate the
compiler just thinks there may be a bug, but also acknowledges it doesn't know
everything.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2022-12-01 14:50 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-08 14:47 [Bug middle-end/105204] New: -Wuse-after-free=1 inconsistency with conditional free piotr.grabowski at scylladb dot com
2022-04-08 14:48 ` [Bug middle-end/105204] " piotr.grabowski at scylladb dot com
2022-04-11 7:12 ` rguenth at gcc dot gnu.org
2022-12-01 14:50 ` avi at scylladb dot com
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).