aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-02-16 09:06:46 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2022-02-16 18:48:30 -0500
commita61aaee63848d422e8443e17bbec3257ee59d5d8 (patch)
tree2b0b4a63040799e86211bd329f4c93b2961a1555 /gcc/testsuite
parent24ca97325cab7bc454c785d55f37120fe7ea6f74 (diff)
downloadgcc-a61aaee63848d422e8443e17bbec3257ee59d5d8.zip
gcc-a61aaee63848d422e8443e17bbec3257ee59d5d8.tar.gz
gcc-a61aaee63848d422e8443e17bbec3257ee59d5d8.tar.bz2
analyzer: fixes to free of non-heap detection [PR104560]
PR analyzer/104560 reports various false positives from -Wanalyzer-free-of-non-heap seen with rdma-core, on what's effectively: free (&ptr->field) where in this case "field" is the first element of its struct, and thus &ptr->field == ptr, and could be on the heap. The root cause is due to malloc_state_machine::on_stmt making "LHS = &EXPR;" transition LHS from start to non_heap when EXPR is not a MEM_REF; this assumption doesn't hold for the above case. This patch eliminates that state transition, instead relying on malloc_state_machine::get_default_state to detect regions known to not be on the heap. Doing so fixes the false positive, but eliminates some events relating to free-of-alloca identifying the alloca, so the patch also reworks free_of_non_heap to capture which region has been freed, adding region creation events to diagnostic paths, so that the alloca calls can be identified, and using the memory space of the region for more precise wording of the diagnostic. The improvement to malloc_state_machine::get_default_state also means we now detect attempts to free VLAs, functions and code labels. In doing so I spotted that I wasn't adding region creation events for regions for global variables, and for cases where an allocation is the last stmt within its basic block, so the patch also fixes these issues. gcc/analyzer/ChangeLog: PR analyzer/104560 * diagnostic-manager.cc (diagnostic_manager::build_emission_path): Add region creation events for globals of interest. (null_assignment_sm_context::get_old_program_state): New. (diagnostic_manager::add_events_for_eedge): Move check for changing dynamic extents from PK_BEFORE_STMT case to after the switch on the dst_point's kind so that we can emit them for the final stmt in a basic block. * engine.cc (impl_sm_context::get_old_program_state): New. * sm-malloc.cc (malloc_state_machine::get_default_state): Rewrite detection of m_non_heap to use get_memory_space. (free_of_non_heap::free_of_non_heap): Add freed_reg param. (free_of_non_heap::subclass_equal_p): Update for changes to fields. (free_of_non_heap::emit): Drop m_kind in favor of get_memory_space. (free_of_non_heap::describe_state_change): Remove logic for detecting alloca. (free_of_non_heap::mark_interesting_stuff): Add region-creation of m_freed_reg. (free_of_non_heap::get_memory_space): New. (free_of_non_heap::kind): Drop enum. (free_of_non_heap::m_freed_reg): New field. (free_of_non_heap::m_kind): Drop field. (malloc_state_machine::on_stmt): Drop transition to m_non_heap. (malloc_state_machine::handle_free_of_non_heap): New function, split out from on_deallocator_call and on_realloc_call, adding detection of the freed region. (malloc_state_machine::on_deallocator_call): Use it. (malloc_state_machine::on_realloc_call): Likewise. * sm.h (sm_context::get_old_program_state): New vfunc. gcc/testsuite/ChangeLog: PR analyzer/104560 * g++.dg/analyzer/placement-new.C: Update expected wording. * g++.dg/analyzer/pr100244.C: Likewise. * gcc.dg/analyzer/attr-malloc-1.c (test_7): Likewise. * gcc.dg/analyzer/malloc-1.c (test_24): Likewise. (test_25): Likewise. (test_26): Likewise. (test_50a, test_50b, test_50c): New. * gcc.dg/analyzer/malloc-callbacks.c (test_5): Update expected wording. * gcc.dg/analyzer/malloc-paths-8.c: Likewise. * gcc.dg/analyzer/pr104560-1.c: New test. * gcc.dg/analyzer/pr104560-2.c: New test. * gcc.dg/analyzer/realloc-1.c (test_7): Updated expected wording. * gcc.dg/analyzer/vla-1.c (test_2): New. Prune output from -Wfree-nonheap-object. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/testsuite')
-rw-r--r--gcc/testsuite/g++.dg/analyzer/placement-new.C4
-rw-r--r--gcc/testsuite/g++.dg/analyzer/pr100244.C2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/attr-malloc-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/malloc-1.c32
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c5
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c4
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/pr104560-1.c43
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/pr104560-2.c26
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/realloc-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/vla-1.c9
10 files changed, 113 insertions, 18 deletions
diff --git a/gcc/testsuite/g++.dg/analyzer/placement-new.C b/gcc/testsuite/g++.dg/analyzer/placement-new.C
index b648a42..8905549 100644
--- a/gcc/testsuite/g++.dg/analyzer/placement-new.C
+++ b/gcc/testsuite/g++.dg/analyzer/placement-new.C
@@ -20,9 +20,9 @@ void test_2 (void)
void test_3 (void)
{
- char buf[sizeof(int)];
+ char buf[sizeof(int)]; // { dg-message "region created on stack here" }
int *p = new(buf) int (42);
- delete p; // { dg-warning "memory not on the heap" }
+ delete p; // { dg-warning "memory on the stack" }
}
// { dg-prune-output "-Wfree-nonheap-object" }
diff --git a/gcc/testsuite/g++.dg/analyzer/pr100244.C b/gcc/testsuite/g++.dg/analyzer/pr100244.C
index 261b3cf..1d5e13d 100644
--- a/gcc/testsuite/g++.dg/analyzer/pr100244.C
+++ b/gcc/testsuite/g++.dg/analyzer/pr100244.C
@@ -11,7 +11,7 @@ struct _Hashtable_alloc {
int _M_single_bucket;
int *_M_buckets;
_Hashtable_alloc () { _M_buckets = &_M_single_bucket; }
- ~_Hashtable_alloc () { delete _M_buckets; } // { dg-warning "not on the heap" }
+ ~_Hashtable_alloc () { delete _M_buckets; } // { dg-warning "on the stack" }
};
void
diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/attr-malloc-1.c
index a9a2a3d..e956cf5 100644
--- a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/attr-malloc-1.c
@@ -70,7 +70,7 @@ void test_6 (struct foo *p)
void test_7 ()
{
struct foo f;
- foo_release (&f); /* { dg-warning "not on the heap" "analyzer" } */
+ foo_release (&f); /* { dg-warning "on the stack" "analyzer" } */
/* { dg-warning "'foo_release' called on unallocated object 'f'" "non-analyzer" { target *-*-* } .-1 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
index 3219f85..d69a605 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
@@ -271,23 +271,23 @@ int *test_23a (int n)
int test_24 (void)
{
- void *ptr = __builtin_alloca (sizeof (int)); /* { dg-message "memory is allocated on the stack here" } */
- free (ptr); /* { dg-warning "'free' of memory allocated on the stack by 'alloca' \\('ptr'\\) will corrupt the heap \\\[CWE-590\\\]" } */
+ void *ptr = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */
+ free (ptr); /* { dg-warning "'free' of 'ptr' which points to memory on the stack \\\[CWE-590\\\]" } */
}
int test_25 (void)
{
- char tmp[100];
- void *p = tmp; /* { dg-message "pointer is from here" } */
- free (p); /* { dg-warning "'free' of 'p' which points to memory not on the heap \\\[CWE-590\\\]" } */
+ char tmp[100]; /* { dg-message "region created on stack here" } */
+ void *p = tmp;
+ free (p); /* { dg-warning "'free' of 'p' which points to memory on the stack \\\[CWE-590\\\]" } */
/* TODO: more precise messages here. */
}
-char global_buffer[100];
+char global_buffer[100]; /* { dg-message "region created here" } */
int test_26 (void)
{
- void *p = global_buffer; /* { dg-message "pointer is from here" } */
+ void *p = global_buffer;
free (p); /* { dg-warning "'free' of 'p' which points to memory not on the heap \\\[CWE-590\\\]" } */
/* TODO: more precise messages here. */
}
@@ -608,4 +608,22 @@ int test_49 (int i)
return x;
}
+/* Free of function, and of label within function. */
+
+void test_50a (void)
+{
+}
+
+void test_50b (void)
+{
+ free (test_50a); /* { dg-warning "'free' of '&test_50a' which points to memory not on the heap \\\[CWE-590\\\]" } */
+}
+
+void test_50c (void)
+{
+ my_label:
+ free (&&my_label); /* { dg-warning "'free' of '&my_label' which points to memory not on the heap \\\[CWE-590\\\]" } */
+}
+
+
/* { dg-prune-output "\\\[-Wfree-nonheap-object" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c b/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c
index 8820ddd..c79f80d 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c
@@ -61,9 +61,8 @@ int *test_5 (void)
{
allocator_t alloc_fn = get_alloca ();
deallocator_t dealloc_fn = get_free ();
- int *ptr = alloc_fn (sizeof (int)); /* { dg-message "pointer is from here" } */
- /* TODO: message should read "memory is allocated on the stack here". */
- dealloc_fn (ptr); /* { dg-warning "'free' of 'ptr' which points to memory not on the heap" } */
+ int *ptr = alloc_fn (sizeof (int)); /* dg-message "region created on stack here" } */
+ dealloc_fn (ptr); /* { dg-warning "'free' of 'ptr' which points to memory on the stack" } */
}
static void __attribute__((noinline))
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
index 9a7c414..4988f53 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-8.c
@@ -40,7 +40,7 @@ void test_3 (size_t sz)
{
void *ptr;
if (sz <= LIMIT)
- ptr = __builtin_alloca (sz); /* { dg-message "memory is allocated on the stack here" } */
+ ptr = __builtin_alloca (sz); /* { dg-message "region created on stack here" } */
else
ptr = malloc (sz);
@@ -49,7 +49,7 @@ void test_3 (size_t sz)
/* Bug: the "sz <= LIMIT" above should have been "sz < LIMIT",
so there's a free-of-alloca when sz == LIMIT. */
if (sz >= LIMIT)
- free (ptr); /* { dg-warning "'free' of memory allocated on the stack by 'alloca'" } */
+ free (ptr); /* { dg-warning "'free' of 'ptr' which points to memory on the stack" } */
}
/* { dg-bogus "leak of 'ptr'" } */
/* This can't happen, as "sz > 1024" && "sz <= 1023" is impossible. */
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104560-1.c b/gcc/testsuite/gcc.dg/analyzer/pr104560-1.c
new file mode 100644
index 0000000..aeab4b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr104560-1.c
@@ -0,0 +1,43 @@
+/* Reduced/adapted from false positive from -Wanalyzer-free-of-non-heap
+ seen on rdma-core. */
+
+#include <stddef.h>
+
+#define check_types_match(expr1, expr2) \
+ ((typeof(expr1) *)0 != (typeof(expr2) *)0)
+
+#define container_of(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ ((char *)(member_ptr) \
+ - container_off(containing_type, member)) \
+ + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+#define container_off(containing_type, member) \
+ offsetof(containing_type, member)
+
+struct ibv_device {
+ /* [...snip...] */
+};
+
+struct verbs_device {
+ struct ibv_device device; /* Must be first */
+ /* [...snip...] */
+ int placeholder;
+};
+
+struct mlx5_device {
+ struct verbs_device verbs_dev;
+ int placeholder;
+};
+
+static inline struct mlx5_device *to_mdev(struct ibv_device *ibdev)
+{
+ return container_of(ibdev, struct mlx5_device, verbs_dev.device);
+}
+
+static void mlx5_uninit_device(struct verbs_device *verbs_device)
+{
+ struct mlx5_device *dev = to_mdev(&verbs_device->device);
+
+ __builtin_free(dev); /* { dg-bogus "not on the heap" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104560-2.c b/gcc/testsuite/gcc.dg/analyzer/pr104560-2.c
new file mode 100644
index 0000000..f968a58
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr104560-2.c
@@ -0,0 +1,26 @@
+struct ibv_device {
+ /* [...snip...] */
+ int placeholder;
+};
+
+struct verbs_device {
+ struct ibv_device device; /* Must be first */
+ /* [...snip...] */
+ int placeholder;
+};
+
+struct mlx5_device {
+ struct verbs_device verbs_dev;
+ int placeholder;
+};
+
+static inline struct mlx5_device *to_mdev(struct ibv_device *ibdev)
+{
+ return (struct mlx5_device *)ibdev;
+}
+
+static void mlx5_uninit_device(struct verbs_device *verbs_device)
+{
+ struct mlx5_device *dev = to_mdev(&verbs_device->device);
+ __builtin_free(dev); /* { dg-bogus "not on the heap" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-1.c b/gcc/testsuite/gcc.dg/analyzer/realloc-1.c
index ef117ad..9951e11 100644
--- a/gcc/testsuite/gcc.dg/analyzer/realloc-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/realloc-1.c
@@ -59,8 +59,8 @@ void test_6 (size_t sz)
void *test_7 (size_t sz)
{
- char buf[100];
- void *p = realloc (&buf, sz); /* { dg-warning "'realloc' of '&buf' which points to memory not on the heap" } */
+ char buf[100]; /* { dg-message "region created on stack here" } */
+ void *p = realloc (&buf, sz); /* { dg-warning "'realloc' of '&buf' which points to memory on the stack" } */
return p;
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/vla-1.c b/gcc/testsuite/gcc.dg/analyzer/vla-1.c
index e5971c8..9561d74 100644
--- a/gcc/testsuite/gcc.dg/analyzer/vla-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/vla-1.c
@@ -12,3 +12,12 @@ void test_1 (int n)
s.b = 17;
__analyzer_eval (s.b == 17); /* { dg-warning "TRUE" } */
}
+
+void test_2 (int n)
+{
+ int arr[n]; /* { dg-message "region created on stack here" } */
+ __builtin_free (arr); /* { dg-warning "'free' of '<unknown>' which points to memory on the stack" } */
+ // TODO: fix the "unknown" here
+}
+
+/* { dg-prune-output "\\\[-Wfree-nonheap-object" } */