aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/analyzer/store.cc18
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/aliasing-3.c75
2 files changed, 86 insertions, 7 deletions
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 8729aa8..3f91b61 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -2456,13 +2456,17 @@ store::eval_alias_1 (const region *base_reg_a,
= base_reg_a->dyn_cast_symbolic_region ())
{
const svalue *sval_a = sym_reg_a->get_pointer ();
- if (sval_a->get_kind () == SK_INITIAL)
- if (tree decl_b = base_reg_b->maybe_get_decl ())
- if (!is_global_var (decl_b))
- {
- /* The initial value of a pointer can't point to a local. */
- return tristate::TS_FALSE;
- }
+ if (tree decl_b = base_reg_b->maybe_get_decl ())
+ {
+ if (!may_be_aliased (decl_b))
+ return tristate::TS_FALSE;
+ if (sval_a->get_kind () == SK_INITIAL)
+ if (!is_global_var (decl_b))
+ {
+ /* The initial value of a pointer can't point to a local. */
+ return tristate::TS_FALSE;
+ }
+ }
if (sval_a->get_kind () == SK_INITIAL
&& base_reg_b->get_kind () == RK_HEAP_ALLOCATED)
{
diff --git a/gcc/testsuite/gcc.dg/analyzer/aliasing-3.c b/gcc/testsuite/gcc.dg/analyzer/aliasing-3.c
new file mode 100644
index 0000000..003077a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/aliasing-3.c
@@ -0,0 +1,75 @@
+#include "analyzer-decls.h"
+
+#define NULL ((void *)0)
+
+struct s1
+{
+ int f1;
+};
+
+static struct s1 *p1_glob = NULL;
+
+void test_1 (struct s1 **pp1, struct s1 *p1_parm)
+{
+ struct s1 *init_p1_glob = p1_glob;
+
+ __analyzer_eval (p1_glob == init_p1_glob); /* { dg-warning "TRUE" } */
+
+ if (!p1_glob)
+ return;
+
+ __analyzer_eval (p1_glob == init_p1_glob); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p1_glob != NULL); /* { dg-warning "TRUE" } */
+
+ *pp1 = p1_parm;
+
+ /* The write through *pp1 can't have changed p1_glob, because
+ we never take a pointer to p1_glob (and it's static to this TU). */
+ __analyzer_eval (p1_glob == init_p1_glob); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p1_glob != NULL); /* { dg-warning "TRUE" } */
+}
+
+struct s2
+{
+ int f1;
+};
+
+static struct s2 *p2_glob = NULL;
+
+void test_2 (struct s2 **pp2, struct s2 *p2_parm)
+{
+ /* Ensure that p2_glob is modified. */
+ p2_glob = __builtin_malloc (sizeof (struct s2));
+ if (!p2_glob)
+ return;
+
+ __analyzer_eval (p2_glob != NULL); /* { dg-warning "TRUE" } */
+
+ *pp2 = p2_parm;
+
+ /* The write through *pp2 can't have changed p2_glob, because
+ we never take a pointer to p2_glob (and it's static to this TU). */
+ __analyzer_eval (p2_glob != NULL); /* { dg-warning "TRUE" } */
+}
+
+struct s3
+{
+ int f1;
+};
+
+struct s3 *p3_glob = NULL;
+
+void test_3 (struct s3 **pp3, struct s3 *p3_parm)
+{
+ p3_glob = __builtin_malloc (sizeof (struct s3));
+ if (!p3_glob)
+ return;
+
+ __analyzer_eval (p3_glob != NULL); /* { dg-warning "TRUE" } */
+
+ *pp3 = p3_parm;
+
+ /* The write through *pp3 could have changed p3_glob, because
+ another TU could take a pointer to p3_glob. */
+ __analyzer_eval (p3_glob != NULL); /* { dg-warning "UNKNOWN" } */
+}