[Bug middle-end/54202] Overeager warning about freeing non-heap objects

2023-08-25 Thread charlechaud at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202

Charles Blake  changed:

   What|Removed |Added

 CC||charlechaud at gmail dot com

--- Comment #11 from Charles Blake  ---
Here is another example (no external includes/etc.):

typedef long unsigned int size_t;

extern void *malloc (size_t __size) __attribute__ ((__nothrow__ , __leaf__))
__attribute__ ((__malloc__))
 __attribute__ ((__alloc_size__ (1))) __attribute__
((__warn_unused_result__));

extern void free (void *__ptr) __attribute__ ((__nothrow__ , __leaf__));

typedef struct { long count, flags; } Foo;

Foo *G(Foo *x, long flags, int unused) {
if (x) { // originally a file descriptor
x->count = 0; flags = 0;
} else {
if (!(x = (Foo *)malloc(sizeof *x))) return (Foo *)0;
flags = 1;
}
x->flags = flags;
return x;
}

Foo *F(Foo *x, long flags) {
if (x) { // originally a pathname path
x->count = 0; flags = 0;
} else {
if (!(x = (Foo *)malloc(sizeof *x))) return (Foo *)0;
flags = 1;
}
x->flags = flags;
return G(x, flags, 123);
}

void release(Foo *x) {
if (x && x->flags) free(x);
}

int main(void) {
Foo x;
if (F(, 0))
release();
return 0;
}

In the above, variations due to compiler optimization levels make it even more
confusing: -O1 does not warn, -O2 does warn, -O3 again does not warn (on both
gcc-12.3 and gcc-13.2 on Gentoo Linux, anyway). O3 optimizes the whole main
away.  clang never warns on this at any -O level, nor with clang --analyze.

What is particularly bad about this warning is that AFAICT there is no way to
massage the code to reliably silence it while also preserving the intended
effect.  Now it's even on by default.  This actively discourages an otherwise
clean arrangement in the C programming language when working with anyone else
who takes warns too seriously.  Any such warning should have "may be" language
not language that sounds like the compiler has "proved an actuality".

Might the same argument apply to many warnings?  Maybe.  Two words is not so
bad, though.  Other warns may have workarounds like annotations to silence them
reliably without sacrificing functionality.  Maybe I'm missing one here?

[Bug middle-end/54202] Overeager warning about freeing non-heap objects

2021-06-16 Thread msebor at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202

--- Comment #10 from Martin Sebor  ---
(In reply to Serdar Sanli from comment #9)
> A simpler example not involving any globals, causing Wfree-nonheap-object
> warning since GCC11

This is actually a bug in the example: it's invalid to decrement a pointer to
the beginning of an object as done in Foo::allocate.

[Bug middle-end/54202] Overeager warning about freeing non-heap objects

2021-06-16 Thread mserdarsanli at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202

Serdar Sanli  changed:

   What|Removed |Added

 CC||mserdarsanli at gmail dot com

--- Comment #9 from Serdar Sanli  ---
A simpler example not involving any globals, causing Wfree-nonheap-object
warning since GCC11
https://godbolt.org/z/MYn1zrjE4

===
struct Foo {
void allocate(int n);
void deallocate();

int *_data;
};

void Foo::allocate(int n) {
_data = new int[n] - 1;
}

void Foo::deallocate() {
delete[] (_data+1);
}

[Bug middle-end/54202] Overeager warning about freeing non-heap objects

2021-05-17 Thread dangelog at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202

Giuseppe D'Angelo  changed:

   What|Removed |Added

 CC||dangelog at gmail dot com

--- Comment #8 from Giuseppe D'Angelo  ---
The original testcase by Thiago still fails with GCC 11.

Unfortunately, GCC 11 decided to turn -Wfree-nonheap-object on by default (!),
resulting in false positives for Qt users (containers in Qt use this pattern).
For instance 

https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qlinkedlist.h?h=5.15

struct QT_DEPRECATED_VERSION_5_15 QLinkedListData
{
QLinkedListData *n, *p;
QtPrivate::RefCount ref; // set to -1 for shared_null
int size;
uint sharable : 1;

Q_CORE_EXPORT static const QLinkedListData shared_null;
};

template 
inline QLinkedList::~QLinkedList()
{
if (!d->ref.deref())
freeData(d); // never called on shared_null because of the check
}


template 
void QLinkedList::freeData(QLinkedListData *x)
{
// ...
delete x; // -Wfree-nonheap-object here
}

[Bug middle-end/54202] Overeager warning about freeing non-heap objects

2020-11-03 Thread msebor at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202

Martin Sebor  changed:

   What|Removed |Added

 CC||msebor at gcc dot gnu.org
  Component|c   |middle-end

--- Comment #7 from Martin Sebor  ---
All late warnings are susceptible to the same problem.  The only way to tell
from the IL that the free call isn't unconditional is from the CFG.  While that
could be used to issue either a "maybe" kind of a warning or a definitive one
per function, it would just turn most instances of these warnings into the
"maybe" kind.  Which is how all warnings need to be viewed regardless.

What might help more than rewording every warning to say "this may be
undefined" is printing the chain of conditions that need to be satisfied in
order for the warning to trigger.  The infrastructure to do this is all there,
it's just a matter of taking advantage of it: when a warning is issued, walk
the shortest path from the entry to the basic block with the problem statement
and print each conditional along the way.  With that, we should end up with
output very close to that of the analyzer:

pr54202.c:17:9: warning: ‘free’ of ‘_null’ which points to memory not on
the heap [CWE-590] [-Wanalyzer-free-of-non-heap]
   17 | free(d);
  | ^~~
  ‘f’: events 1-3
|
|   16 | if (d->refcount == 0)
|  |^
|  ||
|  |(1) following ‘true’ branch...
|   17 | free(d);
|  | ~~~
|  | |
|  | (2) ...to here
|  | (3) call to ‘free’ here
|

Removing basic block 5
f ()
{
  int _2;

   [local count: 1073741824]:
  _2 = shared_null.refcount;
  if (_2 == 0)   <<< condition
goto ; [33.00%]
  else
goto ; [67.00%]

   [local count: 354334800]:
  free (_null); [tail call]   <<< conditional invalid call

   [local count: 1073741824]:
  return;

}