lambda-graphs 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lambda_graphs/__init__.py +18 -0
- lambda_graphs/__main__.py +7 -0
- lambda_graphs/cli.py +183 -0
- lambda_graphs/codeviews/AST/AST.py +120 -0
- lambda_graphs/codeviews/AST/AST_driver.py +37 -0
- lambda_graphs/codeviews/AST/__init__.py +0 -0
- lambda_graphs/codeviews/CFG/CFG.py +42 -0
- lambda_graphs/codeviews/CFG/CFG_c.py +1182 -0
- lambda_graphs/codeviews/CFG/CFG_cpp.py +5604 -0
- lambda_graphs/codeviews/CFG/CFG_driver.py +45 -0
- lambda_graphs/codeviews/CFG/CFG_java.py +1722 -0
- lambda_graphs/codeviews/CFG/__init__.py +0 -0
- lambda_graphs/codeviews/CST/CST_driver.py +70 -0
- lambda_graphs/codeviews/CST/__init__.py +0 -0
- lambda_graphs/codeviews/DFG/DFG_driver.py +42 -0
- lambda_graphs/codeviews/DFG/__init__.py +0 -0
- lambda_graphs/codeviews/SDFG/SDFG.py +135 -0
- lambda_graphs/codeviews/SDFG/SDFG_c.py +2041 -0
- lambda_graphs/codeviews/SDFG/SDFG_cpp.py +4030 -0
- lambda_graphs/codeviews/SDFG/SDFG_java.py +1618 -0
- lambda_graphs/codeviews/SDFG/__init__.py +0 -0
- lambda_graphs/codeviews/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/combined_driver.py +163 -0
- lambda_graphs/tree_parser/__init__.py +0 -0
- lambda_graphs/tree_parser/c_parser.py +565 -0
- lambda_graphs/tree_parser/cpp_parser.py +424 -0
- lambda_graphs/tree_parser/custom_parser.py +66 -0
- lambda_graphs/tree_parser/java_parser.py +254 -0
- lambda_graphs/tree_parser/parser_driver.py +54 -0
- lambda_graphs/utils/DFG_utils.py +44 -0
- lambda_graphs/utils/__init__.py +0 -0
- lambda_graphs/utils/c_nodes.py +431 -0
- lambda_graphs/utils/cpp_nodes.py +1331 -0
- lambda_graphs/utils/java_nodes.py +756 -0
- lambda_graphs/utils/multi_file_merger.py +444 -0
- lambda_graphs/utils/postprocessor.py +83 -0
- lambda_graphs/utils/preprocessor.py +68 -0
- lambda_graphs/utils/src_parser.py +23 -0
- lambda_graphs-0.1.4.dist-info/METADATA +380 -0
- lambda_graphs-0.1.4.dist-info/RECORD +45 -0
- lambda_graphs-0.1.4.dist-info/WHEEL +5 -0
- lambda_graphs-0.1.4.dist-info/entry_points.txt +2 -0
- lambda_graphs-0.1.4.dist-info/licenses/LICENSE +21 -0
- lambda_graphs-0.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2041 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import time
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
|
|
5
|
+
import networkx as nx
|
|
6
|
+
from deepdiff import DeepDiff
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
from ...utils.c_nodes import statement_types
|
|
10
|
+
from ...utils.src_parser import traverse_tree
|
|
11
|
+
|
|
12
|
+
assignment = ["assignment_expression"]
|
|
13
|
+
def_statement = ["init_declarator"]
|
|
14
|
+
declaration_statement = ["declaration"]
|
|
15
|
+
increment_statement = ["update_expression"]
|
|
16
|
+
variable_type = ["identifier"]
|
|
17
|
+
function_calls = ["call_expression"]
|
|
18
|
+
literal_types = [
|
|
19
|
+
"number_literal",
|
|
20
|
+
"string_literal",
|
|
21
|
+
"char_literal",
|
|
22
|
+
"true",
|
|
23
|
+
"false",
|
|
24
|
+
"null",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
input_functions = [
|
|
28
|
+
"scanf",
|
|
29
|
+
"gets",
|
|
30
|
+
"fgets",
|
|
31
|
+
"getline",
|
|
32
|
+
"fscanf",
|
|
33
|
+
"sscanf",
|
|
34
|
+
"fread",
|
|
35
|
+
"read",
|
|
36
|
+
"recv",
|
|
37
|
+
"recvfrom",
|
|
38
|
+
"getchar",
|
|
39
|
+
"fgetc",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
inner_types = ["declaration", "expression_statement"]
|
|
43
|
+
handled_types = (
|
|
44
|
+
assignment
|
|
45
|
+
+ def_statement
|
|
46
|
+
+ increment_statement
|
|
47
|
+
+ function_calls
|
|
48
|
+
+ ["function_definition", "return_statement", "for_statement", "switch_statement"]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
debug = False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def st(child):
|
|
55
|
+
"""Get text from AST node"""
|
|
56
|
+
if child is None:
|
|
57
|
+
return ""
|
|
58
|
+
else:
|
|
59
|
+
return child.text.decode()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_index(node, index):
|
|
63
|
+
"""Get unique index for AST node"""
|
|
64
|
+
try:
|
|
65
|
+
return index[(node.start_point, node.end_point, node.type)]
|
|
66
|
+
except:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def read_index(index, idx):
|
|
71
|
+
"""Get AST node key from index value"""
|
|
72
|
+
return list(index.keys())[list(index.values()).index(idx)]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def scope_check(parent_scope, child_scope):
|
|
76
|
+
"""
|
|
77
|
+
Check if a definition's scope can reach a use's scope.
|
|
78
|
+
|
|
79
|
+
A definition at scope [0, 1, 2] can reach uses at:
|
|
80
|
+
- [0, 1, 2] (same scope)
|
|
81
|
+
- [0, 1, 2, 3] (nested scope)
|
|
82
|
+
|
|
83
|
+
But NOT:
|
|
84
|
+
- [0, 1] (parent scope)
|
|
85
|
+
- [0, 1, 3] (sibling scope)
|
|
86
|
+
"""
|
|
87
|
+
for p in parent_scope:
|
|
88
|
+
if p not in child_scope:
|
|
89
|
+
return False
|
|
90
|
+
return True
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def set_add(lst, item):
|
|
94
|
+
"""Add item to list if not already present (set-like behavior)"""
|
|
95
|
+
for entry in lst:
|
|
96
|
+
if item == entry:
|
|
97
|
+
return
|
|
98
|
+
lst.append(item)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def set_union(first_list, second_list):
|
|
102
|
+
"""Union of two lists (set-like)"""
|
|
103
|
+
resulting_list = list(first_list)
|
|
104
|
+
resulting_list.extend(x for x in second_list if x not in resulting_list)
|
|
105
|
+
return resulting_list
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def set_difference(first_list, second_list):
|
|
109
|
+
"""Difference of two lists (set-like)"""
|
|
110
|
+
return [item for item in first_list if item not in second_list]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def return_first_parent_of_types(node, parent_types, stop_types=None):
|
|
114
|
+
"""Find first parent of given types"""
|
|
115
|
+
if stop_types is None:
|
|
116
|
+
stop_types = []
|
|
117
|
+
|
|
118
|
+
if node.type in parent_types:
|
|
119
|
+
return node
|
|
120
|
+
|
|
121
|
+
while node.parent is not None:
|
|
122
|
+
if node.type in stop_types:
|
|
123
|
+
return None
|
|
124
|
+
if node.parent.type in parent_types:
|
|
125
|
+
return node.parent
|
|
126
|
+
node = node.parent
|
|
127
|
+
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def recursively_get_children_of_types(
|
|
132
|
+
node, st_types, check_list=None, index=None, result=None, stop_types=None
|
|
133
|
+
):
|
|
134
|
+
"""Recursively find child nodes of given types"""
|
|
135
|
+
if isinstance(st_types, str):
|
|
136
|
+
st_types = [st_types]
|
|
137
|
+
if stop_types is None:
|
|
138
|
+
stop_types = []
|
|
139
|
+
if result is None:
|
|
140
|
+
result = []
|
|
141
|
+
|
|
142
|
+
if node.type in stop_types:
|
|
143
|
+
return result
|
|
144
|
+
|
|
145
|
+
if check_list and index:
|
|
146
|
+
result.extend(
|
|
147
|
+
[
|
|
148
|
+
child
|
|
149
|
+
for child in node.children
|
|
150
|
+
if child.type in st_types and get_index(child, index) in check_list
|
|
151
|
+
]
|
|
152
|
+
)
|
|
153
|
+
else:
|
|
154
|
+
result.extend([child for child in node.children if child.type in st_types])
|
|
155
|
+
|
|
156
|
+
for child in node.named_children:
|
|
157
|
+
if child.type not in stop_types:
|
|
158
|
+
result = recursively_get_children_of_types(
|
|
159
|
+
child,
|
|
160
|
+
st_types,
|
|
161
|
+
result=result,
|
|
162
|
+
stop_types=stop_types,
|
|
163
|
+
index=index,
|
|
164
|
+
check_list=check_list,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class Identifier:
|
|
171
|
+
"""Represents a variable at a specific line with scope information"""
|
|
172
|
+
|
|
173
|
+
def __init__(self, parser, node, line=None, declaration=False, full_ref=None):
|
|
174
|
+
self.core = st(node)
|
|
175
|
+
self.unresolved_name = st(full_ref) if full_ref else st(node)
|
|
176
|
+
self.name = self._resolve_name(node, full_ref, parser)
|
|
177
|
+
self.line = line
|
|
178
|
+
self.declaration = declaration
|
|
179
|
+
self.satisfied = False
|
|
180
|
+
|
|
181
|
+
variable_index = get_index(node, parser.index)
|
|
182
|
+
if variable_index and variable_index in parser.symbol_table["scope_map"]:
|
|
183
|
+
self.variable_scope = parser.symbol_table["scope_map"][variable_index]
|
|
184
|
+
if variable_index in parser.declaration_map:
|
|
185
|
+
decl_index = parser.declaration_map[variable_index]
|
|
186
|
+
self.scope = parser.symbol_table["scope_map"].get(decl_index, [0])
|
|
187
|
+
else:
|
|
188
|
+
self.scope = [0]
|
|
189
|
+
|
|
190
|
+
if declaration:
|
|
191
|
+
self.scope = self.variable_scope
|
|
192
|
+
else:
|
|
193
|
+
self.variable_scope = [0]
|
|
194
|
+
self.scope = [0]
|
|
195
|
+
|
|
196
|
+
if line is not None:
|
|
197
|
+
self.real_line_no = read_index(parser.index, line)[0][0]
|
|
198
|
+
|
|
199
|
+
def _resolve_name(self, node, full_ref, parser):
|
|
200
|
+
"""Resolve identifier name for C"""
|
|
201
|
+
if full_ref is None:
|
|
202
|
+
return st(node)
|
|
203
|
+
|
|
204
|
+
if full_ref.type == "field_expression":
|
|
205
|
+
obj = full_ref.child_by_field_name("argument")
|
|
206
|
+
field = full_ref.child_by_field_name("field")
|
|
207
|
+
return st(obj) + "." + st(field)
|
|
208
|
+
|
|
209
|
+
if full_ref.type == "pointer_expression":
|
|
210
|
+
arg = full_ref.child_by_field_name("argument")
|
|
211
|
+
return "*" + st(arg)
|
|
212
|
+
|
|
213
|
+
if full_ref.type == "subscript_expression":
|
|
214
|
+
arg = full_ref.child_by_field_name("argument")
|
|
215
|
+
return st(arg)
|
|
216
|
+
|
|
217
|
+
return st(node)
|
|
218
|
+
|
|
219
|
+
def __eq__(self, other):
|
|
220
|
+
return (
|
|
221
|
+
self.name == other.name
|
|
222
|
+
and self.line == other.line
|
|
223
|
+
and sorted(self.scope) == sorted(other.scope)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def __hash__(self):
|
|
227
|
+
return hash((self.name, self.line, str(self.scope)))
|
|
228
|
+
|
|
229
|
+
def __str__(self):
|
|
230
|
+
result = [self.name]
|
|
231
|
+
if self.line:
|
|
232
|
+
result += [str(self.real_line_no)]
|
|
233
|
+
result += ["|".join(map(str, self.scope))]
|
|
234
|
+
else:
|
|
235
|
+
result += ["?"]
|
|
236
|
+
return f"{{{','.join(result)}}}"
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class Literal:
|
|
240
|
+
"""Represents a literal constant (number, string, etc.) as a data flow source"""
|
|
241
|
+
|
|
242
|
+
def __init__(self, parser, node, line=None):
|
|
243
|
+
self.core = st(node)
|
|
244
|
+
self.name = f"LITERAL_{st(node)}"
|
|
245
|
+
self.value = st(node)
|
|
246
|
+
self.line = line
|
|
247
|
+
self.declaration = True
|
|
248
|
+
self.satisfied = False
|
|
249
|
+
self.scope = [0]
|
|
250
|
+
self.variable_scope = [0]
|
|
251
|
+
|
|
252
|
+
if line is not None:
|
|
253
|
+
self.real_line_no = read_index(parser.index, line)[0][0]
|
|
254
|
+
|
|
255
|
+
def __eq__(self, other):
|
|
256
|
+
return self.name == other.name and self.line == other.line
|
|
257
|
+
|
|
258
|
+
def __hash__(self):
|
|
259
|
+
return hash((self.name, self.line))
|
|
260
|
+
|
|
261
|
+
def __str__(self):
|
|
262
|
+
result = [f"Literal({self.value})"]
|
|
263
|
+
if self.line:
|
|
264
|
+
result += [str(self.real_line_no)]
|
|
265
|
+
else:
|
|
266
|
+
result += ["?"]
|
|
267
|
+
return f"{{{','.join(result)}}}"
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def extract_identifier_from_declarator(declarator_node):
|
|
271
|
+
"""Extract identifier from declarator (may be wrapped in pointer/array)"""
|
|
272
|
+
if declarator_node.type == "identifier":
|
|
273
|
+
return declarator_node
|
|
274
|
+
elif declarator_node.type == "pointer_declarator":
|
|
275
|
+
for child in declarator_node.children:
|
|
276
|
+
if child.type in ["identifier", "pointer_declarator", "array_declarator"]:
|
|
277
|
+
return extract_identifier_from_declarator(child)
|
|
278
|
+
elif declarator_node.type == "array_declarator":
|
|
279
|
+
if declarator_node.children:
|
|
280
|
+
return extract_identifier_from_declarator(declarator_node.children[0])
|
|
281
|
+
elif declarator_node.type == "function_declarator":
|
|
282
|
+
for child in declarator_node.children:
|
|
283
|
+
if child.type in [
|
|
284
|
+
"identifier",
|
|
285
|
+
"pointer_declarator",
|
|
286
|
+
"parenthesized_declarator",
|
|
287
|
+
]:
|
|
288
|
+
return extract_identifier_from_declarator(child)
|
|
289
|
+
elif declarator_node.type == "parenthesized_declarator":
|
|
290
|
+
for child in declarator_node.children:
|
|
291
|
+
if child.type in ["identifier", "pointer_declarator", "array_declarator"]:
|
|
292
|
+
return extract_identifier_from_declarator(child)
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def extract_param_identifier(param_node):
|
|
297
|
+
"""Extract identifier from parameter_declaration"""
|
|
298
|
+
for child in param_node.children:
|
|
299
|
+
if child.type == "identifier":
|
|
300
|
+
return child
|
|
301
|
+
elif child.type in [
|
|
302
|
+
"pointer_declarator",
|
|
303
|
+
"array_declarator",
|
|
304
|
+
"function_declarator",
|
|
305
|
+
]:
|
|
306
|
+
return extract_identifier_from_declarator(child)
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def extract_operator_text(assign_node, left_node, right_node):
|
|
311
|
+
"""Extract operator from assignment (=, +=, -=, etc.)"""
|
|
312
|
+
left_text = left_node.text
|
|
313
|
+
right_text = right_node.text
|
|
314
|
+
operator_bytes = (
|
|
315
|
+
assign_node.text.split(left_text, 1)[-1].rsplit(right_text, 1)[0].strip()
|
|
316
|
+
)
|
|
317
|
+
return operator_bytes.decode()
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def add_entry(
|
|
321
|
+
parser,
|
|
322
|
+
rda_table,
|
|
323
|
+
statement_id,
|
|
324
|
+
used=None,
|
|
325
|
+
defined=None,
|
|
326
|
+
declaration=False,
|
|
327
|
+
core=None,
|
|
328
|
+
):
|
|
329
|
+
"""
|
|
330
|
+
Add variable USE or DEF to RDA table.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
parser: C parser
|
|
334
|
+
rda_table: RDA table
|
|
335
|
+
statement_id: Statement where this occurs
|
|
336
|
+
used: Variable being used (read)
|
|
337
|
+
defined: Variable being defined (written)
|
|
338
|
+
declaration: True if declaration
|
|
339
|
+
core: Full reference node
|
|
340
|
+
"""
|
|
341
|
+
if statement_id not in rda_table:
|
|
342
|
+
rda_table[statement_id] = defaultdict(list)
|
|
343
|
+
|
|
344
|
+
if not used and not defined:
|
|
345
|
+
return
|
|
346
|
+
|
|
347
|
+
current_node = used or defined
|
|
348
|
+
if core is None:
|
|
349
|
+
core = current_node
|
|
350
|
+
|
|
351
|
+
if current_node.type in literal_types:
|
|
352
|
+
if used:
|
|
353
|
+
set_add(
|
|
354
|
+
rda_table[statement_id]["use"],
|
|
355
|
+
Literal(parser, current_node, statement_id),
|
|
356
|
+
)
|
|
357
|
+
return
|
|
358
|
+
|
|
359
|
+
if current_node.type == "field_expression":
|
|
360
|
+
if defined is not None:
|
|
361
|
+
set_add(
|
|
362
|
+
rda_table[statement_id]["def"],
|
|
363
|
+
Identifier(
|
|
364
|
+
parser,
|
|
365
|
+
current_node.child_by_field_name("argument"),
|
|
366
|
+
statement_id,
|
|
367
|
+
full_ref=None,
|
|
368
|
+
declaration=declaration,
|
|
369
|
+
),
|
|
370
|
+
)
|
|
371
|
+
else:
|
|
372
|
+
set_add(
|
|
373
|
+
rda_table[statement_id]["use"],
|
|
374
|
+
Identifier(
|
|
375
|
+
parser, current_node.child_by_field_name("argument"), full_ref=None
|
|
376
|
+
),
|
|
377
|
+
)
|
|
378
|
+
return
|
|
379
|
+
|
|
380
|
+
if used and used.type == "unary_expression":
|
|
381
|
+
operator = None
|
|
382
|
+
argument = None
|
|
383
|
+
for child in used.children:
|
|
384
|
+
if child.type == "&":
|
|
385
|
+
operator = child
|
|
386
|
+
elif child.is_named:
|
|
387
|
+
argument = child
|
|
388
|
+
|
|
389
|
+
if operator is not None and argument is not None:
|
|
390
|
+
if argument.type in variable_type:
|
|
391
|
+
arg_index = get_index(argument, parser.index)
|
|
392
|
+
if arg_index and arg_index in parser.symbol_table["scope_map"]:
|
|
393
|
+
set_add(
|
|
394
|
+
rda_table[statement_id]["use"],
|
|
395
|
+
Identifier(parser, argument, full_ref=argument),
|
|
396
|
+
)
|
|
397
|
+
elif arg_index and arg_index in parser.method_map:
|
|
398
|
+
set_add(
|
|
399
|
+
rda_table[statement_id]["use"],
|
|
400
|
+
Identifier(parser, argument, full_ref=argument),
|
|
401
|
+
)
|
|
402
|
+
return
|
|
403
|
+
|
|
404
|
+
if current_node.type == "pointer_expression":
|
|
405
|
+
pointer = current_node.child_by_field_name("argument")
|
|
406
|
+
|
|
407
|
+
if defined is not None:
|
|
408
|
+
pointer_index = get_index(pointer, parser.index)
|
|
409
|
+
if pointer_index and pointer_index in parser.symbol_table["scope_map"]:
|
|
410
|
+
set_add(
|
|
411
|
+
rda_table[statement_id]["use"],
|
|
412
|
+
Identifier(parser, pointer, full_ref=pointer),
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
set_add(
|
|
416
|
+
rda_table[statement_id]["def"],
|
|
417
|
+
Identifier(
|
|
418
|
+
parser,
|
|
419
|
+
pointer,
|
|
420
|
+
statement_id,
|
|
421
|
+
full_ref=core,
|
|
422
|
+
declaration=declaration,
|
|
423
|
+
),
|
|
424
|
+
)
|
|
425
|
+
else:
|
|
426
|
+
set_add(
|
|
427
|
+
rda_table[statement_id]["use"],
|
|
428
|
+
Identifier(parser, pointer, full_ref=core),
|
|
429
|
+
)
|
|
430
|
+
return
|
|
431
|
+
|
|
432
|
+
if current_node.type == "subscript_expression":
|
|
433
|
+
array = current_node.child_by_field_name("argument")
|
|
434
|
+
index_expr = current_node.child_by_field_name("index")
|
|
435
|
+
|
|
436
|
+
if defined is not None:
|
|
437
|
+
set_add(
|
|
438
|
+
rda_table[statement_id]["def"],
|
|
439
|
+
Identifier(
|
|
440
|
+
parser, array, statement_id, full_ref=core, declaration=declaration
|
|
441
|
+
),
|
|
442
|
+
)
|
|
443
|
+
set_add(
|
|
444
|
+
rda_table[statement_id]["use"], Identifier(parser, array, full_ref=core)
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
if index_expr:
|
|
448
|
+
if index_expr.type in variable_type:
|
|
449
|
+
index_id = get_index(index_expr, parser.index)
|
|
450
|
+
if index_id and index_id in parser.symbol_table["scope_map"]:
|
|
451
|
+
set_add(
|
|
452
|
+
rda_table[statement_id]["use"],
|
|
453
|
+
Identifier(parser, index_expr, full_ref=index_expr),
|
|
454
|
+
)
|
|
455
|
+
elif index_expr.type in literal_types:
|
|
456
|
+
set_add(
|
|
457
|
+
rda_table[statement_id]["use"],
|
|
458
|
+
Literal(parser, index_expr, statement_id),
|
|
459
|
+
)
|
|
460
|
+
else:
|
|
461
|
+
identifiers_in_index = recursively_get_children_of_types(
|
|
462
|
+
index_expr,
|
|
463
|
+
variable_type + ["field_expression"],
|
|
464
|
+
index=parser.index,
|
|
465
|
+
check_list=parser.symbol_table["scope_map"],
|
|
466
|
+
)
|
|
467
|
+
for identifier in identifiers_in_index:
|
|
468
|
+
set_add(
|
|
469
|
+
rda_table[statement_id]["use"],
|
|
470
|
+
Identifier(parser, identifier, full_ref=identifier),
|
|
471
|
+
)
|
|
472
|
+
literals_in_index = recursively_get_children_of_types(
|
|
473
|
+
index_expr, literal_types, index=parser.index
|
|
474
|
+
)
|
|
475
|
+
for literal in literals_in_index:
|
|
476
|
+
set_add(
|
|
477
|
+
rda_table[statement_id]["use"],
|
|
478
|
+
Literal(parser, literal, statement_id),
|
|
479
|
+
)
|
|
480
|
+
return
|
|
481
|
+
|
|
482
|
+
node_index = get_index(current_node, parser.index)
|
|
483
|
+
if node_index is None or node_index not in parser.symbol_table["scope_map"]:
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
if defined is not None:
|
|
487
|
+
set_add(
|
|
488
|
+
rda_table[statement_id]["def"],
|
|
489
|
+
Identifier(
|
|
490
|
+
parser, defined, statement_id, full_ref=core, declaration=declaration
|
|
491
|
+
),
|
|
492
|
+
)
|
|
493
|
+
else:
|
|
494
|
+
set_add(
|
|
495
|
+
rda_table[statement_id]["use"],
|
|
496
|
+
Identifier(parser, used, full_ref=core, declaration=declaration),
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def is_return_value_used(call_expr_statement):
|
|
501
|
+
"""
|
|
502
|
+
Check if a function call's return value is actually used.
|
|
503
|
+
|
|
504
|
+
Args:
|
|
505
|
+
call_expr_statement: The expression_statement or parent node containing the call
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
True if return value is used (assigned, passed as argument, returned, in conditional)
|
|
509
|
+
False if return value is discarded (standalone statement like fn();)
|
|
510
|
+
"""
|
|
511
|
+
if call_expr_statement.type == "expression_statement":
|
|
512
|
+
if len(call_expr_statement.named_children) == 1:
|
|
513
|
+
child = call_expr_statement.named_children[0]
|
|
514
|
+
if child.type == "call_expression":
|
|
515
|
+
return False
|
|
516
|
+
|
|
517
|
+
parent = call_expr_statement.parent
|
|
518
|
+
while parent:
|
|
519
|
+
parent_type = parent.type
|
|
520
|
+
|
|
521
|
+
if parent_type in ["init_declarator", "assignment_expression"]:
|
|
522
|
+
return True
|
|
523
|
+
|
|
524
|
+
if parent_type == "return_statement":
|
|
525
|
+
return True
|
|
526
|
+
|
|
527
|
+
if parent_type == "argument_list":
|
|
528
|
+
return True
|
|
529
|
+
|
|
530
|
+
if parent_type in [
|
|
531
|
+
"if_statement",
|
|
532
|
+
"while_statement",
|
|
533
|
+
"for_statement",
|
|
534
|
+
"do_while_statement",
|
|
535
|
+
"switch_statement",
|
|
536
|
+
]:
|
|
537
|
+
return True
|
|
538
|
+
|
|
539
|
+
if parent_type == "expression_statement":
|
|
540
|
+
return False
|
|
541
|
+
|
|
542
|
+
parent = parent.parent
|
|
543
|
+
|
|
544
|
+
return False
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def collect_function_metadata(parser):
|
|
548
|
+
"""
|
|
549
|
+
Collect metadata about all functions in the program.
|
|
550
|
+
|
|
551
|
+
For each function, track:
|
|
552
|
+
- Function name
|
|
553
|
+
- Parameter names and whether they're pointers
|
|
554
|
+
- Parameter indices
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
557
|
+
Dict mapping function_name -> {
|
|
558
|
+
"params": [(param_name, is_pointer, param_index), ...],
|
|
559
|
+
"node": function_definition AST node
|
|
560
|
+
}
|
|
561
|
+
"""
|
|
562
|
+
metadata = {}
|
|
563
|
+
|
|
564
|
+
for node in traverse_tree(parser.tree.root_node):
|
|
565
|
+
if node.type == "function_definition":
|
|
566
|
+
func_name = None
|
|
567
|
+
params = []
|
|
568
|
+
|
|
569
|
+
for child in node.named_children:
|
|
570
|
+
if child.type == "function_declarator":
|
|
571
|
+
declarator = child.child_by_field_name("declarator")
|
|
572
|
+
if declarator:
|
|
573
|
+
if declarator.type == "identifier":
|
|
574
|
+
func_name = st(declarator)
|
|
575
|
+
elif declarator.type == "pointer_declarator":
|
|
576
|
+
inner = declarator
|
|
577
|
+
while inner and inner.type == "pointer_declarator":
|
|
578
|
+
inner_declarator = inner.child_by_field_name(
|
|
579
|
+
"declarator"
|
|
580
|
+
)
|
|
581
|
+
if inner_declarator:
|
|
582
|
+
inner = inner_declarator
|
|
583
|
+
else:
|
|
584
|
+
break
|
|
585
|
+
if inner and inner.type == "identifier":
|
|
586
|
+
func_name = st(inner)
|
|
587
|
+
|
|
588
|
+
param_list = child.child_by_field_name("parameters")
|
|
589
|
+
if param_list:
|
|
590
|
+
param_idx = 0
|
|
591
|
+
for param in param_list.named_children:
|
|
592
|
+
if param.type == "parameter_declaration":
|
|
593
|
+
param_name = None
|
|
594
|
+
is_pointer = False
|
|
595
|
+
|
|
596
|
+
for p_child in param.named_children:
|
|
597
|
+
if p_child.type == "pointer_declarator":
|
|
598
|
+
is_pointer = True
|
|
599
|
+
inner = p_child
|
|
600
|
+
while inner:
|
|
601
|
+
if inner.type == "identifier":
|
|
602
|
+
param_name = st(inner)
|
|
603
|
+
break
|
|
604
|
+
elif inner.type == "pointer_declarator":
|
|
605
|
+
inner_decl = inner.child_by_field_name(
|
|
606
|
+
"declarator"
|
|
607
|
+
)
|
|
608
|
+
if inner_decl:
|
|
609
|
+
inner = inner_decl
|
|
610
|
+
else:
|
|
611
|
+
break
|
|
612
|
+
else:
|
|
613
|
+
break
|
|
614
|
+
elif p_child.type == "array_declarator":
|
|
615
|
+
is_pointer = True
|
|
616
|
+
param_name = st(
|
|
617
|
+
extract_identifier_from_declarator(p_child)
|
|
618
|
+
)
|
|
619
|
+
elif p_child.type == "identifier":
|
|
620
|
+
if param_name is None:
|
|
621
|
+
param_name = st(p_child)
|
|
622
|
+
|
|
623
|
+
if param_name:
|
|
624
|
+
params.append((param_name, is_pointer, param_idx))
|
|
625
|
+
param_idx += 1
|
|
626
|
+
break
|
|
627
|
+
|
|
628
|
+
if func_name:
|
|
629
|
+
metadata[func_name] = {"params": params, "node": node}
|
|
630
|
+
|
|
631
|
+
return metadata
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
def analyze_pointer_modifications(parser, function_metadata):
|
|
635
|
+
"""
|
|
636
|
+
Analyze which pointer parameters are modified within each function.
|
|
637
|
+
|
|
638
|
+
A pointer parameter is considered "modified" if:
|
|
639
|
+
- It's dereferenced on the left side of an assignment: *param = ...
|
|
640
|
+
- Used in pointer arithmetic with assignment: param[i] = ...
|
|
641
|
+
- Passed to another function that modifies it (transitive)
|
|
642
|
+
|
|
643
|
+
Args:
|
|
644
|
+
parser: Parser with AST
|
|
645
|
+
function_metadata: Dict from collect_function_metadata()
|
|
646
|
+
|
|
647
|
+
Returns:
|
|
648
|
+
Dict mapping function_name -> set of parameter indices that are modified
|
|
649
|
+
"""
|
|
650
|
+
modifications = {}
|
|
651
|
+
|
|
652
|
+
for func_name, meta in function_metadata.items():
|
|
653
|
+
modified_params = set()
|
|
654
|
+
func_node = meta["node"]
|
|
655
|
+
|
|
656
|
+
param_name_to_idx = {}
|
|
657
|
+
for param_name, is_pointer, param_idx in meta["params"]:
|
|
658
|
+
if is_pointer:
|
|
659
|
+
param_name_to_idx[param_name] = param_idx
|
|
660
|
+
|
|
661
|
+
if not param_name_to_idx:
|
|
662
|
+
modifications[func_name] = modified_params
|
|
663
|
+
continue
|
|
664
|
+
|
|
665
|
+
for node in traverse_tree(func_node):
|
|
666
|
+
if node.type == "assignment_expression":
|
|
667
|
+
left = node.child_by_field_name("left")
|
|
668
|
+
if left:
|
|
669
|
+
if left.type == "pointer_expression":
|
|
670
|
+
arg = left.child_by_field_name("argument")
|
|
671
|
+
if arg and arg.type == "identifier":
|
|
672
|
+
var_name = st(arg)
|
|
673
|
+
if var_name in param_name_to_idx:
|
|
674
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
675
|
+
|
|
676
|
+
elif left.type == "subscript_expression":
|
|
677
|
+
array_arg = left.child_by_field_name("argument")
|
|
678
|
+
if array_arg and array_arg.type == "identifier":
|
|
679
|
+
var_name = st(array_arg)
|
|
680
|
+
if var_name in param_name_to_idx:
|
|
681
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
682
|
+
|
|
683
|
+
elif left.type == "field_expression":
|
|
684
|
+
obj = left.child_by_field_name("argument")
|
|
685
|
+
if obj and obj.type == "identifier":
|
|
686
|
+
var_name = st(obj)
|
|
687
|
+
if var_name in param_name_to_idx:
|
|
688
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
689
|
+
|
|
690
|
+
elif node.type == "update_expression":
|
|
691
|
+
arg = node.child_by_field_name("argument")
|
|
692
|
+
if arg:
|
|
693
|
+
if arg.type == "parenthesized_expression":
|
|
694
|
+
inner_children = [c for c in arg.named_children if c.is_named]
|
|
695
|
+
if inner_children:
|
|
696
|
+
arg = inner_children[0]
|
|
697
|
+
|
|
698
|
+
if arg.type == "pointer_expression":
|
|
699
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
700
|
+
if inner_arg and inner_arg.type == "identifier":
|
|
701
|
+
var_name = st(inner_arg)
|
|
702
|
+
if var_name in param_name_to_idx:
|
|
703
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
704
|
+
elif arg.type == "subscript_expression":
|
|
705
|
+
array_arg = arg.child_by_field_name("argument")
|
|
706
|
+
if array_arg and array_arg.type == "identifier":
|
|
707
|
+
var_name = st(array_arg)
|
|
708
|
+
if var_name in param_name_to_idx:
|
|
709
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
710
|
+
elif arg.type == "field_expression":
|
|
711
|
+
obj = arg.child_by_field_name("argument")
|
|
712
|
+
if obj and obj.type == "identifier":
|
|
713
|
+
var_name = st(obj)
|
|
714
|
+
if var_name in param_name_to_idx:
|
|
715
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
716
|
+
|
|
717
|
+
modifications[func_name] = modified_params
|
|
718
|
+
|
|
719
|
+
return modifications
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
def build_rda_table(
|
|
723
|
+
parser, CFG_results, function_metadata=None, pointer_modifications=None
|
|
724
|
+
):
|
|
725
|
+
"""
|
|
726
|
+
Build RDA table by traversing AST and tracking DEF/USE.
|
|
727
|
+
|
|
728
|
+
Follows Java SDFG pattern: traverse tree stopping at identifiers,
|
|
729
|
+
check each node's type to determine DEF/USE relationships.
|
|
730
|
+
|
|
731
|
+
Returns:
|
|
732
|
+
rda_table: Dict mapping statement_id to {"def": set, "use": set}
|
|
733
|
+
"""
|
|
734
|
+
rda_table = {}
|
|
735
|
+
index = parser.index
|
|
736
|
+
tree = parser.tree
|
|
737
|
+
|
|
738
|
+
inner_types = ["parenthesized_expression", "binary_expression", "unary_expression"]
|
|
739
|
+
handled_cases = ["compound_statement", "translation_unit"]
|
|
740
|
+
|
|
741
|
+
for root_node in traverse_tree(tree, variable_type):
|
|
742
|
+
if not root_node.is_named:
|
|
743
|
+
continue
|
|
744
|
+
|
|
745
|
+
if root_node.type == "return_statement":
|
|
746
|
+
parent_id = get_index(root_node, index)
|
|
747
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
748
|
+
continue
|
|
749
|
+
|
|
750
|
+
return_expr = (
|
|
751
|
+
root_node.named_children[0] if root_node.named_children else None
|
|
752
|
+
)
|
|
753
|
+
if (
|
|
754
|
+
return_expr
|
|
755
|
+
and return_expr.type
|
|
756
|
+
in variable_type
|
|
757
|
+
+ ["field_expression", "pointer_expression", "subscript_expression"]
|
|
758
|
+
+ literal_types
|
|
759
|
+
):
|
|
760
|
+
add_entry(parser, rda_table, parent_id, used=return_expr)
|
|
761
|
+
else:
|
|
762
|
+
vars_used = recursively_get_children_of_types(
|
|
763
|
+
root_node,
|
|
764
|
+
variable_type
|
|
765
|
+
+ [
|
|
766
|
+
"field_expression",
|
|
767
|
+
"pointer_expression",
|
|
768
|
+
"subscript_expression",
|
|
769
|
+
],
|
|
770
|
+
index=parser.index,
|
|
771
|
+
check_list=parser.symbol_table["scope_map"],
|
|
772
|
+
)
|
|
773
|
+
for var in vars_used:
|
|
774
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
775
|
+
|
|
776
|
+
literals_used = recursively_get_children_of_types(
|
|
777
|
+
root_node, literal_types, index=parser.index
|
|
778
|
+
)
|
|
779
|
+
for literal in literals_used:
|
|
780
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
781
|
+
|
|
782
|
+
elif root_node.type in def_statement:
|
|
783
|
+
parent_statement = return_first_parent_of_types(
|
|
784
|
+
root_node, statement_types["node_list_type"]
|
|
785
|
+
)
|
|
786
|
+
if parent_statement is None:
|
|
787
|
+
continue
|
|
788
|
+
|
|
789
|
+
parent_id = get_index(parent_statement, index)
|
|
790
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
791
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
792
|
+
parent_statement = return_first_parent_of_types(
|
|
793
|
+
parent_statement, statement_types["node_list_type"]
|
|
794
|
+
)
|
|
795
|
+
parent_id = get_index(parent_statement, index)
|
|
796
|
+
elif parent_statement.type in handled_cases:
|
|
797
|
+
continue
|
|
798
|
+
else:
|
|
799
|
+
continue
|
|
800
|
+
|
|
801
|
+
declarator = root_node.child_by_field_name("declarator")
|
|
802
|
+
if declarator is None and len(root_node.children) > 0:
|
|
803
|
+
declarator = root_node.children[0]
|
|
804
|
+
|
|
805
|
+
var_identifier = extract_identifier_from_declarator(declarator)
|
|
806
|
+
|
|
807
|
+
if var_identifier:
|
|
808
|
+
add_entry(
|
|
809
|
+
parser,
|
|
810
|
+
rda_table,
|
|
811
|
+
parent_id,
|
|
812
|
+
defined=var_identifier,
|
|
813
|
+
declaration=True,
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
initializer = root_node.child_by_field_name("value")
|
|
817
|
+
if initializer:
|
|
818
|
+
if (
|
|
819
|
+
initializer.type
|
|
820
|
+
in variable_type
|
|
821
|
+
+ [
|
|
822
|
+
"field_expression",
|
|
823
|
+
"pointer_expression",
|
|
824
|
+
"subscript_expression",
|
|
825
|
+
"unary_expression",
|
|
826
|
+
]
|
|
827
|
+
+ literal_types
|
|
828
|
+
):
|
|
829
|
+
add_entry(parser, rda_table, parent_id, used=initializer)
|
|
830
|
+
else:
|
|
831
|
+
vars_used = recursively_get_children_of_types(
|
|
832
|
+
initializer,
|
|
833
|
+
variable_type + ["field_expression"],
|
|
834
|
+
index=parser.index,
|
|
835
|
+
check_list=parser.symbol_table["scope_map"],
|
|
836
|
+
)
|
|
837
|
+
for var in vars_used:
|
|
838
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
839
|
+
literals_used = recursively_get_children_of_types(
|
|
840
|
+
initializer, literal_types, index=parser.index
|
|
841
|
+
)
|
|
842
|
+
for literal in literals_used:
|
|
843
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
844
|
+
|
|
845
|
+
elif root_node.type in declaration_statement:
|
|
846
|
+
parent_id = get_index(root_node, index)
|
|
847
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
848
|
+
continue
|
|
849
|
+
|
|
850
|
+
has_init_declarator = any(
|
|
851
|
+
child.type == "init_declarator" for child in root_node.named_children
|
|
852
|
+
)
|
|
853
|
+
if has_init_declarator:
|
|
854
|
+
continue
|
|
855
|
+
|
|
856
|
+
for child in root_node.named_children:
|
|
857
|
+
if child.type == "identifier":
|
|
858
|
+
child_id = get_index(child, index)
|
|
859
|
+
if child_id:
|
|
860
|
+
from collections import defaultdict
|
|
861
|
+
|
|
862
|
+
if parent_id not in rda_table:
|
|
863
|
+
rda_table[parent_id] = defaultdict(list)
|
|
864
|
+
ident = Identifier(parser, child, parent_id, declaration=True)
|
|
865
|
+
ident.scope = [0]
|
|
866
|
+
ident.variable_scope = [0]
|
|
867
|
+
set_add(rda_table[parent_id]["def"], ident)
|
|
868
|
+
elif child.type in [
|
|
869
|
+
"pointer_declarator",
|
|
870
|
+
"array_declarator",
|
|
871
|
+
"function_declarator",
|
|
872
|
+
"parenthesized_declarator",
|
|
873
|
+
]:
|
|
874
|
+
var_identifier = extract_identifier_from_declarator(child)
|
|
875
|
+
if var_identifier:
|
|
876
|
+
var_id = get_index(var_identifier, index)
|
|
877
|
+
if var_id:
|
|
878
|
+
add_entry(
|
|
879
|
+
parser,
|
|
880
|
+
rda_table,
|
|
881
|
+
parent_id,
|
|
882
|
+
defined=var_identifier,
|
|
883
|
+
declaration=True,
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
elif root_node.type in assignment:
|
|
887
|
+
parent_statement = return_first_parent_of_types(
|
|
888
|
+
root_node, statement_types["node_list_type"]
|
|
889
|
+
)
|
|
890
|
+
if parent_statement is None:
|
|
891
|
+
continue
|
|
892
|
+
|
|
893
|
+
parent_id = get_index(parent_statement, index)
|
|
894
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
895
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
896
|
+
parent_statement = return_first_parent_of_types(
|
|
897
|
+
parent_statement, statement_types["node_list_type"]
|
|
898
|
+
)
|
|
899
|
+
parent_id = get_index(parent_statement, index)
|
|
900
|
+
elif parent_statement.type in handled_cases:
|
|
901
|
+
continue
|
|
902
|
+
else:
|
|
903
|
+
continue
|
|
904
|
+
|
|
905
|
+
left_node = root_node.child_by_field_name("left")
|
|
906
|
+
right_node = root_node.child_by_field_name("right")
|
|
907
|
+
|
|
908
|
+
if left_node is None or right_node is None:
|
|
909
|
+
continue
|
|
910
|
+
|
|
911
|
+
operator_text = extract_operator_text(root_node, left_node, right_node)
|
|
912
|
+
|
|
913
|
+
if operator_text != "=":
|
|
914
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
915
|
+
else:
|
|
916
|
+
if left_node.type == "field_expression":
|
|
917
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
918
|
+
elif left_node.type in variable_type:
|
|
919
|
+
left_node_index = get_index(left_node, index)
|
|
920
|
+
if (
|
|
921
|
+
left_node_index
|
|
922
|
+
and left_node_index in parser.symbol_table["scope_map"]
|
|
923
|
+
):
|
|
924
|
+
is_init_declarator = False
|
|
925
|
+
check_parent = root_node.parent
|
|
926
|
+
while check_parent:
|
|
927
|
+
if check_parent.type == "init_declarator":
|
|
928
|
+
is_init_declarator = True
|
|
929
|
+
break
|
|
930
|
+
if check_parent.type in statement_types.get(
|
|
931
|
+
"node_list_type", []
|
|
932
|
+
):
|
|
933
|
+
break
|
|
934
|
+
check_parent = check_parent.parent
|
|
935
|
+
|
|
936
|
+
if not is_init_declarator:
|
|
937
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
938
|
+
|
|
939
|
+
add_entry(parser, rda_table, parent_id, defined=left_node)
|
|
940
|
+
|
|
941
|
+
if (
|
|
942
|
+
right_node.type
|
|
943
|
+
in variable_type
|
|
944
|
+
+ [
|
|
945
|
+
"field_expression",
|
|
946
|
+
"pointer_expression",
|
|
947
|
+
"subscript_expression",
|
|
948
|
+
"unary_expression",
|
|
949
|
+
]
|
|
950
|
+
+ literal_types
|
|
951
|
+
):
|
|
952
|
+
add_entry(parser, rda_table, parent_id, used=right_node)
|
|
953
|
+
else:
|
|
954
|
+
vars_used = recursively_get_children_of_types(
|
|
955
|
+
right_node,
|
|
956
|
+
variable_type + ["field_expression"],
|
|
957
|
+
index=parser.index,
|
|
958
|
+
check_list=parser.symbol_table["scope_map"],
|
|
959
|
+
)
|
|
960
|
+
for var in vars_used:
|
|
961
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
962
|
+
literals_used = recursively_get_children_of_types(
|
|
963
|
+
right_node, literal_types, index=parser.index
|
|
964
|
+
)
|
|
965
|
+
for literal in literals_used:
|
|
966
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
967
|
+
|
|
968
|
+
elif root_node.type in increment_statement:
|
|
969
|
+
parent_statement = return_first_parent_of_types(
|
|
970
|
+
root_node, statement_types["node_list_type"]
|
|
971
|
+
)
|
|
972
|
+
if parent_statement is None:
|
|
973
|
+
continue
|
|
974
|
+
|
|
975
|
+
parent_id = get_index(parent_statement, index)
|
|
976
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
977
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
978
|
+
parent_statement = return_first_parent_of_types(
|
|
979
|
+
parent_statement, statement_types["node_list_type"]
|
|
980
|
+
)
|
|
981
|
+
parent_id = get_index(parent_statement, index)
|
|
982
|
+
elif parent_statement.type in handled_cases:
|
|
983
|
+
continue
|
|
984
|
+
else:
|
|
985
|
+
continue
|
|
986
|
+
|
|
987
|
+
if root_node.type in variable_type + ["field_expression"]:
|
|
988
|
+
add_entry(parser, rda_table, parent_id, used=root_node)
|
|
989
|
+
add_entry(parser, rda_table, parent_id, defined=root_node)
|
|
990
|
+
else:
|
|
991
|
+
identifiers = recursively_get_children_of_types(
|
|
992
|
+
root_node,
|
|
993
|
+
variable_type + ["field_expression"],
|
|
994
|
+
index=parser.index,
|
|
995
|
+
check_list=parser.symbol_table["scope_map"],
|
|
996
|
+
)
|
|
997
|
+
for identifier in identifiers:
|
|
998
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
999
|
+
add_entry(parser, rda_table, parent_id, defined=identifier)
|
|
1000
|
+
|
|
1001
|
+
elif root_node.type in function_calls:
|
|
1002
|
+
parent_statement = return_first_parent_of_types(
|
|
1003
|
+
root_node, statement_types["node_list_type"]
|
|
1004
|
+
)
|
|
1005
|
+
if parent_statement is None:
|
|
1006
|
+
continue
|
|
1007
|
+
|
|
1008
|
+
parent_id = get_index(parent_statement, index)
|
|
1009
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1010
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1011
|
+
parent_statement = return_first_parent_of_types(
|
|
1012
|
+
parent_statement, statement_types["node_list_type"]
|
|
1013
|
+
)
|
|
1014
|
+
parent_id = get_index(parent_statement, index)
|
|
1015
|
+
elif parent_statement.type in handled_cases:
|
|
1016
|
+
continue
|
|
1017
|
+
else:
|
|
1018
|
+
continue
|
|
1019
|
+
|
|
1020
|
+
function_name = None
|
|
1021
|
+
if root_node.children and root_node.children[0].type == "identifier":
|
|
1022
|
+
function_name = st(root_node.children[0])
|
|
1023
|
+
|
|
1024
|
+
is_input_function = function_name in input_functions
|
|
1025
|
+
|
|
1026
|
+
for child in root_node.children[1:]:
|
|
1027
|
+
if is_input_function and child.type == "argument_list":
|
|
1028
|
+
for arg in child.named_children:
|
|
1029
|
+
if arg.type == "pointer_expression":
|
|
1030
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1031
|
+
if inner_arg:
|
|
1032
|
+
if inner_arg.type in variable_type:
|
|
1033
|
+
add_entry(
|
|
1034
|
+
parser,
|
|
1035
|
+
rda_table,
|
|
1036
|
+
parent_id,
|
|
1037
|
+
defined=inner_arg,
|
|
1038
|
+
declaration=False,
|
|
1039
|
+
)
|
|
1040
|
+
elif inner_arg.type in [
|
|
1041
|
+
"field_expression",
|
|
1042
|
+
"subscript_expression",
|
|
1043
|
+
]:
|
|
1044
|
+
add_entry(
|
|
1045
|
+
parser,
|
|
1046
|
+
rda_table,
|
|
1047
|
+
parent_id,
|
|
1048
|
+
defined=inner_arg,
|
|
1049
|
+
declaration=False,
|
|
1050
|
+
)
|
|
1051
|
+
if inner_arg.type == "subscript_expression":
|
|
1052
|
+
index_expr = inner_arg.child_by_field_name(
|
|
1053
|
+
"index"
|
|
1054
|
+
)
|
|
1055
|
+
if index_expr:
|
|
1056
|
+
vars_in_index = (
|
|
1057
|
+
recursively_get_children_of_types(
|
|
1058
|
+
index_expr,
|
|
1059
|
+
variable_type
|
|
1060
|
+
+ ["field_expression"],
|
|
1061
|
+
index=parser.index,
|
|
1062
|
+
check_list=parser.symbol_table[
|
|
1063
|
+
"scope_map"
|
|
1064
|
+
],
|
|
1065
|
+
)
|
|
1066
|
+
)
|
|
1067
|
+
for var in vars_in_index:
|
|
1068
|
+
add_entry(
|
|
1069
|
+
parser,
|
|
1070
|
+
rda_table,
|
|
1071
|
+
parent_id,
|
|
1072
|
+
used=var,
|
|
1073
|
+
)
|
|
1074
|
+
elif arg.type in variable_type + ["field_expression"]:
|
|
1075
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1076
|
+
elif arg.type in literal_types:
|
|
1077
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1078
|
+
else:
|
|
1079
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1080
|
+
arg,
|
|
1081
|
+
variable_type + ["field_expression"],
|
|
1082
|
+
index=parser.index,
|
|
1083
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1084
|
+
)
|
|
1085
|
+
for identifier in identifiers_used:
|
|
1086
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1087
|
+
literals_used = recursively_get_children_of_types(
|
|
1088
|
+
arg, literal_types, index=parser.index
|
|
1089
|
+
)
|
|
1090
|
+
for literal in literals_used:
|
|
1091
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1092
|
+
elif not is_input_function and child.type == "argument_list":
|
|
1093
|
+
modifies_params = set()
|
|
1094
|
+
if (
|
|
1095
|
+
function_name
|
|
1096
|
+
and function_metadata
|
|
1097
|
+
and function_name in function_metadata
|
|
1098
|
+
):
|
|
1099
|
+
if (
|
|
1100
|
+
pointer_modifications
|
|
1101
|
+
and function_name in pointer_modifications
|
|
1102
|
+
):
|
|
1103
|
+
modifies_params = pointer_modifications[function_name]
|
|
1104
|
+
|
|
1105
|
+
for arg_idx, arg in enumerate(child.named_children):
|
|
1106
|
+
is_modified_param = arg_idx in modifies_params
|
|
1107
|
+
|
|
1108
|
+
if is_modified_param and arg.type == "pointer_expression":
|
|
1109
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1110
|
+
if inner_arg:
|
|
1111
|
+
if inner_arg.type in variable_type:
|
|
1112
|
+
add_entry(
|
|
1113
|
+
parser, rda_table, parent_id, used=inner_arg
|
|
1114
|
+
)
|
|
1115
|
+
add_entry(
|
|
1116
|
+
parser,
|
|
1117
|
+
rda_table,
|
|
1118
|
+
parent_id,
|
|
1119
|
+
defined=inner_arg,
|
|
1120
|
+
declaration=False,
|
|
1121
|
+
)
|
|
1122
|
+
elif inner_arg.type in [
|
|
1123
|
+
"field_expression",
|
|
1124
|
+
"subscript_expression",
|
|
1125
|
+
]:
|
|
1126
|
+
add_entry(
|
|
1127
|
+
parser, rda_table, parent_id, used=inner_arg
|
|
1128
|
+
)
|
|
1129
|
+
add_entry(
|
|
1130
|
+
parser,
|
|
1131
|
+
rda_table,
|
|
1132
|
+
parent_id,
|
|
1133
|
+
defined=inner_arg,
|
|
1134
|
+
declaration=False,
|
|
1135
|
+
)
|
|
1136
|
+
if inner_arg.type == "subscript_expression":
|
|
1137
|
+
index_expr = inner_arg.child_by_field_name(
|
|
1138
|
+
"index"
|
|
1139
|
+
)
|
|
1140
|
+
if index_expr:
|
|
1141
|
+
vars_in_index = (
|
|
1142
|
+
recursively_get_children_of_types(
|
|
1143
|
+
index_expr,
|
|
1144
|
+
variable_type
|
|
1145
|
+
+ ["field_expression"],
|
|
1146
|
+
index=parser.index,
|
|
1147
|
+
check_list=parser.symbol_table[
|
|
1148
|
+
"scope_map"
|
|
1149
|
+
],
|
|
1150
|
+
)
|
|
1151
|
+
)
|
|
1152
|
+
for var in vars_in_index:
|
|
1153
|
+
add_entry(
|
|
1154
|
+
parser,
|
|
1155
|
+
rda_table,
|
|
1156
|
+
parent_id,
|
|
1157
|
+
used=var,
|
|
1158
|
+
)
|
|
1159
|
+
elif arg.type in variable_type + ["field_expression"]:
|
|
1160
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1161
|
+
elif arg.type in literal_types:
|
|
1162
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1163
|
+
else:
|
|
1164
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1165
|
+
arg,
|
|
1166
|
+
variable_type + ["field_expression"],
|
|
1167
|
+
index=parser.index,
|
|
1168
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1169
|
+
)
|
|
1170
|
+
for identifier in identifiers_used:
|
|
1171
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1172
|
+
literals_used = recursively_get_children_of_types(
|
|
1173
|
+
arg, literal_types, index=parser.index
|
|
1174
|
+
)
|
|
1175
|
+
for literal in literals_used:
|
|
1176
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1177
|
+
|
|
1178
|
+
elif child.type in variable_type + ["field_expression"]:
|
|
1179
|
+
add_entry(parser, rda_table, parent_id, used=child)
|
|
1180
|
+
elif child.type in literal_types:
|
|
1181
|
+
add_entry(parser, rda_table, parent_id, used=child)
|
|
1182
|
+
else:
|
|
1183
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1184
|
+
child,
|
|
1185
|
+
variable_type + ["field_expression"],
|
|
1186
|
+
index=parser.index,
|
|
1187
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1188
|
+
)
|
|
1189
|
+
for identifier in identifiers_used:
|
|
1190
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1191
|
+
literals_used = recursively_get_children_of_types(
|
|
1192
|
+
child, literal_types, index=parser.index
|
|
1193
|
+
)
|
|
1194
|
+
for literal in literals_used:
|
|
1195
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1196
|
+
|
|
1197
|
+
elif root_node.type == "function_definition":
|
|
1198
|
+
parent_id = get_index(root_node, index)
|
|
1199
|
+
if parent_id is None:
|
|
1200
|
+
continue
|
|
1201
|
+
|
|
1202
|
+
for child in root_node.named_children:
|
|
1203
|
+
if child.type == "function_declarator":
|
|
1204
|
+
func_name_node = child.child_by_field_name("declarator")
|
|
1205
|
+
if func_name_node and func_name_node.type in variable_type:
|
|
1206
|
+
func_name_idx = get_index(func_name_node, index)
|
|
1207
|
+
if (
|
|
1208
|
+
func_name_idx
|
|
1209
|
+
and func_name_idx in parser.symbol_table["scope_map"]
|
|
1210
|
+
):
|
|
1211
|
+
add_entry(
|
|
1212
|
+
parser,
|
|
1213
|
+
rda_table,
|
|
1214
|
+
parent_id,
|
|
1215
|
+
defined=func_name_node,
|
|
1216
|
+
declaration=True,
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
param_list = child.child_by_field_name("parameters")
|
|
1220
|
+
if param_list:
|
|
1221
|
+
for param in param_list.named_children:
|
|
1222
|
+
if param.type == "parameter_declaration":
|
|
1223
|
+
param_id = extract_param_identifier(param)
|
|
1224
|
+
if param_id:
|
|
1225
|
+
add_entry(
|
|
1226
|
+
parser,
|
|
1227
|
+
rda_table,
|
|
1228
|
+
parent_id,
|
|
1229
|
+
defined=param_id,
|
|
1230
|
+
declaration=True,
|
|
1231
|
+
)
|
|
1232
|
+
break
|
|
1233
|
+
|
|
1234
|
+
elif root_node.type == "switch_statement":
|
|
1235
|
+
parent_id = get_index(root_node, index)
|
|
1236
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1237
|
+
continue
|
|
1238
|
+
|
|
1239
|
+
condition = root_node.child_by_field_name("condition")
|
|
1240
|
+
if condition:
|
|
1241
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1242
|
+
condition,
|
|
1243
|
+
variable_type + ["field_expression"],
|
|
1244
|
+
index=parser.index,
|
|
1245
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1246
|
+
)
|
|
1247
|
+
for identifier in identifiers_used:
|
|
1248
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1249
|
+
|
|
1250
|
+
elif root_node.type == "for_statement":
|
|
1251
|
+
parent_id = get_index(root_node, index)
|
|
1252
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1253
|
+
continue
|
|
1254
|
+
|
|
1255
|
+
condition = root_node.child_by_field_name("condition")
|
|
1256
|
+
if condition:
|
|
1257
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1258
|
+
condition,
|
|
1259
|
+
variable_type + ["field_expression"],
|
|
1260
|
+
index=parser.index,
|
|
1261
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1262
|
+
)
|
|
1263
|
+
for identifier in identifiers_used:
|
|
1264
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1265
|
+
|
|
1266
|
+
elif root_node.type == "while_statement":
|
|
1267
|
+
parent_id = get_index(root_node, index)
|
|
1268
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1269
|
+
continue
|
|
1270
|
+
|
|
1271
|
+
condition = root_node.child_by_field_name("condition")
|
|
1272
|
+
if condition:
|
|
1273
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1274
|
+
condition,
|
|
1275
|
+
variable_type + ["field_expression"],
|
|
1276
|
+
index=parser.index,
|
|
1277
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1278
|
+
)
|
|
1279
|
+
for identifier in identifiers_used:
|
|
1280
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1281
|
+
|
|
1282
|
+
elif (
|
|
1283
|
+
root_node.type == "parenthesized_expression"
|
|
1284
|
+
and root_node.parent is not None
|
|
1285
|
+
and root_node.parent.type == "do_statement"
|
|
1286
|
+
):
|
|
1287
|
+
parent_id = get_index(root_node, index)
|
|
1288
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1289
|
+
continue
|
|
1290
|
+
|
|
1291
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1292
|
+
root_node,
|
|
1293
|
+
variable_type + ["field_expression"],
|
|
1294
|
+
index=parser.index,
|
|
1295
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1296
|
+
)
|
|
1297
|
+
for identifier in identifiers_used:
|
|
1298
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1299
|
+
|
|
1300
|
+
elif root_node.type == "do_statement":
|
|
1301
|
+
pass
|
|
1302
|
+
|
|
1303
|
+
elif root_node.type == "if_statement":
|
|
1304
|
+
parent_id = get_index(root_node, index)
|
|
1305
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1306
|
+
continue
|
|
1307
|
+
|
|
1308
|
+
condition = root_node.child_by_field_name("condition")
|
|
1309
|
+
if condition:
|
|
1310
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1311
|
+
condition,
|
|
1312
|
+
variable_type + ["field_expression"],
|
|
1313
|
+
index=parser.index,
|
|
1314
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1315
|
+
)
|
|
1316
|
+
for identifier in identifiers_used:
|
|
1317
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1318
|
+
|
|
1319
|
+
elif root_node.type == "conditional_expression":
|
|
1320
|
+
parent_statement = return_first_parent_of_types(
|
|
1321
|
+
root_node, statement_types["node_list_type"]
|
|
1322
|
+
)
|
|
1323
|
+
if parent_statement is None:
|
|
1324
|
+
continue
|
|
1325
|
+
|
|
1326
|
+
parent_id = get_index(parent_statement, index)
|
|
1327
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1328
|
+
continue
|
|
1329
|
+
|
|
1330
|
+
condition = root_node.child_by_field_name("condition")
|
|
1331
|
+
if condition:
|
|
1332
|
+
if condition.type in variable_type + ["field_expression"]:
|
|
1333
|
+
add_entry(parser, rda_table, parent_id, used=condition)
|
|
1334
|
+
else:
|
|
1335
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1336
|
+
condition,
|
|
1337
|
+
variable_type + ["field_expression"],
|
|
1338
|
+
index=parser.index,
|
|
1339
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1340
|
+
)
|
|
1341
|
+
for identifier in identifiers_used:
|
|
1342
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1343
|
+
literals_used = recursively_get_children_of_types(
|
|
1344
|
+
condition, literal_types, index=parser.index
|
|
1345
|
+
)
|
|
1346
|
+
for literal in literals_used:
|
|
1347
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1348
|
+
|
|
1349
|
+
consequence = root_node.child_by_field_name("consequence")
|
|
1350
|
+
if consequence:
|
|
1351
|
+
if consequence.type in variable_type + ["field_expression"]:
|
|
1352
|
+
add_entry(parser, rda_table, parent_id, used=consequence)
|
|
1353
|
+
else:
|
|
1354
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1355
|
+
consequence,
|
|
1356
|
+
variable_type + ["field_expression"],
|
|
1357
|
+
index=parser.index,
|
|
1358
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1359
|
+
)
|
|
1360
|
+
for identifier in identifiers_used:
|
|
1361
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1362
|
+
literals_used = recursively_get_children_of_types(
|
|
1363
|
+
consequence, literal_types, index=parser.index
|
|
1364
|
+
)
|
|
1365
|
+
for literal in literals_used:
|
|
1366
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1367
|
+
|
|
1368
|
+
alternative = root_node.child_by_field_name("alternative")
|
|
1369
|
+
if alternative:
|
|
1370
|
+
if alternative.type in variable_type + ["field_expression"]:
|
|
1371
|
+
add_entry(parser, rda_table, parent_id, used=alternative)
|
|
1372
|
+
else:
|
|
1373
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1374
|
+
alternative,
|
|
1375
|
+
variable_type + ["field_expression"],
|
|
1376
|
+
index=parser.index,
|
|
1377
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1378
|
+
)
|
|
1379
|
+
for identifier in identifiers_used:
|
|
1380
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1381
|
+
literals_used = recursively_get_children_of_types(
|
|
1382
|
+
alternative, literal_types, index=parser.index
|
|
1383
|
+
)
|
|
1384
|
+
for literal in literals_used:
|
|
1385
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1386
|
+
|
|
1387
|
+
else:
|
|
1388
|
+
if root_node.type not in variable_type:
|
|
1389
|
+
continue
|
|
1390
|
+
|
|
1391
|
+
in_do_while_condition = False
|
|
1392
|
+
temp_parent = root_node.parent
|
|
1393
|
+
while temp_parent is not None:
|
|
1394
|
+
if (
|
|
1395
|
+
temp_parent.type == "parenthesized_expression"
|
|
1396
|
+
and temp_parent.parent is not None
|
|
1397
|
+
and temp_parent.parent.type == "do_statement"
|
|
1398
|
+
):
|
|
1399
|
+
in_do_while_condition = True
|
|
1400
|
+
break
|
|
1401
|
+
temp_parent = temp_parent.parent
|
|
1402
|
+
|
|
1403
|
+
if in_do_while_condition:
|
|
1404
|
+
continue
|
|
1405
|
+
|
|
1406
|
+
handled_types = (
|
|
1407
|
+
def_statement
|
|
1408
|
+
+ assignment
|
|
1409
|
+
+ increment_statement
|
|
1410
|
+
+ function_calls
|
|
1411
|
+
+ ["return_statement"]
|
|
1412
|
+
)
|
|
1413
|
+
parent_statement = return_first_parent_of_types(
|
|
1414
|
+
root_node,
|
|
1415
|
+
statement_types["non_control_statement"]
|
|
1416
|
+
+ statement_types["control_statement"],
|
|
1417
|
+
stop_types=statement_types.get("statement_holders", []) + handled_types,
|
|
1418
|
+
)
|
|
1419
|
+
|
|
1420
|
+
if parent_statement is None:
|
|
1421
|
+
continue
|
|
1422
|
+
|
|
1423
|
+
parent_id = get_index(parent_statement, index)
|
|
1424
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1425
|
+
continue
|
|
1426
|
+
|
|
1427
|
+
immediate_parent = root_node.parent
|
|
1428
|
+
if immediate_parent and immediate_parent.type == "pointer_expression":
|
|
1429
|
+
continue
|
|
1430
|
+
|
|
1431
|
+
add_entry(parser, rda_table, parent_id, used=root_node)
|
|
1432
|
+
|
|
1433
|
+
return rda_table
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
def start_rda(index, rda_table, cfg_graph, pre_solve=False):
|
|
1437
|
+
"""
|
|
1438
|
+
Perform Reaching Definitions Analysis.
|
|
1439
|
+
|
|
1440
|
+
Fixed-point iteration algorithm:
|
|
1441
|
+
Initialize all IN/OUT to empty
|
|
1442
|
+
Repeat until convergence:
|
|
1443
|
+
For each statement s:
|
|
1444
|
+
IN[s] = union of OUT[p] for predecessors p
|
|
1445
|
+
OUT[s] = (IN[s] - KILL[s]) ∪ DEF[s]
|
|
1446
|
+
"""
|
|
1447
|
+
graph = copy.deepcopy(cfg_graph)
|
|
1448
|
+
if pre_solve:
|
|
1449
|
+
remove_edges = []
|
|
1450
|
+
for edge in graph.edges:
|
|
1451
|
+
edge_data = graph.edges[edge]
|
|
1452
|
+
if "label" in edge_data and edge_data["label"] in [
|
|
1453
|
+
"function_call",
|
|
1454
|
+
"function_return",
|
|
1455
|
+
]:
|
|
1456
|
+
remove_edges.append(edge)
|
|
1457
|
+
graph.remove_edges_from(remove_edges)
|
|
1458
|
+
|
|
1459
|
+
cfg = graph
|
|
1460
|
+
nodes = graph.nodes
|
|
1461
|
+
|
|
1462
|
+
old_result = {}
|
|
1463
|
+
for node in nodes:
|
|
1464
|
+
old_result[node] = {"IN": set(), "OUT": set()}
|
|
1465
|
+
|
|
1466
|
+
new_result = copy.deepcopy(old_result)
|
|
1467
|
+
iteration = 0
|
|
1468
|
+
|
|
1469
|
+
while True:
|
|
1470
|
+
iteration += 1
|
|
1471
|
+
|
|
1472
|
+
for node in nodes:
|
|
1473
|
+
predecessors = [s for (s, t) in cfg.in_edges(node)]
|
|
1474
|
+
|
|
1475
|
+
in_set = set()
|
|
1476
|
+
for pred in predecessors:
|
|
1477
|
+
in_set = in_set.union(old_result[pred]["OUT"])
|
|
1478
|
+
|
|
1479
|
+
new_result[node]["IN"] = in_set
|
|
1480
|
+
|
|
1481
|
+
def_info = rda_table[node]["def"] if node in rda_table else set()
|
|
1482
|
+
names_defined = [d.name for d in def_info]
|
|
1483
|
+
|
|
1484
|
+
surviving_defs = set()
|
|
1485
|
+
for incoming_def in in_set:
|
|
1486
|
+
if incoming_def.name not in names_defined:
|
|
1487
|
+
surviving_defs.add(incoming_def)
|
|
1488
|
+
|
|
1489
|
+
new_result[node]["OUT"] = surviving_defs.union(def_info)
|
|
1490
|
+
|
|
1491
|
+
ddiff = DeepDiff(old_result, new_result, ignore_order=True)
|
|
1492
|
+
if ddiff == {}:
|
|
1493
|
+
if debug:
|
|
1494
|
+
logger.info("RDA: Converged in {} iterations", iteration)
|
|
1495
|
+
break
|
|
1496
|
+
|
|
1497
|
+
old_result = copy.deepcopy(new_result)
|
|
1498
|
+
|
|
1499
|
+
return new_result
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
def add_edge(final_graph, source, target, attrib=None):
|
|
1503
|
+
"""Add edge to graph with attributes, preventing duplicates"""
|
|
1504
|
+
if attrib is not None:
|
|
1505
|
+
used_def = attrib.get("used_def", None)
|
|
1506
|
+
edge_type = attrib.get("edge_type", None)
|
|
1507
|
+
dataflow_type = attrib.get("dataflow_type", None)
|
|
1508
|
+
|
|
1509
|
+
for u, v, k, data in final_graph.edges(keys=True, data=True):
|
|
1510
|
+
if (
|
|
1511
|
+
u == source
|
|
1512
|
+
and v == target
|
|
1513
|
+
and data.get("used_def") == used_def
|
|
1514
|
+
and data.get("edge_type") == edge_type
|
|
1515
|
+
and data.get("dataflow_type") == dataflow_type
|
|
1516
|
+
):
|
|
1517
|
+
return
|
|
1518
|
+
|
|
1519
|
+
final_graph.add_edge(source, target)
|
|
1520
|
+
if attrib is not None:
|
|
1521
|
+
edge_keys = [
|
|
1522
|
+
k for u, v, k in final_graph.edges(keys=True) if u == source and v == target
|
|
1523
|
+
]
|
|
1524
|
+
if edge_keys:
|
|
1525
|
+
edge_key = max(edge_keys)
|
|
1526
|
+
else:
|
|
1527
|
+
edge_key = 0
|
|
1528
|
+
nx.set_edge_attributes(final_graph, {(source, target, edge_key): attrib})
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
def name_match_with_fields(name1, name2):
|
|
1532
|
+
"""Check if two names match (handling struct fields)"""
|
|
1533
|
+
if name1 == name2:
|
|
1534
|
+
return True
|
|
1535
|
+
|
|
1536
|
+
if name1.startswith(name2 + ".") or name2.startswith(name1 + "."):
|
|
1537
|
+
return True
|
|
1538
|
+
|
|
1539
|
+
return False
|
|
1540
|
+
|
|
1541
|
+
|
|
1542
|
+
def get_required_edges_from_def_to_use(
|
|
1543
|
+
index, cfg, rda_solution, rda_table, graph_nodes, processed_edges, properties
|
|
1544
|
+
):
|
|
1545
|
+
"""
|
|
1546
|
+
Generate DFG edges from RDA solution.
|
|
1547
|
+
|
|
1548
|
+
For each statement s:
|
|
1549
|
+
For each use u in USE[s]:
|
|
1550
|
+
For each def d in IN[s]:
|
|
1551
|
+
If d.name == u.name and scope_check(d.scope, u.scope):
|
|
1552
|
+
Add edge: d.line → s
|
|
1553
|
+
"""
|
|
1554
|
+
final_graph = copy.deepcopy(cfg)
|
|
1555
|
+
final_graph.remove_edges_from(list(final_graph.edges()))
|
|
1556
|
+
|
|
1557
|
+
for node in graph_nodes:
|
|
1558
|
+
if node not in rda_table:
|
|
1559
|
+
continue
|
|
1560
|
+
|
|
1561
|
+
use_info = rda_table[node]["use"]
|
|
1562
|
+
|
|
1563
|
+
for used in use_info:
|
|
1564
|
+
if isinstance(used, Literal):
|
|
1565
|
+
used.satisfied = True
|
|
1566
|
+
continue
|
|
1567
|
+
|
|
1568
|
+
for available_def in rda_solution[node]["IN"]:
|
|
1569
|
+
if available_def.name == used.name:
|
|
1570
|
+
if scope_check(available_def.scope, used.scope):
|
|
1571
|
+
add_edge(
|
|
1572
|
+
final_graph,
|
|
1573
|
+
available_def.line,
|
|
1574
|
+
node,
|
|
1575
|
+
{
|
|
1576
|
+
"dataflow_type": "comesFrom",
|
|
1577
|
+
"edge_type": "DFG_edge",
|
|
1578
|
+
"color": "#00A3FF",
|
|
1579
|
+
"used_def": used.name,
|
|
1580
|
+
},
|
|
1581
|
+
)
|
|
1582
|
+
used.satisfied = True
|
|
1583
|
+
|
|
1584
|
+
elif "." in used.name or "." in available_def.name:
|
|
1585
|
+
if name_match_with_fields(used.name, available_def.name):
|
|
1586
|
+
if scope_check(available_def.scope, used.scope):
|
|
1587
|
+
add_edge(
|
|
1588
|
+
final_graph,
|
|
1589
|
+
available_def.line,
|
|
1590
|
+
node,
|
|
1591
|
+
{
|
|
1592
|
+
"dataflow_type": "comesFrom",
|
|
1593
|
+
"edge_type": "DFG_edge",
|
|
1594
|
+
"color": "#00A3FF",
|
|
1595
|
+
"used_def": used.name,
|
|
1596
|
+
},
|
|
1597
|
+
)
|
|
1598
|
+
used.satisfied = True
|
|
1599
|
+
|
|
1600
|
+
if not used.satisfied:
|
|
1601
|
+
for def_node in graph_nodes:
|
|
1602
|
+
if def_node not in rda_table:
|
|
1603
|
+
continue
|
|
1604
|
+
for definition in rda_table[def_node]["def"]:
|
|
1605
|
+
if definition.name == used.name:
|
|
1606
|
+
node_type = (
|
|
1607
|
+
read_index(index, def_node)[-1]
|
|
1608
|
+
if def_node in index.values()
|
|
1609
|
+
else None
|
|
1610
|
+
)
|
|
1611
|
+
if node_type == "function_definition":
|
|
1612
|
+
add_edge(
|
|
1613
|
+
final_graph,
|
|
1614
|
+
def_node,
|
|
1615
|
+
node,
|
|
1616
|
+
{
|
|
1617
|
+
"dataflow_type": "comesFrom",
|
|
1618
|
+
"edge_type": "DFG_edge",
|
|
1619
|
+
"color": "#00A3FF",
|
|
1620
|
+
"used_def": used.name,
|
|
1621
|
+
},
|
|
1622
|
+
)
|
|
1623
|
+
used.satisfied = True
|
|
1624
|
+
break
|
|
1625
|
+
|
|
1626
|
+
if properties.get("last_def", False):
|
|
1627
|
+
killed_defs = rda_solution[node]["IN"] - rda_solution[node]["OUT"]
|
|
1628
|
+
for killed_def in killed_defs:
|
|
1629
|
+
node_type = read_index(index, node)[-1]
|
|
1630
|
+
def_node_type = read_index(index, killed_def.line)[-1]
|
|
1631
|
+
ignore_types = [
|
|
1632
|
+
"for_statement",
|
|
1633
|
+
"while_statement",
|
|
1634
|
+
"if_statement",
|
|
1635
|
+
"switch_statement",
|
|
1636
|
+
]
|
|
1637
|
+
if node_type not in ignore_types and def_node_type not in ignore_types:
|
|
1638
|
+
add_edge(
|
|
1639
|
+
final_graph,
|
|
1640
|
+
killed_def.line,
|
|
1641
|
+
node,
|
|
1642
|
+
{"color": "orange", "dataflow_type": "lastDef"},
|
|
1643
|
+
)
|
|
1644
|
+
|
|
1645
|
+
for edge in processed_edges:
|
|
1646
|
+
add_edge(
|
|
1647
|
+
final_graph,
|
|
1648
|
+
edge[0],
|
|
1649
|
+
edge[1],
|
|
1650
|
+
{"dataflow_type": "parameter", "edge_type": "DFG_edge"},
|
|
1651
|
+
)
|
|
1652
|
+
|
|
1653
|
+
return final_graph
|
|
1654
|
+
|
|
1655
|
+
|
|
1656
|
+
def rda_cfg_map(rda_solution, CFG_results):
|
|
1657
|
+
"""Create debug graph showing RDA info on CFG edges"""
|
|
1658
|
+
graph = copy.deepcopy(CFG_results.graph)
|
|
1659
|
+
|
|
1660
|
+
for edge in list(graph.edges):
|
|
1661
|
+
out_set = rda_solution[edge[0]]["OUT"]
|
|
1662
|
+
in_set = rda_solution[edge[1]]["IN"]
|
|
1663
|
+
|
|
1664
|
+
intersection = [d for d in out_set if d in in_set]
|
|
1665
|
+
|
|
1666
|
+
if intersection:
|
|
1667
|
+
edge_data = graph.get_edge_data(*edge)
|
|
1668
|
+
edge_data["rda_info"] = ",".join([str(d) for d in intersection])
|
|
1669
|
+
else:
|
|
1670
|
+
graph.remove_edge(*edge)
|
|
1671
|
+
|
|
1672
|
+
return graph
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
def collect_call_site_information(parser, function_metadata, cfg_graph):
|
|
1676
|
+
"""
|
|
1677
|
+
Collect information about function call sites for interprocedural analysis.
|
|
1678
|
+
|
|
1679
|
+
For each call site, track:
|
|
1680
|
+
- Which function is called
|
|
1681
|
+
- Which arguments are passed by reference (&var)
|
|
1682
|
+
- The mapping of actual arguments to formal parameters
|
|
1683
|
+
|
|
1684
|
+
Returns:
|
|
1685
|
+
List of dicts with call site information:
|
|
1686
|
+
{
|
|
1687
|
+
"call_site_node": AST node,
|
|
1688
|
+
"call_site_id": CFG node ID,
|
|
1689
|
+
"function_name": str,
|
|
1690
|
+
"pass_by_ref_args": [(arg_idx, var_name, var_node), ...]
|
|
1691
|
+
}
|
|
1692
|
+
"""
|
|
1693
|
+
call_sites = []
|
|
1694
|
+
index = parser.index
|
|
1695
|
+
|
|
1696
|
+
for node in traverse_tree(parser.tree.root_node):
|
|
1697
|
+
if node.type == "call_expression":
|
|
1698
|
+
function_name = None
|
|
1699
|
+
if node.children and node.children[0].type == "identifier":
|
|
1700
|
+
function_name = st(node.children[0])
|
|
1701
|
+
|
|
1702
|
+
if not function_name or function_name not in function_metadata:
|
|
1703
|
+
continue
|
|
1704
|
+
|
|
1705
|
+
parent_statement = return_first_parent_of_types(
|
|
1706
|
+
node, statement_types["node_list_type"]
|
|
1707
|
+
)
|
|
1708
|
+
if not parent_statement:
|
|
1709
|
+
continue
|
|
1710
|
+
|
|
1711
|
+
call_site_id = get_index(parent_statement, index)
|
|
1712
|
+
if call_site_id is None or call_site_id not in cfg_graph.nodes:
|
|
1713
|
+
continue
|
|
1714
|
+
|
|
1715
|
+
pass_by_ref_args = []
|
|
1716
|
+
for child in node.children[1:]:
|
|
1717
|
+
if child.type == "argument_list":
|
|
1718
|
+
func_params = function_metadata[function_name]["params"]
|
|
1719
|
+
|
|
1720
|
+
for arg_idx, arg in enumerate(child.named_children):
|
|
1721
|
+
if arg_idx < len(func_params):
|
|
1722
|
+
param_name, is_pointer, param_idx = func_params[arg_idx]
|
|
1723
|
+
|
|
1724
|
+
if is_pointer:
|
|
1725
|
+
if arg.type == "pointer_expression":
|
|
1726
|
+
has_ampersand = False
|
|
1727
|
+
arg_node = None
|
|
1728
|
+
for arg_child in arg.children:
|
|
1729
|
+
if arg_child.type == "&":
|
|
1730
|
+
has_ampersand = True
|
|
1731
|
+
elif arg_child.is_named:
|
|
1732
|
+
arg_node = arg_child
|
|
1733
|
+
|
|
1734
|
+
if has_ampersand and arg_node:
|
|
1735
|
+
if arg_node.type == "identifier":
|
|
1736
|
+
var_name = st(arg_node)
|
|
1737
|
+
pass_by_ref_args.append(
|
|
1738
|
+
(arg_idx, var_name, arg_node)
|
|
1739
|
+
)
|
|
1740
|
+
elif arg.type == "identifier":
|
|
1741
|
+
var_name = st(arg)
|
|
1742
|
+
arg_index = get_index(arg, index)
|
|
1743
|
+
if (
|
|
1744
|
+
arg_index
|
|
1745
|
+
and arg_index
|
|
1746
|
+
in parser.symbol_table["scope_map"]
|
|
1747
|
+
):
|
|
1748
|
+
pass_by_ref_args.append(
|
|
1749
|
+
(arg_idx, var_name, arg)
|
|
1750
|
+
)
|
|
1751
|
+
|
|
1752
|
+
if pass_by_ref_args:
|
|
1753
|
+
call_sites.append(
|
|
1754
|
+
{
|
|
1755
|
+
"call_site_node": node,
|
|
1756
|
+
"call_site_id": call_site_id,
|
|
1757
|
+
"function_name": function_name,
|
|
1758
|
+
"pass_by_ref_args": pass_by_ref_args,
|
|
1759
|
+
}
|
|
1760
|
+
)
|
|
1761
|
+
|
|
1762
|
+
return call_sites
|
|
1763
|
+
|
|
1764
|
+
|
|
1765
|
+
def find_modification_sites(parser, function_metadata, pointer_modifications):
|
|
1766
|
+
"""
|
|
1767
|
+
Find all modification sites for pointer parameters inside functions.
|
|
1768
|
+
|
|
1769
|
+
For each function, find all statements where a pointer parameter is modified.
|
|
1770
|
+
|
|
1771
|
+
Returns:
|
|
1772
|
+
Dict mapping function_name -> list of (param_idx, modification_node, statement_id)
|
|
1773
|
+
"""
|
|
1774
|
+
modification_sites = {}
|
|
1775
|
+
index = parser.index
|
|
1776
|
+
|
|
1777
|
+
for func_name, meta in function_metadata.items():
|
|
1778
|
+
modifications = []
|
|
1779
|
+
func_node = meta["node"]
|
|
1780
|
+
modified_params = pointer_modifications.get(func_name, set())
|
|
1781
|
+
|
|
1782
|
+
param_name_to_idx = {}
|
|
1783
|
+
for param_name, is_pointer, param_idx in meta["params"]:
|
|
1784
|
+
if is_pointer and param_idx in modified_params:
|
|
1785
|
+
param_name_to_idx[param_name] = param_idx
|
|
1786
|
+
|
|
1787
|
+
if not param_name_to_idx:
|
|
1788
|
+
modification_sites[func_name] = modifications
|
|
1789
|
+
continue
|
|
1790
|
+
|
|
1791
|
+
for node in traverse_tree(func_node):
|
|
1792
|
+
modification_param_idx = None
|
|
1793
|
+
mod_node = None
|
|
1794
|
+
|
|
1795
|
+
if node.type == "assignment_expression":
|
|
1796
|
+
left = node.child_by_field_name("left")
|
|
1797
|
+
if left:
|
|
1798
|
+
if left.type == "pointer_expression":
|
|
1799
|
+
arg = left.child_by_field_name("argument")
|
|
1800
|
+
if arg and arg.type == "identifier":
|
|
1801
|
+
var_name = st(arg)
|
|
1802
|
+
if var_name in param_name_to_idx:
|
|
1803
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
1804
|
+
mod_node = node
|
|
1805
|
+
|
|
1806
|
+
elif left.type == "subscript_expression":
|
|
1807
|
+
array_arg = left.child_by_field_name("argument")
|
|
1808
|
+
if array_arg and array_arg.type == "identifier":
|
|
1809
|
+
var_name = st(array_arg)
|
|
1810
|
+
if var_name in param_name_to_idx:
|
|
1811
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
1812
|
+
mod_node = node
|
|
1813
|
+
|
|
1814
|
+
elif node.type == "update_expression":
|
|
1815
|
+
arg = node.child_by_field_name("argument")
|
|
1816
|
+
if arg:
|
|
1817
|
+
if arg.type == "parenthesized_expression":
|
|
1818
|
+
inner_children = [c for c in arg.named_children if c.is_named]
|
|
1819
|
+
if inner_children:
|
|
1820
|
+
arg = inner_children[0]
|
|
1821
|
+
|
|
1822
|
+
if arg.type == "pointer_expression":
|
|
1823
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1824
|
+
if inner_arg and inner_arg.type == "identifier":
|
|
1825
|
+
var_name = st(inner_arg)
|
|
1826
|
+
if var_name in param_name_to_idx:
|
|
1827
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
1828
|
+
mod_node = node
|
|
1829
|
+
elif arg.type == "subscript_expression":
|
|
1830
|
+
array_arg = arg.child_by_field_name("argument")
|
|
1831
|
+
if array_arg and array_arg.type == "identifier":
|
|
1832
|
+
var_name = st(array_arg)
|
|
1833
|
+
if var_name in param_name_to_idx:
|
|
1834
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
1835
|
+
mod_node = node
|
|
1836
|
+
|
|
1837
|
+
if modification_param_idx is not None and mod_node is not None:
|
|
1838
|
+
parent_statement = return_first_parent_of_types(
|
|
1839
|
+
mod_node, statement_types["node_list_type"]
|
|
1840
|
+
)
|
|
1841
|
+
if parent_statement:
|
|
1842
|
+
statement_id = get_index(parent_statement, index)
|
|
1843
|
+
if statement_id is not None:
|
|
1844
|
+
modifications.append(
|
|
1845
|
+
(modification_param_idx, mod_node, statement_id)
|
|
1846
|
+
)
|
|
1847
|
+
|
|
1848
|
+
modification_sites[func_name] = modifications
|
|
1849
|
+
|
|
1850
|
+
return modification_sites
|
|
1851
|
+
|
|
1852
|
+
|
|
1853
|
+
def add_interprocedural_edges(
|
|
1854
|
+
final_graph,
|
|
1855
|
+
parser,
|
|
1856
|
+
call_sites,
|
|
1857
|
+
modification_sites,
|
|
1858
|
+
function_metadata,
|
|
1859
|
+
cfg_graph,
|
|
1860
|
+
rda_table,
|
|
1861
|
+
):
|
|
1862
|
+
"""
|
|
1863
|
+
Add interprocedural DFG edges for pass-by-reference.
|
|
1864
|
+
|
|
1865
|
+
For each call site where &var is passed to a pointer parameter:
|
|
1866
|
+
1. Add edge from call site to function definition (argument-parameter binding)
|
|
1867
|
+
2. Add edges from modification sites inside function to uses after the call
|
|
1868
|
+
|
|
1869
|
+
Args:
|
|
1870
|
+
final_graph: The DFG graph to add edges to
|
|
1871
|
+
parser: C parser
|
|
1872
|
+
call_sites: List of call site information from collect_call_site_information()
|
|
1873
|
+
modification_sites: Dict from find_modification_sites()
|
|
1874
|
+
function_metadata: Dict from collect_function_metadata()
|
|
1875
|
+
cfg_graph: Control flow graph
|
|
1876
|
+
rda_table: RDA table with def/use information
|
|
1877
|
+
"""
|
|
1878
|
+
index = parser.index
|
|
1879
|
+
|
|
1880
|
+
for call_site_info in call_sites:
|
|
1881
|
+
call_site_id = call_site_info["call_site_id"]
|
|
1882
|
+
function_name = call_site_info["function_name"]
|
|
1883
|
+
pass_by_ref_args = call_site_info["pass_by_ref_args"]
|
|
1884
|
+
|
|
1885
|
+
if (
|
|
1886
|
+
function_name not in function_metadata
|
|
1887
|
+
or function_name not in modification_sites
|
|
1888
|
+
):
|
|
1889
|
+
continue
|
|
1890
|
+
|
|
1891
|
+
func_meta = function_metadata[function_name]
|
|
1892
|
+
func_node = func_meta["node"]
|
|
1893
|
+
func_def_id = get_index(func_node, index)
|
|
1894
|
+
|
|
1895
|
+
if func_def_id is None:
|
|
1896
|
+
continue
|
|
1897
|
+
|
|
1898
|
+
for arg_idx, var_name, var_node in pass_by_ref_args:
|
|
1899
|
+
add_edge(
|
|
1900
|
+
final_graph,
|
|
1901
|
+
call_site_id,
|
|
1902
|
+
func_def_id,
|
|
1903
|
+
{
|
|
1904
|
+
"dataflow_type": "comesFrom",
|
|
1905
|
+
"edge_type": "DFG_edge",
|
|
1906
|
+
"color": "#00A3FF",
|
|
1907
|
+
"used_def": var_name,
|
|
1908
|
+
"interprocedural": "call_to_function",
|
|
1909
|
+
},
|
|
1910
|
+
)
|
|
1911
|
+
|
|
1912
|
+
mods = modification_sites.get(function_name, [])
|
|
1913
|
+
for mod_param_idx, mod_node, mod_statement_id in mods:
|
|
1914
|
+
if mod_param_idx == arg_idx:
|
|
1915
|
+
successors = []
|
|
1916
|
+
visited = set()
|
|
1917
|
+
queue = [call_site_id]
|
|
1918
|
+
|
|
1919
|
+
while queue:
|
|
1920
|
+
current = queue.pop(0)
|
|
1921
|
+
if current in visited:
|
|
1922
|
+
continue
|
|
1923
|
+
visited.add(current)
|
|
1924
|
+
|
|
1925
|
+
uses_var = False
|
|
1926
|
+
defines_var = False
|
|
1927
|
+
if current != call_site_id and current in rda_table:
|
|
1928
|
+
for used in rda_table[current]["use"]:
|
|
1929
|
+
if used.name == var_name:
|
|
1930
|
+
uses_var = True
|
|
1931
|
+
successors.append(current)
|
|
1932
|
+
break
|
|
1933
|
+
|
|
1934
|
+
for defined in rda_table[current]["def"]:
|
|
1935
|
+
if defined.name == var_name:
|
|
1936
|
+
defines_var = True
|
|
1937
|
+
break
|
|
1938
|
+
|
|
1939
|
+
if (
|
|
1940
|
+
current == call_site_id
|
|
1941
|
+
or not uses_var
|
|
1942
|
+
or (uses_var and defines_var)
|
|
1943
|
+
):
|
|
1944
|
+
for edge in cfg_graph.out_edges(current):
|
|
1945
|
+
if edge[1] not in visited:
|
|
1946
|
+
queue.append(edge[1])
|
|
1947
|
+
|
|
1948
|
+
for use_site in successors:
|
|
1949
|
+
add_edge(
|
|
1950
|
+
final_graph,
|
|
1951
|
+
mod_statement_id,
|
|
1952
|
+
use_site,
|
|
1953
|
+
{
|
|
1954
|
+
"dataflow_type": "comesFrom",
|
|
1955
|
+
"edge_type": "DFG_edge",
|
|
1956
|
+
"color": "#00A3FF",
|
|
1957
|
+
"used_def": var_name,
|
|
1958
|
+
"interprocedural": "modification_to_use",
|
|
1959
|
+
},
|
|
1960
|
+
)
|
|
1961
|
+
|
|
1962
|
+
|
|
1963
|
+
def dfg_c(properties, CFG_results):
|
|
1964
|
+
"""
|
|
1965
|
+
Main driver for generating DFG for C programs.
|
|
1966
|
+
|
|
1967
|
+
Args:
|
|
1968
|
+
properties: Configuration dict with DFG options
|
|
1969
|
+
CFG_results: CFG driver results with graph, parser, etc.
|
|
1970
|
+
|
|
1971
|
+
Returns:
|
|
1972
|
+
(final_graph, debug_graph, rda_table, rda_solution)
|
|
1973
|
+
"""
|
|
1974
|
+
parser = CFG_results.parser
|
|
1975
|
+
index = parser.index
|
|
1976
|
+
tree = parser.tree
|
|
1977
|
+
|
|
1978
|
+
cfg_graph = copy.deepcopy(CFG_results.graph)
|
|
1979
|
+
node_list = CFG_results.node_list
|
|
1980
|
+
|
|
1981
|
+
processed_edges = []
|
|
1982
|
+
for edge in list(cfg_graph.edges()):
|
|
1983
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
1984
|
+
if edge_data and len(edge_data) > 0:
|
|
1985
|
+
edge_data = edge_data[0]
|
|
1986
|
+
if edge_data.get("label") == "function_return":
|
|
1987
|
+
return_statement = node_list.get(read_index(index, edge[0]))
|
|
1988
|
+
call_site_node = node_list.get(read_index(index, edge[1]))
|
|
1989
|
+
|
|
1990
|
+
if return_statement and return_statement.type == "return_statement":
|
|
1991
|
+
if return_statement.named_children:
|
|
1992
|
+
if call_site_node and is_return_value_used(call_site_node):
|
|
1993
|
+
processed_edges.append(edge)
|
|
1994
|
+
|
|
1995
|
+
function_metadata = collect_function_metadata(parser)
|
|
1996
|
+
pointer_modifications = analyze_pointer_modifications(parser, function_metadata)
|
|
1997
|
+
|
|
1998
|
+
start_rda_init_time = time.time()
|
|
1999
|
+
rda_table = build_rda_table(
|
|
2000
|
+
parser, CFG_results, function_metadata, pointer_modifications
|
|
2001
|
+
)
|
|
2002
|
+
end_rda_init_time = time.time()
|
|
2003
|
+
|
|
2004
|
+
start_rda_time = time.time()
|
|
2005
|
+
rda_solution = start_rda(index, rda_table, cfg_graph, pre_solve=True)
|
|
2006
|
+
end_rda_time = time.time()
|
|
2007
|
+
|
|
2008
|
+
final_graph = get_required_edges_from_def_to_use(
|
|
2009
|
+
index,
|
|
2010
|
+
cfg_graph,
|
|
2011
|
+
rda_solution,
|
|
2012
|
+
rda_table,
|
|
2013
|
+
cfg_graph.nodes,
|
|
2014
|
+
processed_edges,
|
|
2015
|
+
properties,
|
|
2016
|
+
)
|
|
2017
|
+
|
|
2018
|
+
call_sites = collect_call_site_information(parser, function_metadata, cfg_graph)
|
|
2019
|
+
modification_sites = find_modification_sites(
|
|
2020
|
+
parser, function_metadata, pointer_modifications
|
|
2021
|
+
)
|
|
2022
|
+
add_interprocedural_edges(
|
|
2023
|
+
final_graph,
|
|
2024
|
+
parser,
|
|
2025
|
+
call_sites,
|
|
2026
|
+
modification_sites,
|
|
2027
|
+
function_metadata,
|
|
2028
|
+
cfg_graph,
|
|
2029
|
+
rda_table,
|
|
2030
|
+
)
|
|
2031
|
+
|
|
2032
|
+
if debug:
|
|
2033
|
+
logger.info(
|
|
2034
|
+
"RDA init: {:.3f}s, RDA: {:.3f}s",
|
|
2035
|
+
end_rda_init_time - start_rda_init_time,
|
|
2036
|
+
end_rda_time - start_rda_time,
|
|
2037
|
+
)
|
|
2038
|
+
|
|
2039
|
+
debug_graph = rda_cfg_map(rda_solution, CFG_results)
|
|
2040
|
+
|
|
2041
|
+
return final_graph, debug_graph, rda_table, rda_solution
|