diff options
Diffstat (limited to 'gcc/testsuite/gcc.dg/analyzer')
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/data-model-5.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/data-model-5b.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/data-model-5c.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py | 65 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c | 48 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-2.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-3.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-4.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.c | 41 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-5-html.py | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c | 35 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py | 89 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/torture/pr93647.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/torture/switch-3.c | 2 |
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; |