aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.dg/analyzer')
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h7
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/data-model-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/data-model-5b.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/data-model-5c.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c9
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py65
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c48
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-2.c17
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-3.c20
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-4.c8
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.c41
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.py29
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c35
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py89
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c2
16 files changed, 369 insertions, 9 deletions
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h
index 372a136..db0140b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h
@@ -30,6 +30,10 @@ extern void __analyzer_dump (void);
/* Emit a warning describing the size of the base region of (*ptr). */
extern void __analyzer_dump_capacity (const void *ptr);
+/* When reached, dump GraphViz .dot source to stderr for a diagram
+ describing the analyzer’s state. */
+extern void __analyzer_dump_dot (void);
+
/* Dump information about what decls have escaped at this point on the path. */
extern void __analyzer_dump_escaped (void);
@@ -58,6 +62,9 @@ extern void __analyzer_dump_region_model (void);
This is for use when debugging, and may be of use in DejaGnu tests. */
extern void __analyzer_dump_state (const char *name, ...);
+/* Dump copious information about the analyzer’s state when reached. */
+extern void __analyzer_dump_xml (void);
+
/* Emit a warning with text "TRUE", FALSE" or "UNKNOWN" based on the
truthfulness of the argument. */
extern void __analyzer_eval (int);
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-5.c b/gcc/testsuite/gcc.dg/analyzer/data-model-5.c
index b71bad7..78e2752 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-5.c
@@ -60,7 +60,7 @@ base_obj *alloc_obj (type_obj *ob_type, size_t sz)
{
base_obj *obj = (base_obj *)malloc (sz);
if (!obj)
- return NULL;
+ return NULL; /* { dg-message "using NULL here" } */
obj->ob_type = ob_type;
obj->ob_refcnt = 1;
return obj;
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-5b.c b/gcc/testsuite/gcc.dg/analyzer/data-model-5b.c
index cd6a4df..f66c8c4 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-5b.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-5b.c
@@ -44,7 +44,7 @@ base_obj *alloc_obj (type_obj *ob_type, size_t sz)
{
base_obj *obj = (base_obj *)malloc (sz);
if (!obj)
- return NULL;
+ return NULL; /* { dg-message "using NULL here" } */
obj->ob_type = ob_type;
obj->ob_refcnt = 1;
return obj;
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-5c.c b/gcc/testsuite/gcc.dg/analyzer/data-model-5c.c
index ad4e1d2..1ce355f 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-5c.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-5c.c
@@ -38,7 +38,7 @@ base_obj *alloc_obj (type_obj *ob_type, size_t sz)
{
base_obj *obj = (base_obj *)malloc (sz);
if (!obj)
- return NULL;
+ return NULL; /* { dg-message "using NULL here" } */
obj->ob_type = ob_type;
obj->ob_refcnt = 1;
return obj;
diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c
index d9015ac..1890312 100644
--- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c
+++ b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c
@@ -5,12 +5,12 @@
/* { dg-additional-options "-O2 -g" } */
-typedef long int ptrdiff_t;
-typedef unsigned long int uintptr_t;
-typedef long int EMACS_INT;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __PTRDIFF_TYPE__ EMACS_INT;
enum
{
- EMACS_INT_WIDTH = 64,
+ EMACS_INT_WIDTH = sizeof(EMACS_INT) * 8,
VALBITS = EMACS_INT_WIDTH - 3,
};
typedef struct Lisp_X* Lisp_Word;
@@ -151,4 +151,5 @@ set_marker_internal(Lisp_Object position, Lisp_Object buffer)
struct buffer* b = live_buffer(buffer);
if (NILP(position) || (MARKERP(position) && !XMARKER(position)->buffer) || !b) /* { dg-bogus "Wanalyzer-deref-before-check" } */
unchain_marker();
+ return 0;
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py
new file mode 100644
index 0000000..d92af83
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py
@@ -0,0 +1,65 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_state_graph(sarif):
+ result = get_result_by_index(sarif, 0)
+
+ assert result['level'] == 'warning'
+ assert result['ruleId'] == '-Wanalyzer-use-after-free'
+
+ # TODO: check code flow
+ events = result["codeFlows"][0]["threadFlows"][0]['locations']
+
+ # Event "(1)": "entry to 'test'" (index == 0)
+ assert events[0]['location']['message']['text'] == "entry to 'test'"
+ state0 = get_state_graph(events, 0)
+
+ stack = state0['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
+
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
+
+ # Final event:
+ assert events[-1]['location']['message']['text'].startswith("use after 'free' of ")
+ state = get_state_graph(events, -1)
+
+ stack = state['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
+
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
+
+ heap = state['nodes'][1]
+ assert heap['id'] == 'heap'
+ assert get_state_node_kind(heap) == 'heap'
+
+ assert len(heap['children']) == 3
+ heap_buffer0 = heap['children'][0]
+ assert heap_buffer0['id'].startswith('heap-allocated-region-')
+ assert get_state_node_kind(heap_buffer0) == 'dynalloc-buffer'
+
+ globals_ = state['nodes'][2]
+ assert globals_['id'] == 'globals'
+ assert get_state_node_kind(globals_) == 'globals'
+
+ first = globals_['children'][0]
+ assert first['id'].startswith('decl-region-')
+ assert get_state_node_kind(first) == 'variable'
+ assert get_state_node_name(first) == 'first'
+ assert get_state_node_type(first) == 'struct node *'
+
+ assert len(state['edges']) == 3
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c
new file mode 100644
index 0000000..3b35cfa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c
@@ -0,0 +1,48 @@
+/* { dg-additional-options "-fdiagnostics-add-output=sarif:state-graphs=yes" } */
+
+#include "analyzer-decls.h"
+
+struct node
+{
+ struct node *m_next;
+ int m_val;
+};
+
+struct node *first;
+
+struct node *
+append_value (int value)
+{
+ struct node *n = __builtin_malloc (sizeof (struct node));
+ if (!n)
+ return 0;
+ n->m_val = value;
+
+ n->m_next = first;
+ first = n;
+
+ return n;
+}
+
+int g;
+
+void
+test ()
+{
+ if (!append_value (42))
+ return;
+ if (!append_value (1066))
+ return;
+ if (!append_value (1776))
+ return;
+
+ __builtin_free (first->m_next->m_next);
+ first->m_next->m_next->m_next->m_next = NULL; /* { dg-warning "-Wanalyzer-use-after-free" } */
+}
+
+/* Verify that some JSON was written to a file with the expected name. */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest state-diagram-1.c "state-diagram-1-sarif.py" } } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-2.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-2.c
new file mode 100644
index 0000000..bde2bc4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-2.c
@@ -0,0 +1,17 @@
+#include "analyzer-decls.h"
+#include <stdio.h>
+
+int g;
+int h;
+
+int
+test_pointer_to_global (FILE *f)
+{
+ int *p = &g;
+ int *q = &h;
+
+ fread (&g, sizeof (g), 1, f);
+ fread (&h, sizeof (h), 1, f);
+
+ return *p / *q; /* { dg-warning "-Wanalyzer-tainted-divisor" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-3.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-3.c
new file mode 100644
index 0000000..a28553d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-3.c
@@ -0,0 +1,20 @@
+#include "analyzer-decls.h"
+
+int
+inner (int *p)
+{
+ return *p; /* { dg-warning "-Wanalyzer-use-of-uninitialized-value" } */
+}
+
+int
+middle (int *q)
+{
+ return inner (q);
+}
+
+int
+outer ()
+{
+ int i;
+ return middle (&i);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-4.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-4.c
new file mode 100644
index 0000000..37c654f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-4.c
@@ -0,0 +1,8 @@
+#include "analyzer-decls.h"
+
+void test ()
+{
+ void *p = __builtin_malloc (1024);
+ __builtin_free (p);
+ __builtin_free (p); /* { dg-warning "-Wanalyzer-double-free" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.c
new file mode 100644
index 0000000..274a951
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.c
@@ -0,0 +1,41 @@
+/* { dg-require-dot "" } */
+/* { dg-additional-options "-fdiagnostics-add-output=experimental-html:javascript=no,show-state-diagrams=yes" } */
+/* { dg-additional-options "-fdiagnostics-show-caret" } */
+
+#include "analyzer-decls.h"
+
+struct foo
+{
+ int m_ints[4];
+};
+
+struct bar
+{
+ struct foo m_foos[3];
+ int m_int;
+ char m_ch;
+};
+
+struct baz
+{
+ struct bar m_bars[2];
+ struct foo m_foos[5];
+};
+
+void test (void)
+{
+ struct baz baz_arr[2];
+ baz_arr[1].m_bars[1].m_foos[2].m_ints[1] = 42;
+ __analyzer_dump_path (); /* { dg-message "path" } */
+}
+
+/* We need -fdiagnostics-show-caret for the HTML output to show the source,
+ and thus to show event labels. */
+
+/* { dg-begin-multiline-output "" }
+ __analyzer_dump_path ();
+ { dg-end-multiline-output "" } */
+
+/* Use a Python script to verify various properties about the generated
+ .html file:
+ { dg-final { run-html-pytest state-diagram-5-html.c "state-diagram-5-html.py" } } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.py b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.py
new file mode 100644
index 0000000..79374b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.py
@@ -0,0 +1,29 @@
+# Smoketest of HTML state diagram output
+
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def test_state_diagram(html_tree):
+ diag = get_diag_by_index(html_tree, 0)
+ assert diag is not None
+
+ path = diag.find('xhtml:div[@id="execution-path"]', ns)
+ assert path is not None
+
+ event_label = path.find('.//xhtml:span[@id="gcc-diag-0-event-0"]', ns)
+ assert event_label is not None
+ assert event_label.get('class') == 'event'
+
+ assert event_label.text == '(1) here'
+
+ state_diagram = event_label.find('xhtml:div[@class="state-diagram"]', ns)
+ assert state_diagram is not None
+ assert state_diagram.get('id') == 'gcc-diag-0-event-0-state-diagram'
+
+ svg = state_diagram.find('.//svg:svg', ns)
+ assert svg is not None
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c
new file mode 100644
index 0000000..b981cf9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c
@@ -0,0 +1,35 @@
+/* { dg-additional-options "-fdiagnostics-add-output=sarif:state-graphs=yes" } */
+
+#include "analyzer-decls.h"
+
+struct foo
+{
+ int m_ints[4];
+};
+
+struct bar
+{
+ struct foo m_foos[3];
+ int m_int;
+ char m_ch;
+};
+
+struct baz
+{
+ struct bar m_bars[2];
+ struct foo m_foos[5];
+};
+
+void test (void)
+{
+ struct baz baz_arr[2];
+ baz_arr[1].m_bars[1].m_foos[2].m_ints[1] = 42;
+ __analyzer_dump_path (); /* { dg-message "path" } */
+}
+
+/* Verify that some JSON was written to a file with the expected name. */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest state-diagram-5-sarif.c "state-diagram-5-sarif.py" } } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py
new file mode 100644
index 0000000..3a2c6f8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py
@@ -0,0 +1,89 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_nested_types_in_state_graph(sarif):
+ result = get_result_by_index(sarif, 0)
+
+ assert result['level'] == 'note'
+
+ events = result["codeFlows"][0]["threadFlows"][0]['locations']
+
+ assert events[0]['location']['message']['text'] == 'here'
+ state = get_state_graph(events, 0)
+
+ stack = state['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
+
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
+
+ # We have:
+ # baz_arr[1].m_bars[1].m_foos[2].m_ints[1] = 42;
+
+ # Verify that we correctly expand from the analyzer's bit-offset
+ # representation to nested elements and fields.
+
+ # "baz_arr":
+ baz_arr = frame['children'][0]
+ assert get_state_node_kind(baz_arr) == 'variable'
+ assert get_state_node_type(baz_arr) == 'struct baz[2]'
+
+ assert len(baz_arr['children']) == 2
+
+ bindings = baz_arr['children'][0]
+ assert bindings['id'].startswith('concrete-bindings-')
+ assert get_state_node_kind(bindings) == 'other'
+ assert get_state_node_value(bindings['children'][0]) == '(int)42'
+
+ # "baz_arr[1]":
+ baz_arr_1 = baz_arr['children'][1]
+ assert get_state_node_type(baz_arr_1) == 'struct baz'
+ assert get_state_node_kind(baz_arr_1) == 'element'
+ assert get_state_node_attr(baz_arr_1, 'index') == '1'
+
+ assert len(baz_arr_1['children']) == 1
+
+ # "baz_arr[1].m_bars":
+ baz_arr_1_m_bars = baz_arr_1['children'][0]
+ assert get_state_node_name(baz_arr_1_m_bars) == 'm_bars'
+ assert get_state_node_type(baz_arr_1_m_bars) == 'struct bar[2]'
+
+ # "baz_arr[1].m_bars[1]"
+ baz_arr_1_m_bars_1 = baz_arr_1_m_bars['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1) == 'struct bar'
+ assert get_state_node_kind(baz_arr_1_m_bars_1) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1, 'index') == '1'
+
+ # "baz_arr[1].m_bars[1].m_foos"
+ baz_arr_1_m_bars_1_m_foos = baz_arr_1_m_bars_1['children'][0]
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos) == 'field'
+ assert get_state_node_name(baz_arr_1_m_bars_1_m_foos) == 'm_foos'
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos) == 'struct foo[3]'
+
+ # "baz_arr[1].m_bars[1].m_foos[2]"
+ baz_arr_1_m_bars_1_m_foos_2 = baz_arr_1_m_bars_1_m_foos['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2) == 'struct foo'
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1_m_foos_2, 'index') == '2'
+
+ # "baz_arr[1].m_bars[1].m_foos[2].m_ints"
+ baz_arr_1_m_bars_1_m_foos_2_m_ints = baz_arr_1_m_bars_1_m_foos_2['children'][0]
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'field'
+ assert get_state_node_name(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'm_ints'
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'int[4]'
+
+ # "baz_arr[1].m_bars[1].m_foos[2].m_ints[1]"
+ baz_arr_1_m_bars_1_m_foos_2_m_ints_1 = baz_arr_1_m_bars_1_m_foos_2_m_ints['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == 'int'
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1_m_foos_2_m_ints_1, 'index') == '1'
+ assert get_state_node_value(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == '(int)42'
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c b/gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c
index fbfe570..194c99a 100644
--- a/gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c
@@ -8,7 +8,7 @@ ky (int);
void
wd (void)
{
- tz = 0;
+ tz = 0; /* { dg-message "using NULL here" } */
ky (*tz); /* { dg-warning "dereference of NULL" } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c b/gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c
index 57b8acd..b40be66 100644
--- a/gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c
@@ -68,7 +68,7 @@ extern void check_init_u32 (__u32 v);
/* Adapted/reduced from arch/x86/kernel/cpu/mtrr/if.c: mtrr_ioctl,
which is GPL-2.0 */
-long mtrr_ioctl(unsigned int cmd, unsigned long __arg) {
+long mtrr_ioctl(unsigned int cmd, __UINTPTR_TYPE__ __arg) {
int err = 0;
struct mtrr_sentry sentry;
struct mtrr_gentry gentry;