blob: fb87d16f8334ef7b20462ff8072efc62618ec18d [file] [log] [blame]
/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-verbosity=3" } */
/* { dg-enable-nn-line-numbers "" } */
#include <stdlib.h>
void calls_free_1 (void *ptr)
{
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
}
void test_1 (void *ptr, int a, int b)
{
if (a)
calls_free_1 (ptr);
if (b)
{
}
else
calls_free_1 (ptr);
}
/* { dg-begin-multiline-output "" }
NN | free (ptr);
| ^~~~~~~~~~
'test_1': events 1-4
|
| NN | void test_1 (void *ptr, int a, int b)
| | ^~~~~~
| | |
| | (1) entry to 'test_1'
| NN | {
| NN | if (a)
| | ~
| | |
| | (2) following 'true' branch (when 'a != 0')...
| NN | calls_free_1 (ptr);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (3) ...to here
| | (4) calling 'calls_free_1' from 'test_1'
|
+--> 'calls_free_1': events 5-6
|
| NN | void calls_free_1 (void *ptr)
| | ^~~~~~~~~~~~
| | |
| | (5) entry to 'calls_free_1'
| NN | {
| NN | free (ptr);
| | ~~~~~~~~~~
| | |
| | (6) first 'free' here
|
<------+
|
'test_1': events 7-10
|
| NN | calls_free_1 (ptr);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (7) returning to 'test_1' from 'calls_free_1'
| NN |
| NN | if (b)
| | ~
| | |
| | (8) following 'false' branch (when 'b == 0')...
|......
| NN | calls_free_1 (ptr);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (9) ...to here
| | (10) passing freed pointer 'ptr' in call to 'calls_free_1' from 'test_1'
|
+--> 'calls_free_1': events 11-12
|
| NN | void calls_free_1 (void *ptr)
| | ^~~~~~~~~~~~
| | |
| | (11) entry to 'calls_free_1'
| NN | {
| NN | free (ptr);
| | ~~~~~~~~~~
| | |
| | (12) second 'free' here; first 'free' was at (6)
|
{ dg-end-multiline-output "" } */
void calls_free_2 (void *ptr)
{
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
}
void test_2 (void *ptr, int a, int b)
{
switch (a)
{
default:
break;
case 1:
break;
case 3:
calls_free_2 (ptr);
break;
}
switch (b)
{
default:
calls_free_2 (ptr);
break;
case 1:
break;
case 42:
break;
}
}
/* { dg-begin-multiline-output "" }
NN | free (ptr);
| ^~~~~~~~~~
'test_2': events 1-4
|
| NN | void test_2 (void *ptr, int a, int b)
| | ^~~~~~
| | |
| | (1) entry to 'test_2'
| NN | {
| NN | switch (a)
| | ~~~~~~
| | |
| | (2) following 'case 3:' branch...
|......
| NN | case 3:
| | ~~~~
| | |
| | (3) ...to here
| NN | calls_free_2 (ptr);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (4) calling 'calls_free_2' from 'test_2'
|
+--> 'calls_free_2': events 5-6
|
| NN | void calls_free_2 (void *ptr)
| | ^~~~~~~~~~~~
| | |
| | (5) entry to 'calls_free_2'
| NN | {
| NN | free (ptr);
| | ~~~~~~~~~~
| | |
| | (6) first 'free' here
|
<------+
|
'test_2': events 7-10
|
| NN | calls_free_2 (ptr);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (7) returning to 'test_2' from 'calls_free_2'
|......
| NN | switch (b)
| | ~~~~~~
| | |
| | (8) following 'default:' branch...
| NN | {
| NN | default:
| | ~~~~~~~
| | |
| | (9) ...to here
| NN | calls_free_2 (ptr);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (10) passing freed pointer 'ptr' in call to 'calls_free_2' from 'test_2'
|
+--> 'calls_free_2': events 11-12
|
| NN | void calls_free_2 (void *ptr)
| | ^~~~~~~~~~~~
| | |
| | (11) entry to 'calls_free_2'
| NN | {
| NN | free (ptr);
| | ~~~~~~~~~~
| | |
| | (12) second 'free' here; first 'free' was at (6)
|
{ dg-end-multiline-output "" } */
// TODO: range cases
/* The call/return to this function shouldn't appear in the path. */
void called_by_test_3 (void)
{
}
void test_3 (void *ptr)
{
free (ptr);
called_by_test_3 ();
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
}
/* { dg-begin-multiline-output "" }
NN | free (ptr);
| ^~~~~~~~~~
'test_3': events 1-2
|
| NN | free (ptr);
| | ^~~~~~~~~~
| | |
| | (1) first 'free' here
| NN | called_by_test_3 ();
| NN | free (ptr);
| | ~~~~~~~~~~
| | |
| | (2) second 'free' here; first 'free' was at (1)
|
{ dg-end-multiline-output "" } */