blob: 3671e8d7d8d3dce537a794579591eab11f736e95 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# We expect an aanalyzer warning with a path, referencing the #include
# both in the warning and in the events within its execution path.
# In textual form, we'd expect something like:
# . In file included from PATH/include-chain-2.c:28:
# . PATH/include-chain-2.h: In function 'test':
# . PATH/include-chain-2.h:6:3: warning: double-'free' of 'ptr' [CWE-415] [-Wanalyzer-double-free]
# . 6 | __builtin_free (ptr);
# . | ^~~~~~~~~~~~~~~~~~~~
# . 'test': events 1-2
# . 5 | __builtin_free (ptr);
# . | ^~~~~~~~~~~~~~~~~~~~
# . | |
# . | (1) first 'free' here
# . 6 | __builtin_free (ptr);
# . | ~~~~~~~~~~~~~~~~~~~~
# . | |
# . | (2) second 'free' here; first 'free' was at (1)
from sarif import *
import pytest
@pytest.fixture(scope='function', autouse=True)
def sarif():
return sarif_from_env()
def test_basics(sarif):
schema = sarif['$schema']
assert schema == "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json"
version = sarif['version']
assert version == "2.1.0"
def test_execution_successful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
# We expect a mere 'warning' to allow executionSuccessful be true
assert invocation['executionSuccessful'] == True
def test_result(sarif):
runs = sarif['runs']
run = runs[0]
results = run['results']
assert len(results) == 1
result = results[0]
assert result['ruleId'] == '-Wanalyzer-double-free'
assert result['level'] == 'warning'
assert result['message']['text'] == "double-'free' of 'ptr'"
assert result["taxa"] == [{"id": "415",
"toolComponent": {"name": "cwe"}}]
def test_location_relationships(sarif):
runs = sarif['runs']
run = runs[0]
results = run['results']
assert len(results) == 1
result = results[0]
locations = result['locations']
assert len(locations) == 1
location = locations[0]
assert 'id' in location
assert get_location_artifact_uri(location).endswith('include-chain-2.h')
assert get_location_snippet_text(location) == " __builtin_free (ptr); // 2nd\n"
# We expect one related location, describing the #include
relatedLocations = result['relatedLocations']
assert len(relatedLocations) == 1
# The "#include "include-chain-1.h" line in include-chain-1.c:
hash_include_2_h = relatedLocations[0]
assert 'id' in hash_include_2_h
assert get_location_snippet_text(hash_include_2_h) == '#include "include-chain-2.h"\n'
assert get_location_artifact_uri(hash_include_2_h).endswith('include-chain-2.c')
# We expect an execution path
assert len(result['codeFlows']) == 1
codeFlow = result['codeFlows'][0]
assert len(codeFlow['threadFlows']) == 1
threadFlow = codeFlow['threadFlows'][0]
assert threadFlow['id'] == 'main'
assert len(threadFlow['locations']) == 2
assert threadFlow['locations'][0]['location']['message']['text'] \
== "first 'free' here"
assert threadFlow['locations'][0]['location']['physicalLocation']['contextRegion']['snippet']['text'] \
== " __builtin_free (ptr); // 1st\n"
assert threadFlow['locations'][0]['kinds'] == ['release', 'memory']
assert threadFlow['locations'][0]['executionOrder'] == 1
# We should have an embedded link in this event's message to the
# other event's location within the SARIF file:
assert threadFlow['locations'][1]['location']['message']['text'] \
== "second 'free' here; first 'free' was at [(1)](sarif:/runs/0/results/0/codeFlows/0/threadFlows/0/locations/0)"
assert threadFlow['locations'][1]['location']['physicalLocation']['contextRegion']['snippet']['text'] \
== " __builtin_free (ptr); // 2nd\n"
assert threadFlow['locations'][1]['kinds'] == ['danger']
assert threadFlow['locations'][1]['executionOrder'] == 2
# Check the various relationships; we expect a directed graph of edges
# representing the various "isIncludedBy" and "includes" relationships.
# The primary location should be "isIncludedBy" the "#include "include-chain-2.h" line
assert len(location['relationships']) == 1
assert location['relationships'][0]['target'] == hash_include_2_h['id']
assert location['relationships'][0]['kinds'] == ["isIncludedBy"]
# Similarly, so should the locations within the threadFlow
event0_rels = get_location_relationships(threadFlow['locations'][0]['location'])
assert len(event0_rels) == 1
assert event0_rels[0]['target'] == hash_include_2_h['id']
assert event0_rels[0]['kinds'] == ["isIncludedBy"]
event1_rels = get_location_relationships(threadFlow['locations'][1]['location'])
assert len(event1_rels) == 1
assert event1_rels[0]['target'] == hash_include_2_h['id']
assert event1_rels[0]['kinds'] == ["isIncludedBy"]
# The "#include "include-chain-2.h" line in include-chain-2.c should
# have an "includes" relationship to the main location and to the
# two locations in the execution path:
assert len(hash_include_2_h['relationships']) == 3
assert hash_include_2_h['relationships'][0]['target'] == location['id']
assert hash_include_2_h['relationships'][0]['kinds'] == ["includes"]
assert hash_include_2_h['relationships'][1]['target'] == threadFlow['locations'][0]['location']['id']
assert hash_include_2_h['relationships'][1]['kinds'] == ["includes"]
assert hash_include_2_h['relationships'][2]['target'] == threadFlow['locations'][1]['location']['id']
assert hash_include_2_h['relationships'][2]['kinds'] == ["includes"]
|