@@ -88,6 +88,12 @@ source location
the SARIF logicalLocation ``decoratedName`` property
(SARIF v2.1.0 `§3.33.6 <https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790975>`_).
+ Repeated calls to :func:`diagnostic_manager_new_logical_location` with
+ "equal" input values on the same :type:`diagnostic_manager` will return
+ the same instance of :type:`diagnostic_logical_location`. "Equal" here
+ includes different string buffers that compare as equal with
+ :func:``strcmp`.
+
.. function:: void diagnostic_manager_debug_dump_logical_location (const diagnostic_manager *diag_mgr, \
const diagnostic_logical_location *loc, \
FILE *out)
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MAP
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
@@ -43,6 +44,15 @@ public:
: m_str (str ? ::xstrdup (str) : nullptr)
{
}
+ owned_nullable_string (const owned_nullable_string &other)
+ : m_str (other.xstrdup ())
+ {
+ }
+ owned_nullable_string (owned_nullable_string &&other)
+ {
+ m_str = other.m_str;
+ other.m_str = nullptr;
+ }
~owned_nullable_string ()
{
@@ -62,6 +72,16 @@ public:
return m_str ? ::xstrdup (m_str) : nullptr;
}
+ bool
+ operator< (const owned_nullable_string &other) const
+ {
+ if (m_str && other.m_str)
+ return strcmp (m_str, other.m_str) < 0;
+ if (m_str == nullptr && other.m_str != nullptr)
+ return true;
+ return false;
+ }
+
private:
char *m_str;
};
@@ -205,6 +225,23 @@ struct diagnostic_logical_location : public logical_location
return label_text::borrow (m_short_name.get_str ());
}
+ bool
+ operator< (const diagnostic_logical_location &other) const
+ {
+ if (m_kind < other.m_kind)
+ return true;
+ if (m_parent < other.m_parent)
+ return true;
+ if (m_short_name < other.m_short_name)
+ return true;
+ if (m_fully_qualified_name < other.m_fully_qualified_name)
+ return true;
+ if (m_decorated_name < other.m_decorated_name)
+ return true;
+
+ return false;
+ }
+
private:
enum diagnostic_logical_location_kind_t m_kind;
const diagnostic_logical_location *m_parent;
@@ -445,6 +482,16 @@ public:
const char *fully_qualified_name,
const char *decorated_name)
{
+ /* Use m_logical_locs to "uniquify" instances. */
+ diagnostic_logical_location key (kind,
+ parent,
+ short_name,
+ fully_qualified_name,
+ decorated_name);
+ auto iter = m_logical_locs.find (key);
+ if (iter != m_logical_locs.end ())
+ return (*iter).second.get ();
+
std::unique_ptr<diagnostic_logical_location> logical_loc
= ::make_unique<diagnostic_logical_location> (kind,
parent,
@@ -452,7 +499,9 @@ public:
fully_qualified_name,
decorated_name);
const diagnostic_logical_location *result = logical_loc.get ();
- m_logical_locs.push_back (std::move (logical_loc));
+ m_logical_locs.insert
+ (logical_locs_map_t::value_type (std::move (key),
+ std::move (logical_loc)));
return result;
}
@@ -552,7 +601,9 @@ private:
hash_map<nofree_string_hash, diagnostic_file *> m_str_to_file_map;
hash_map<int_hash<location_t, UNKNOWN_LOCATION, location_t (-1)>,
diagnostic_physical_location *> m_location_t_map;
- std::vector<std::unique_ptr<diagnostic_logical_location>> m_logical_locs;
+ typedef std::map<diagnostic_logical_location,
+ std::unique_ptr<diagnostic_logical_location>> logical_locs_map_t;
+ logical_locs_map_t m_logical_locs;
const diagnostic *m_current_diag;
const diagnostic_logical_location *m_prev_diag_logical_loc;
std::unique_ptr<edit_context> m_edit_context;
@@ -758,8 +809,7 @@ struct diagnostic_execution_path : public diagnostic_path
const logical_location *logical_loc_b
= m_events[event_idx_b]->get_logical_location ();
- // TODO:
- /* Pointer equality, so we may want to uniqify logical loc ptrs. */
+ /* Pointer equality, as we uniqify logical location instances. */
return logical_loc_a == logical_loc_b;
}
@@ -19,6 +19,8 @@ PRINT "hello world!";
*/
const int line_num = __LINE__ - 2;
+#include <assert.h>
+
int
main ()
{
@@ -60,6 +62,17 @@ main ()
diagnostic_finish (d, "can't find %qs", "foo");
/* end quoted source */
+ /* Verify that creating a diagnostic_logical_location with equal values
+ yields the same instance. */
+ const diagnostic_logical_location *dup
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "test_short_name",
+ "test_qualified_name",
+ "test_decorated_name");
+ assert (dup == logical_loc);
+
return end_test ();
}
new file mode 100644
@@ -0,0 +1,402 @@
+/* Test a replay of a .sarif file generated from GCC testsuite.
+
+ The dg directives were stripped out from the generated .sarif
+ to avoid confusing DejaGnu for this test. */
+
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "GNU C23",
+ "fullName": "GNU C23 (GCC) version 15.0.0 20241211 (experimental) (x86_64-pc-linux-gnu)",
+ "version": "15.0.0 20241211 (experimental)",
+ "informationUri": "https://gcc.gnu.org/gcc-15/",
+ "rules": [{"id": "-Wanalyzer-possible-null-dereference",
+ "helpUri": "https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-possible-null-dereference"},
+ {"id": "-Wanalyzer-double-free",
+ "helpUri": "https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-free"}]}},
+ "taxonomies": [{"name": "CWE",
+ "version": "4.7",
+ "organization": "MITRE",
+ "shortDescription": {"text": "The MITRE Common Weakness Enumeration"},
+ "taxa": [{"id": "690",
+ "helpUri": "https://cwe.mitre.org/data/definitions/690.html"},
+ {"id": "415",
+ "helpUri": "https://cwe.mitre.org/data/definitions/415.html"}]}],
+ "invocations": [{"arguments": ["./cc1",
+ "-quiet",
+ "-iprefix",
+ "/home/david/coding/gcc-newgit-more-taint/build-with-libgdiagnostics/gcc/../lib/gcc/x86_64-pc-linux-gnu/15.0.0/",
+ "-isystem",
+ "./include",
+ "-isystem",
+ "./include-fixed",
+ "/not/a/real/path/malloc-vs-local-4.c",
+ "-quiet",
+ "-dumpbase",
+ "malloc-vs-local-4.c",
+ "-dumpbase-ext",
+ ".c",
+ "-mtune=generic",
+ "-march=x86-64",
+ "-fanalyzer",
+ "-fdiagnostics-add-output=sarif",
+ "-o",
+ "malloc-vs-local-4.s"],
+ "workingDirectory": {"uri": "/home/david/coding/gcc-newgit-more-taint/build-with-libgdiagnostics/gcc"},
+ "startTimeUtc": "2024-12-12T22:09:12Z",
+ "executionSuccessful": true,
+ "toolExecutionNotifications": [],
+ "endTimeUtc": "2024-12-12T22:09:12Z"}],
+ "originalUriBaseIds": {"PWD": {"uri": "file:///home/david/coding/gcc-newgit-more-taint/build-with-libgdiagnostics/gcc/"}},
+ "artifacts": [{"location": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "sourceLanguage": "c",
+ "contents": {"text": "#include <stdlib.h>\n\nvoid __attribute__((noinline)) callee_1 (int *ptr)\n{\n *ptr = 42; \n}\n\nint test_1 (int i, int flag)\n{\n /* Double diamond CFG; either use &i, or a malloc-ed buffer. */\n int *ptr = &i;\n if (flag)\n ptr = (int *)malloc (sizeof (int));\n callee_1 (ptr);\n if (flag)\n free (ptr);\n return i;\n}\n\nvoid __attribute__((noinline)) callee_2 (int *ptr)\n{\n *ptr = 42;\n}\n\nint test_2 (int flag)\n{\n int i;\n\n if (flag)\n callee_2 (&i);\n\n callee_2 (&i);\n\n if (!flag)\n {\n void *ptr = malloc (16);\n free (ptr);\n free (ptr);\n }\n}\n"},
+ "roles": ["analysisTarget",
+ "tracedFile"]}],
+ "results": [{"ruleId": "-Wanalyzer-possible-null-dereference",
+ "taxa": [{"id": "690",
+ "toolComponent": {"name": "cwe"}}],
+ "properties": {"gcc/analyzer/saved_diagnostic/sm": "malloc",
+ "gcc/analyzer/saved_diagnostic/enode": 78,
+ "gcc/analyzer/saved_diagnostic/snode": 22,
+ "gcc/analyzer/saved_diagnostic/sval": "&HEAP_ALLOCATED_REGION(46)",
+ "gcc/analyzer/saved_diagnostic/state": "unchecked ({free})",
+ "gcc/analyzer/saved_diagnostic/idx": 1},
+ "level": "warning",
+ "message": {"text": "dereference of possibly-NULL ‘ptr’"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 5,
+ "startColumn": 3,
+ "endColumn": 12},
+ "contextRegion": {"startLine": 5,
+ "snippet": {"text": " *ptr = 42;\n"}}},
+ "logicalLocations": [{"name": "callee_1",
+ "fullyQualifiedName": "callee_1",
+ "decoratedName": "callee_1",
+ "kind": "function"}]}],
+ "codeFlows": [{"threadFlows": [{"id": "main",
+ "locations": [{"properties": {"gcc/analyzer/checker_event/emission_id": "(1)",
+ "gcc/analyzer/checker_event/kind": "EK_FUNCTION_ENTRY"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 8,
+ "startColumn": 5,
+ "endColumn": 11},
+ "contextRegion": {"startLine": 8,
+ "snippet": {"text": "int test_1 (int i, int flag)\n"}}},
+ "logicalLocations": [{"name": "test_1",
+ "fullyQualifiedName": "test_1",
+ "decoratedName": "test_1",
+ "kind": "function"}],
+ "message": {"text": "entry to ‘test_1’"}},
+ "kinds": ["enter",
+ "function"],
+ "nestingLevel": 1,
+ "executionOrder": 1},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(2)",
+ "gcc/analyzer/checker_event/kind": "EK_START_CFG_EDGE",
+ "gcc/analyzer/superedge_event/superedge": {"kind": "SUPEREDGE_CFG_EDGE",
+ "src_idx": 13,
+ "dst_idx": 14,
+ "desc": "true (flags TRUE_VALUE) (has goto_locus)"}},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 12,
+ "startColumn": 6,
+ "endColumn": 7},
+ "contextRegion": {"startLine": 12,
+ "snippet": {"text": " if (flag)\n"}}},
+ "logicalLocations": [{"name": "test_1",
+ "fullyQualifiedName": "test_1",
+ "decoratedName": "test_1",
+ "kind": "function"}],
+ "message": {"text": "following ‘true’ branch (when ‘flag != 0’)..."}},
+ "kinds": ["branch",
+ "true"],
+ "nestingLevel": 1,
+ "executionOrder": 2},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(3)",
+ "gcc/analyzer/checker_event/kind": "EK_END_CFG_EDGE",
+ "gcc/analyzer/superedge_event/superedge": {"kind": "SUPEREDGE_CFG_EDGE",
+ "src_idx": 13,
+ "dst_idx": 14,
+ "desc": "true (flags TRUE_VALUE) (has goto_locus)"}},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 13,
+ "startColumn": 18,
+ "endColumn": 39},
+ "contextRegion": {"startLine": 13,
+ "snippet": {"text": " ptr = (int *)malloc (sizeof (int));\n"}}},
+ "logicalLocations": [{"name": "test_1",
+ "fullyQualifiedName": "test_1",
+ "decoratedName": "test_1",
+ "kind": "function"}],
+ "message": {"text": "...to here"}},
+ "kinds": ["branch",
+ "true"],
+ "nestingLevel": 1,
+ "executionOrder": 3},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(4)",
+ "gcc/analyzer/checker_event/kind": "EK_STATE_CHANGE"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 13,
+ "startColumn": 18,
+ "endColumn": 39},
+ "contextRegion": {"startLine": 13,
+ "snippet": {"text": " ptr = (int *)malloc (sizeof (int));\n"}}},
+ "logicalLocations": [{"name": "test_1",
+ "fullyQualifiedName": "test_1",
+ "decoratedName": "test_1",
+ "kind": "function"}],
+ "message": {"text": "this call could return NULL"}},
+ "kinds": ["acquire",
+ "memory"],
+ "nestingLevel": 1,
+ "executionOrder": 4},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(5)",
+ "gcc/analyzer/checker_event/kind": "EK_CALL_EDGE",
+ "gcc/analyzer/superedge_event/superedge": {"kind": "SUPEREDGE_CALL",
+ "src_idx": 15,
+ "dst_idx": 21,
+ "desc": "call"}},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 14,
+ "startColumn": 3,
+ "endColumn": 17},
+ "contextRegion": {"startLine": 14,
+ "snippet": {"text": " callee_1 (ptr);\n"}}},
+ "logicalLocations": [{"name": "test_1",
+ "fullyQualifiedName": "test_1",
+ "decoratedName": "test_1",
+ "kind": "function"}],
+ "message": {"text": "calling ‘callee_1’ from ‘test_1’"}},
+ "kinds": ["call",
+ "function"],
+ "nestingLevel": 1,
+ "executionOrder": 5},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(6)",
+ "gcc/analyzer/checker_event/kind": "EK_FUNCTION_ENTRY"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 3,
+ "startColumn": 32,
+ "endColumn": 40},
+ "contextRegion": {"startLine": 3,
+ "snippet": {"text": "void __attribute__((noinline)) callee_1 (int *ptr)\n"}}},
+ "logicalLocations": [{"name": "callee_1",
+ "fullyQualifiedName": "callee_1",
+ "decoratedName": "callee_1",
+ "kind": "function"}],
+ "message": {"text": "entry to ‘callee_1’"}},
+ "kinds": ["enter",
+ "function"],
+ "nestingLevel": 2,
+ "executionOrder": 6},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(7)",
+ "gcc/analyzer/checker_event/kind": "EK_WARNING"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 5,
+ "startColumn": 3,
+ "endColumn": 12},
+ "contextRegion": {"startLine": 5,
+ "snippet": {"text": " *ptr = 42;\n"}}},
+ "logicalLocations": [{"name": "callee_1",
+ "fullyQualifiedName": "callee_1",
+ "decoratedName": "callee_1",
+ "kind": "function"}],
+ "message": {"text": "‘ptr’ could be NULL: unchecked value from [(4)](sarif:/runs/0/results/0/codeFlows/0/threadFlows/0/locations/3)"}},
+ "kinds": ["danger"],
+ "nestingLevel": 2,
+ "executionOrder": 7}]}]}]},
+ {"ruleId": "-Wanalyzer-double-free",
+ "taxa": [{"id": "415",
+ "toolComponent": {"name": "cwe"}}],
+ "properties": {"gcc/analyzer/saved_diagnostic/sm": "malloc",
+ "gcc/analyzer/saved_diagnostic/enode": 39,
+ "gcc/analyzer/saved_diagnostic/snode": 6,
+ "gcc/analyzer/saved_diagnostic/sval": "&HEAP_ALLOCATED_REGION(46)",
+ "gcc/analyzer/saved_diagnostic/state": "freed",
+ "gcc/analyzer/saved_diagnostic/idx": 0},
+ "level": "warning",
+ "message": {"text": "double-‘free’ of ‘ptr’"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 38,
+ "startColumn": 7,
+ "endColumn": 17},
+ "contextRegion": {"startLine": 38,
+ "snippet": {"text": " free (ptr);\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}]}],
+ "codeFlows": [{"threadFlows": [{"id": "main",
+ "locations": [{"properties": {"gcc/analyzer/checker_event/emission_id": "(1)",
+ "gcc/analyzer/checker_event/kind": "EK_START_CFG_EDGE",
+ "gcc/analyzer/superedge_event/superedge": {"kind": "SUPEREDGE_CFG_EDGE",
+ "src_idx": 5,
+ "dst_idx": 6,
+ "desc": "true (flags TRUE_VALUE) (has goto_locus)"}},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 34,
+ "startColumn": 6,
+ "endColumn": 7},
+ "contextRegion": {"startLine": 34,
+ "snippet": {"text": " if (!flag)\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}],
+ "message": {"text": "following ‘true’ branch (when ‘flag == 0’)..."}},
+ "kinds": ["branch",
+ "true"],
+ "nestingLevel": 1,
+ "executionOrder": 1},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(2)",
+ "gcc/analyzer/checker_event/kind": "EK_END_CFG_EDGE",
+ "gcc/analyzer/superedge_event/superedge": {"kind": "SUPEREDGE_CFG_EDGE",
+ "src_idx": 5,
+ "dst_idx": 6,
+ "desc": "true (flags TRUE_VALUE) (has goto_locus)"}},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 36,
+ "startColumn": 19,
+ "endColumn": 30},
+ "contextRegion": {"startLine": 36,
+ "snippet": {"text": " void *ptr = malloc (16);\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}],
+ "message": {"text": "...to here"}},
+ "kinds": ["branch",
+ "true"],
+ "nestingLevel": 1,
+ "executionOrder": 2},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(3)",
+ "gcc/analyzer/checker_event/kind": "EK_STATE_CHANGE"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 36,
+ "startColumn": 19,
+ "endColumn": 30},
+ "contextRegion": {"startLine": 36,
+ "snippet": {"text": " void *ptr = malloc (16);\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}],
+ "message": {"text": "allocated here"}},
+ "kinds": ["acquire",
+ "memory"],
+ "nestingLevel": 1,
+ "executionOrder": 3},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(4)",
+ "gcc/analyzer/checker_event/kind": "EK_STATE_CHANGE"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 37,
+ "startColumn": 7,
+ "endColumn": 17},
+ "contextRegion": {"startLine": 37,
+ "snippet": {"text": " free (ptr);\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}],
+ "message": {"text": "first ‘free’ here"}},
+ "kinds": ["release",
+ "memory"],
+ "nestingLevel": 1,
+ "executionOrder": 4},
+ {"properties": {"gcc/analyzer/checker_event/emission_id": "(5)",
+ "gcc/analyzer/checker_event/kind": "EK_WARNING"},
+ "location": {"physicalLocation": {"artifactLocation": {"uri": "/not/a/real/path/malloc-vs-local-4.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 38,
+ "startColumn": 7,
+ "endColumn": 17},
+ "contextRegion": {"startLine": 38,
+ "snippet": {"text": " free (ptr);\n"}}},
+ "logicalLocations": [{"name": "test_2",
+ "fullyQualifiedName": "test_2",
+ "decoratedName": "test_2",
+ "kind": "function"}],
+ "message": {"text": "second ‘free’ here; first ‘free’ was at [(4)](sarif:/runs/0/results/1/codeFlows/0/threadFlows/0/locations/3)"}},
+ "kinds": ["danger"],
+ "nestingLevel": 1,
+ "executionOrder": 5}]}]}]}]}]}
+// TODO: show the CWEs
+// TODO: fix URL in message
+
+/* { dg-begin-multiline-output "" }
+In function 'callee_1':
+/not/a/real/path/malloc-vs-local-4.c:5:3: warning: dereference of possibly-NULL ‘ptr’ [-Wanalyzer-possible-null-dereference]
+ 5 | *ptr = 42;
+ | ^~~~~~~~~~
+ 'test_1': events 1-5
+ |
+ | 8 | int test_1 (int i, int flag)
+ | | ^~~~~~~
+ | | |
+ | | (1) entry to ‘test_1’
+ |......
+ | 12 | if (flag)
+ | | ~~
+ | | |
+ | | (2) following ‘true’ branch (when ‘flag != 0’)...
+ | 13 | ptr = (int *)malloc (sizeof (int));
+ | | ~~~~~~~~~~~~~~~~~~~~~~
+ | | |
+ | | (3) ...to here
+ | | (4) this call could return NULL
+ | 14 | callee_1 (ptr);
+ | | ~~~~~~~~~~~~~~~
+ | | |
+ | | (5) calling ‘callee_1’ from ‘test_1’
+ |
+ +--> 'callee_1': events 6-7
+ |
+ | 3 | void __attribute__((noinline)) callee_1 (int *ptr)
+ | | ^~~~~~~~~
+ | | |
+ | | (6) entry to ‘callee_1’
+ | 4 | {
+ | 5 | *ptr = 42;
+ | | ~~~~~~~~~~
+ | | |
+ | | (7) ‘ptr’ could be NULL: unchecked value from [(4)](sarif:/runs/0/results/0/codeFlows/0/threadFlows/0/locations/3)
+ |
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+In function 'test_2':
+/not/a/real/path/malloc-vs-local-4.c:38:7: warning: double-‘free’ of ‘ptr’ [-Wanalyzer-double-free]
+ 38 | free (ptr);
+ | ^~~~~~~~~~~
+ 'test_2': events 1-5
+ 34 | if (!flag)
+ | ^~
+ | |
+ | (1) following ‘true’ branch (when ‘flag == 0’)...
+ 35 | {
+ 36 | void *ptr = malloc (16);
+ | ~~~~~~~~~~~~
+ | |
+ | (2) ...to here
+ | (3) allocated here
+ 37 | free (ptr);
+ | ~~~~~~~~~~~
+ | |
+ | (4) first ‘free’ here
+ 38 | free (ptr);
+ | ~~~~~~~~~~~
+ | |
+ | (5) second ‘free’ here; first ‘free’ was at [(4)](sarif:/runs/0/results/1/codeFlows/0/threadFlows/0/locations/3)
+ { dg-end-multiline-output "" } */
@@ -167,20 +167,19 @@
// TODO: show the CWE
/* { dg-begin-multiline-output "" }
+In function 'custom_logger':
signal-1.c:13:3: warning: call to ‘fprintf’ from within signal handler [-Wanalyzer-unsafe-call-within-signal-handler]
13 | fprintf(stderr, "LOG: %s", msg);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 'main': event 1
+ 'main': events 1-2
|
| 21 | int main(int argc, const char *argv)
| | ^~~~~
| | |
| | (1) entry to ‘main’
- |
- 'main': event 2
- |
+ |......
| 25 | signal(SIGINT, handler);
- | | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) registering ‘handler’ as signal handler
|
@@ -189,31 +188,27 @@ signal-1.c:13:3: warning: call to ‘fprintf’ from within signal handler [-Wan
|GNU C17:
| (3): later on, when the signal is delivered to the process
|
- +--> 'handler': event 4
+ +--> 'handler': events 4-5
|
| 16 | static void handler(int signum)
| | ^~~~~~~~
| | |
| | (4) entry to ‘handler’
- |
- 'handler': event 5
- |
+ | 17 | {
| 18 | custom_logger("got signal");
- | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (5) calling ‘custom_logger’ from ‘handler’
|
- +--> 'custom_logger': event 6
+ +--> 'custom_logger': events 6-7
|
| 11 | void custom_logger(const char *msg)
| | ^~~~~~~~~~~~~~
| | |
| | (6) entry to ‘custom_logger’
- |
- 'custom_logger': event 7
- |
+ | 12 | {
| 13 | fprintf(stderr, "LOG: %s", msg);
- | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (7) call to ‘fprintf’ from within signal handler
|
@@ -165,20 +165,19 @@
// TODO: show the CWE
/* { dg-begin-multiline-output "" }
+In function 'custom_logger':
../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c:13:3: warning: call to ‘fprintf’ from within signal handler [-Wanalyzer-unsafe-call-within-signal-handler]
13 | fprintf(stderr, "LOG: %s", msg);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 'main': event 1
+ 'main': events 1-2
|
| 21 | int main(int argc, const char *argv)
| | ^~~~~
| | |
| | (1) entry to ‘main’
- |
- 'main': event 2
- |
+ |......
| 25 | signal(SIGINT, handler);
- | | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) registering ‘handler’ as signal handler
|
@@ -187,31 +186,27 @@
|GNU C17:
| (3): later on, when the signal is delivered to the process
|
- +--> 'handler': event 4
+ +--> 'handler': events 4-5
|
| 16 | static void handler(int signum)
| | ^~~~~~~~
| | |
| | (4) entry to ‘handler’
- |
- 'handler': event 5
- |
+ | 17 | {
| 18 | custom_logger("got signal");
- | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (5) calling ‘custom_logger’ from ‘handler’
|
- +--> 'custom_logger': event 6
+ +--> 'custom_logger': events 6-7
|
| 11 | void custom_logger(const char *msg)
| | ^~~~~~~~~~~~~~
| | |
| | (6) entry to ‘custom_logger’
- |
- 'custom_logger': event 7
- |
+ | 12 | {
| 13 | fprintf(stderr, "LOG: %s", msg);
- | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (7) call to ‘fprintf’ from within signal handler
|
@@ -749,15 +749,8 @@
/* { dg-begin-multiline-output "" }
In function 'collections::list::add':
collections/list.h:15:9: error: Variable "ptr" was used without being initialized. It was declared [here](0). [C2001]
- event 1
- |
- |
- event 2
- |
- |
- event 3
- |
- |
+ events 1-3
+......
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
collections/list.h:8:5: note: Variable "ptr" was declared here.
This patch updates diagnostic_manager_new_logical_location so that repeated calls with the same input values yield the same instance of diagnostic_logical_location. Doing so allows the path-printing logic to properly consolidate runs of events, whereas previously it could treat each event as having a distinct logical location, and thus require them to be printed separately; this greatly improves the output of sarif-replay when displaying execution paths. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r15-6285-g2af541920787e3. gcc/ChangeLog: * doc/libgdiagnostics/topics/logical-locations.rst (diagnostic_manager_new_logical_location): Add note about repeated calls. * libgdiagnostics.cc: Define INCLUDE_MAP. (class owned_nullable_string): Add copy ctor and move ctor. (owned_nullable_string::operator<): New. (diagnostic_logical_location::operator<): New. (diagnostic_manager::new_logical_location): Use m_logical_locs to "uniquify" instances, converting it to a std::map. (diagnostic_manager::logical_locs_map_t): New typedef. (diagnostic_manager::t m_logical_locs): Convert from a std::vector to a std::map. (diagnostic_execution_path::same_function_p): Update comment. gcc/testsuite/ChangeLog: * libgdiagnostics.dg/test-logical-location.c: Include <assert.h>. Verify that creating a diagnostic_logical_location with equal values yields the same instance. * sarif-replay.dg/2.1.0-valid/malloc-vs-local-4.c.sarif: New test. * sarif-replay.dg/2.1.0-valid/signal-1.c.moved.sarif: Update expected output to show logical location and for consolidation of events into runs. * sarif-replay.dg/2.1.0-valid/signal-1.c.sarif: Likewise. * sarif-replay.dg/2.1.0-valid/spec-example-4.sarif: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- .../topics/logical-locations.rst | 6 + gcc/libgdiagnostics.cc | 58 ++- .../test-logical-location.c | 13 + .../2.1.0-valid/malloc-vs-local-4.c.sarif | 402 ++++++++++++++++++ .../2.1.0-valid/signal-1.c.moved.sarif | 25 +- .../2.1.0-valid/signal-1.c.sarif | 25 +- .../2.1.0-valid/spec-example-4.sarif | 11 +- 7 files changed, 497 insertions(+), 43 deletions(-) create mode 100644 gcc/testsuite/sarif-replay.dg/2.1.0-valid/malloc-vs-local-4.c.sarif