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,4030 @@
|
|
|
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.cpp_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", "this", "qualified_identifier"]
|
|
17
|
+
function_calls = ["call_expression"]
|
|
18
|
+
method_calls = ["call_expression"]
|
|
19
|
+
literal_types = [
|
|
20
|
+
"number_literal",
|
|
21
|
+
"string_literal",
|
|
22
|
+
"char_literal",
|
|
23
|
+
"raw_string_literal",
|
|
24
|
+
"true",
|
|
25
|
+
"false",
|
|
26
|
+
"nullptr",
|
|
27
|
+
"null",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
input_functions = [
|
|
32
|
+
"scanf",
|
|
33
|
+
"gets",
|
|
34
|
+
"fgets",
|
|
35
|
+
"getline",
|
|
36
|
+
"fscanf",
|
|
37
|
+
"sscanf",
|
|
38
|
+
"fread",
|
|
39
|
+
"read",
|
|
40
|
+
"recv",
|
|
41
|
+
"recvfrom",
|
|
42
|
+
"getchar",
|
|
43
|
+
"fgetc",
|
|
44
|
+
"cin",
|
|
45
|
+
"std::cin",
|
|
46
|
+
]
|
|
47
|
+
inner_types = ["declaration", "expression_statement"]
|
|
48
|
+
handled_types = (
|
|
49
|
+
assignment
|
|
50
|
+
+ def_statement
|
|
51
|
+
+ increment_statement
|
|
52
|
+
+ function_calls
|
|
53
|
+
+ [
|
|
54
|
+
"function_definition",
|
|
55
|
+
"return_statement",
|
|
56
|
+
"for_statement",
|
|
57
|
+
"for_range_loop",
|
|
58
|
+
"switch_statement",
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
debug = False
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def st(child):
|
|
66
|
+
"""Get text from AST node"""
|
|
67
|
+
if child is None:
|
|
68
|
+
return ""
|
|
69
|
+
else:
|
|
70
|
+
return child.text.decode()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_index(node, index):
|
|
74
|
+
"""Get unique index for AST node"""
|
|
75
|
+
try:
|
|
76
|
+
return index[(node.start_point, node.end_point, node.type)]
|
|
77
|
+
except:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def read_index(index, idx):
|
|
82
|
+
"""Get AST node key from index value"""
|
|
83
|
+
return list(index.keys())[list(index.values()).index(idx)]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def scope_check(parent_scope, child_scope):
|
|
87
|
+
"""
|
|
88
|
+
Check if a definition's scope can reach a use's scope.
|
|
89
|
+
|
|
90
|
+
A definition at scope [0, 1, 2] can reach uses at:
|
|
91
|
+
- [0, 1, 2] (same scope)
|
|
92
|
+
- [0, 1, 2, 3] (nested scope)
|
|
93
|
+
|
|
94
|
+
But NOT:
|
|
95
|
+
- [0, 1] (parent scope)
|
|
96
|
+
- [0, 1, 3] (sibling scope)
|
|
97
|
+
"""
|
|
98
|
+
for p in parent_scope:
|
|
99
|
+
if p not in child_scope:
|
|
100
|
+
return False
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def set_add(lst, item):
|
|
105
|
+
"""Add item to list if not already present (set-like behavior)"""
|
|
106
|
+
for entry in lst:
|
|
107
|
+
if item == entry:
|
|
108
|
+
return
|
|
109
|
+
lst.append(item)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def set_union(first_list, second_list):
|
|
113
|
+
"""Union of two lists (set-like)"""
|
|
114
|
+
resulting_list = list(first_list)
|
|
115
|
+
resulting_list.extend(x for x in second_list if x not in resulting_list)
|
|
116
|
+
return resulting_list
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def set_difference(first_list, second_list):
|
|
120
|
+
"""Difference of two lists (set-like)"""
|
|
121
|
+
return [item for item in first_list if item not in second_list]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def return_first_parent_of_types(node, parent_types, stop_types=None):
|
|
125
|
+
"""Find first parent of given types"""
|
|
126
|
+
if stop_types is None:
|
|
127
|
+
stop_types = []
|
|
128
|
+
|
|
129
|
+
if node.type in parent_types:
|
|
130
|
+
return node
|
|
131
|
+
|
|
132
|
+
while node.parent is not None:
|
|
133
|
+
if node.type in stop_types:
|
|
134
|
+
return None
|
|
135
|
+
if node.parent.type in parent_types:
|
|
136
|
+
return node.parent
|
|
137
|
+
node = node.parent
|
|
138
|
+
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def is_node_inside_loop(ast_node):
|
|
143
|
+
"""
|
|
144
|
+
Check if an AST node is inside a loop structure.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
ast_node: AST node to check
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
True if node is inside a loop (for/while/do-while), False otherwise
|
|
151
|
+
"""
|
|
152
|
+
if ast_node is None:
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
current = ast_node
|
|
156
|
+
while current.parent is not None:
|
|
157
|
+
if current.parent.type in [
|
|
158
|
+
"for_statement",
|
|
159
|
+
"while_statement",
|
|
160
|
+
"do_statement",
|
|
161
|
+
"for_range_loop",
|
|
162
|
+
]:
|
|
163
|
+
return True
|
|
164
|
+
current = current.parent
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_loop_condition_node(ast_node, parser):
|
|
169
|
+
"""
|
|
170
|
+
Get the loop condition CFG node for a node inside a loop body.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
ast_node: AST node inside a loop body
|
|
174
|
+
parser: Parser with index
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Tuple (is_in_loop_body, loop_condition_id):
|
|
178
|
+
- is_in_loop_body: True if node is inside a loop body
|
|
179
|
+
- loop_condition_id: CFG node ID of the loop condition, or None
|
|
180
|
+
"""
|
|
181
|
+
if ast_node is None:
|
|
182
|
+
return False, None
|
|
183
|
+
|
|
184
|
+
current = ast_node
|
|
185
|
+
while current.parent is not None:
|
|
186
|
+
parent_type = current.parent.type
|
|
187
|
+
|
|
188
|
+
if parent_type in [
|
|
189
|
+
"for_statement",
|
|
190
|
+
"while_statement",
|
|
191
|
+
"do_statement",
|
|
192
|
+
"for_range_loop",
|
|
193
|
+
]:
|
|
194
|
+
loop_condition_id = get_index(current.parent, parser.index)
|
|
195
|
+
return True, loop_condition_id
|
|
196
|
+
|
|
197
|
+
current = current.parent
|
|
198
|
+
|
|
199
|
+
return False, None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def get_variable_type(parser, node):
|
|
203
|
+
"""
|
|
204
|
+
Get the type of a variable from parser's symbol table.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
parser: C++ parser with symbol table
|
|
208
|
+
node: AST node representing the variable
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
String representing the type, or None if not found
|
|
212
|
+
"""
|
|
213
|
+
var_index = get_index(node, parser.index)
|
|
214
|
+
if var_index is None:
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
if var_index in parser.declaration_map:
|
|
218
|
+
decl_index = parser.declaration_map[var_index]
|
|
219
|
+
if decl_index in parser.symbol_table.get("data_type", {}):
|
|
220
|
+
return parser.symbol_table["data_type"][decl_index]
|
|
221
|
+
|
|
222
|
+
if var_index in parser.symbol_table.get("data_type", {}):
|
|
223
|
+
return parser.symbol_table["data_type"][var_index]
|
|
224
|
+
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def is_primitive_type(type_string):
|
|
229
|
+
"""
|
|
230
|
+
Check if a type string represents a C++ primitive type.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
type_string: String representing the type
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
True if primitive, False otherwise
|
|
237
|
+
"""
|
|
238
|
+
if type_string is None:
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
primitive_types = {
|
|
242
|
+
"int",
|
|
243
|
+
"short",
|
|
244
|
+
"long",
|
|
245
|
+
"char",
|
|
246
|
+
"wchar_t",
|
|
247
|
+
"char8_t",
|
|
248
|
+
"char16_t",
|
|
249
|
+
"char32_t",
|
|
250
|
+
"signed",
|
|
251
|
+
"unsigned",
|
|
252
|
+
"int8_t",
|
|
253
|
+
"int16_t",
|
|
254
|
+
"int32_t",
|
|
255
|
+
"int64_t",
|
|
256
|
+
"uint8_t",
|
|
257
|
+
"uint16_t",
|
|
258
|
+
"uint32_t",
|
|
259
|
+
"uint64_t",
|
|
260
|
+
"int_fast8_t",
|
|
261
|
+
"int_fast16_t",
|
|
262
|
+
"int_fast32_t",
|
|
263
|
+
"int_fast64_t",
|
|
264
|
+
"uint_fast8_t",
|
|
265
|
+
"uint_fast16_t",
|
|
266
|
+
"uint_fast32_t",
|
|
267
|
+
"uint_fast64_t",
|
|
268
|
+
"int_least8_t",
|
|
269
|
+
"int_least16_t",
|
|
270
|
+
"int_least32_t",
|
|
271
|
+
"int_least64_t",
|
|
272
|
+
"uint_least8_t",
|
|
273
|
+
"uint_least16_t",
|
|
274
|
+
"uint_least32_t",
|
|
275
|
+
"uint_least64_t",
|
|
276
|
+
"intmax_t",
|
|
277
|
+
"uintmax_t",
|
|
278
|
+
"intptr_t",
|
|
279
|
+
"uintptr_t",
|
|
280
|
+
"size_t",
|
|
281
|
+
"ssize_t",
|
|
282
|
+
"ptrdiff_t",
|
|
283
|
+
"float",
|
|
284
|
+
"double",
|
|
285
|
+
"bool",
|
|
286
|
+
"void",
|
|
287
|
+
"DWORD",
|
|
288
|
+
"WORD",
|
|
289
|
+
"BYTE",
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
type_clean = (
|
|
293
|
+
type_string.strip().replace("const", "").replace("volatile", "").strip()
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
if type_clean in primitive_types:
|
|
297
|
+
return True
|
|
298
|
+
|
|
299
|
+
tokens = type_clean.split()
|
|
300
|
+
if all(token in primitive_types for token in tokens):
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
for prim in primitive_types:
|
|
304
|
+
if prim in type_clean:
|
|
305
|
+
if type_clean == prim or type_clean.startswith(prim + " "):
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
return False
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def is_class_or_struct_type(parser, type_string):
|
|
312
|
+
"""
|
|
313
|
+
Check if a type string represents a class or struct type.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
parser: C++ parser with symbol table
|
|
317
|
+
type_string: String representing the type
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
True if class/struct, False otherwise
|
|
321
|
+
"""
|
|
322
|
+
if type_string is None:
|
|
323
|
+
return False
|
|
324
|
+
|
|
325
|
+
if not is_primitive_type(type_string):
|
|
326
|
+
if hasattr(parser, "records") and type_string in parser.records:
|
|
327
|
+
return True
|
|
328
|
+
|
|
329
|
+
if "std::" in type_string or "::" in type_string:
|
|
330
|
+
return True
|
|
331
|
+
|
|
332
|
+
return True
|
|
333
|
+
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def recursively_get_children_of_types(
|
|
338
|
+
node, st_types, check_list=None, index=None, result=None, stop_types=None
|
|
339
|
+
):
|
|
340
|
+
"""Recursively find child nodes of given types"""
|
|
341
|
+
if isinstance(st_types, str):
|
|
342
|
+
st_types = [st_types]
|
|
343
|
+
if stop_types is None:
|
|
344
|
+
stop_types = []
|
|
345
|
+
if result is None:
|
|
346
|
+
result = []
|
|
347
|
+
|
|
348
|
+
if node.type in stop_types:
|
|
349
|
+
return result
|
|
350
|
+
|
|
351
|
+
if check_list and index:
|
|
352
|
+
result.extend(
|
|
353
|
+
[
|
|
354
|
+
child
|
|
355
|
+
for child in node.children
|
|
356
|
+
if child.type in st_types and get_index(child, index) in check_list
|
|
357
|
+
]
|
|
358
|
+
)
|
|
359
|
+
else:
|
|
360
|
+
result.extend([child for child in node.children if child.type in st_types])
|
|
361
|
+
|
|
362
|
+
for child in node.named_children:
|
|
363
|
+
if child.type not in stop_types:
|
|
364
|
+
if (
|
|
365
|
+
"qualified_identifier" in st_types
|
|
366
|
+
and child.type == "qualified_identifier"
|
|
367
|
+
):
|
|
368
|
+
continue
|
|
369
|
+
result = recursively_get_children_of_types(
|
|
370
|
+
child,
|
|
371
|
+
st_types,
|
|
372
|
+
result=result,
|
|
373
|
+
stop_types=stop_types,
|
|
374
|
+
index=index,
|
|
375
|
+
check_list=check_list,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return result
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class Identifier:
|
|
382
|
+
"""Represents a variable at a specific line with scope information"""
|
|
383
|
+
|
|
384
|
+
def __init__(
|
|
385
|
+
self,
|
|
386
|
+
parser,
|
|
387
|
+
node,
|
|
388
|
+
line=None,
|
|
389
|
+
declaration=False,
|
|
390
|
+
full_ref=None,
|
|
391
|
+
method_call=False,
|
|
392
|
+
has_initializer=False,
|
|
393
|
+
is_pointer_modification_at_call_site=False,
|
|
394
|
+
):
|
|
395
|
+
self.core = st(node)
|
|
396
|
+
self.unresolved_name = st(full_ref) if full_ref else st(node)
|
|
397
|
+
self.base_name = self._resolve_name(node, full_ref, parser)
|
|
398
|
+
self.name = self.base_name
|
|
399
|
+
self.line = line
|
|
400
|
+
self.declaration = declaration
|
|
401
|
+
self.has_initializer = has_initializer
|
|
402
|
+
self.method_call = method_call
|
|
403
|
+
self.is_pointer_modification_at_call_site = is_pointer_modification_at_call_site
|
|
404
|
+
if method_call and node.type == "qualified_identifier":
|
|
405
|
+
self.satisfied = False
|
|
406
|
+
else:
|
|
407
|
+
self.satisfied = method_call
|
|
408
|
+
|
|
409
|
+
class_node = return_first_parent_of_types(
|
|
410
|
+
node, ["class_specifier", "struct_specifier"]
|
|
411
|
+
)
|
|
412
|
+
self.parent_class = None
|
|
413
|
+
self.is_member_access = False
|
|
414
|
+
|
|
415
|
+
if class_node is not None:
|
|
416
|
+
class_name_node = None
|
|
417
|
+
for child in class_node.children:
|
|
418
|
+
if child.type == "type_identifier":
|
|
419
|
+
class_name_node = child
|
|
420
|
+
break
|
|
421
|
+
if class_name_node:
|
|
422
|
+
self.parent_class = st(class_name_node)
|
|
423
|
+
|
|
424
|
+
parent = node.parent
|
|
425
|
+
while parent and parent != class_node:
|
|
426
|
+
if parent.type == "function_definition":
|
|
427
|
+
if full_ref is None or full_ref.type not in [
|
|
428
|
+
"field_expression",
|
|
429
|
+
"pointer_expression",
|
|
430
|
+
]:
|
|
431
|
+
self.is_member_access = True
|
|
432
|
+
break
|
|
433
|
+
parent = parent.parent
|
|
434
|
+
|
|
435
|
+
variable_index = get_index(node, parser.index)
|
|
436
|
+
|
|
437
|
+
if hasattr(node, "qualified_name"):
|
|
438
|
+
if hasattr(node, "real_node"):
|
|
439
|
+
variable_index = get_index(node.real_node, parser.index)
|
|
440
|
+
|
|
441
|
+
if variable_index is None and node.type == "qualified_identifier":
|
|
442
|
+
innermost = extract_identifier_from_declarator(node)
|
|
443
|
+
if innermost:
|
|
444
|
+
variable_index = get_index(innermost, parser.index)
|
|
445
|
+
|
|
446
|
+
if variable_index and variable_index in parser.symbol_table["scope_map"]:
|
|
447
|
+
self.variable_scope = parser.symbol_table["scope_map"][variable_index]
|
|
448
|
+
if variable_index in parser.declaration_map:
|
|
449
|
+
decl_index = parser.declaration_map[variable_index]
|
|
450
|
+
self.scope = parser.symbol_table["scope_map"].get(decl_index, [0])
|
|
451
|
+
else:
|
|
452
|
+
self.scope = [0]
|
|
453
|
+
|
|
454
|
+
if declaration:
|
|
455
|
+
self.scope = self.variable_scope
|
|
456
|
+
else:
|
|
457
|
+
if line and line in parser.symbol_table.get("scope_map", {}):
|
|
458
|
+
self.variable_scope = parser.symbol_table["scope_map"][line]
|
|
459
|
+
self.scope = self.variable_scope
|
|
460
|
+
elif line:
|
|
461
|
+
self.variable_scope = [0, 11, 12]
|
|
462
|
+
self.scope = [0]
|
|
463
|
+
else:
|
|
464
|
+
self.variable_scope = [0]
|
|
465
|
+
self.scope = [0]
|
|
466
|
+
|
|
467
|
+
if line is not None:
|
|
468
|
+
self.real_line_no = read_index(parser.index, line)[0][0]
|
|
469
|
+
|
|
470
|
+
if self.is_member_access and self.parent_class:
|
|
471
|
+
self.name = f"{self.parent_class}::{self.base_name}"
|
|
472
|
+
|
|
473
|
+
def _resolve_name(self, node, full_ref, parser):
|
|
474
|
+
"""Resolve identifier name for C++"""
|
|
475
|
+
if full_ref is None:
|
|
476
|
+
return st(node)
|
|
477
|
+
|
|
478
|
+
if full_ref.type == "field_expression":
|
|
479
|
+
argument = full_ref.child_by_field_name("argument")
|
|
480
|
+
field = full_ref.child_by_field_name("field")
|
|
481
|
+
|
|
482
|
+
if argument:
|
|
483
|
+
arg_text = st(argument)
|
|
484
|
+
field_text = st(field) if field else ""
|
|
485
|
+
return arg_text + "." + field_text
|
|
486
|
+
return st(full_ref)
|
|
487
|
+
|
|
488
|
+
if full_ref.type == "pointer_expression":
|
|
489
|
+
arg = full_ref.child_by_field_name("argument")
|
|
490
|
+
return "*" + st(arg) if arg else st(full_ref)
|
|
491
|
+
|
|
492
|
+
if full_ref.type == "subscript_expression":
|
|
493
|
+
arg = full_ref.child_by_field_name("argument")
|
|
494
|
+
return st(arg) if arg else st(full_ref)
|
|
495
|
+
|
|
496
|
+
if full_ref.type == "unary_expression":
|
|
497
|
+
for child in full_ref.children:
|
|
498
|
+
if child.type == "&":
|
|
499
|
+
arg = full_ref.child_by_field_name("argument")
|
|
500
|
+
return st(arg) if arg else st(full_ref)
|
|
501
|
+
|
|
502
|
+
if full_ref.type == "qualified_identifier":
|
|
503
|
+
qualified_text = st(full_ref)
|
|
504
|
+
if "::" in qualified_text:
|
|
505
|
+
return qualified_text.split("::")[-1]
|
|
506
|
+
return qualified_text
|
|
507
|
+
|
|
508
|
+
if st(node) == "this":
|
|
509
|
+
return "this"
|
|
510
|
+
|
|
511
|
+
return st(node)
|
|
512
|
+
|
|
513
|
+
def __eq__(self, other):
|
|
514
|
+
return (
|
|
515
|
+
self.name == other.name
|
|
516
|
+
and self.line == other.line
|
|
517
|
+
and sorted(self.scope) == sorted(other.scope)
|
|
518
|
+
and self.method_call == other.method_call
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
def __hash__(self):
|
|
522
|
+
return hash((self.name, self.line, str(self.scope), self.method_call))
|
|
523
|
+
|
|
524
|
+
def __str__(self):
|
|
525
|
+
result = [self.name]
|
|
526
|
+
if self.line:
|
|
527
|
+
result += [str(self.real_line_no)]
|
|
528
|
+
result += ["|".join(map(str, self.scope))]
|
|
529
|
+
else:
|
|
530
|
+
result += ["?"]
|
|
531
|
+
if self.method_call:
|
|
532
|
+
result += ["()"]
|
|
533
|
+
return f"{{{','.join(result)}}}"
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
class Literal:
|
|
537
|
+
"""Represents a literal constant (number, string, etc.) as a data flow source"""
|
|
538
|
+
|
|
539
|
+
def __init__(self, parser, node, line=None):
|
|
540
|
+
self.core = st(node)
|
|
541
|
+
self.name = f"LITERAL_{st(node)}"
|
|
542
|
+
self.value = st(node)
|
|
543
|
+
self.line = line
|
|
544
|
+
self.declaration = True
|
|
545
|
+
self.satisfied = False
|
|
546
|
+
self.scope = [0]
|
|
547
|
+
self.variable_scope = [0]
|
|
548
|
+
self.method_call = False
|
|
549
|
+
|
|
550
|
+
if line is not None:
|
|
551
|
+
self.real_line_no = read_index(parser.index, line)[0][0]
|
|
552
|
+
|
|
553
|
+
def __eq__(self, other):
|
|
554
|
+
return self.name == other.name and self.line == other.line
|
|
555
|
+
|
|
556
|
+
def __hash__(self):
|
|
557
|
+
return hash((self.name, self.line))
|
|
558
|
+
|
|
559
|
+
def __str__(self):
|
|
560
|
+
result = [f"Literal({self.value})"]
|
|
561
|
+
if self.line:
|
|
562
|
+
result += [str(self.real_line_no)]
|
|
563
|
+
else:
|
|
564
|
+
result += ["?"]
|
|
565
|
+
return f"{{{','.join(result)}}}"
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def get_namespace_for_node(node, parser):
|
|
569
|
+
"""
|
|
570
|
+
Get the namespace that contains this node, if any.
|
|
571
|
+
|
|
572
|
+
Returns the namespace name or None if not in a namespace.
|
|
573
|
+
"""
|
|
574
|
+
parent = node.parent
|
|
575
|
+
while parent:
|
|
576
|
+
if parent.type == "namespace_definition":
|
|
577
|
+
for child in parent.children:
|
|
578
|
+
if child.type == "namespace_identifier":
|
|
579
|
+
return st(child)
|
|
580
|
+
parent = parent.parent
|
|
581
|
+
return None
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def extract_identifier_from_declarator(declarator_node):
|
|
585
|
+
"""Extract identifier from declarator (may be wrapped in pointer/array/reference/qualified)"""
|
|
586
|
+
if declarator_node.type == "identifier":
|
|
587
|
+
return declarator_node
|
|
588
|
+
elif declarator_node.type == "qualified_identifier":
|
|
589
|
+
for child in declarator_node.children:
|
|
590
|
+
if child.type in ["identifier", "qualified_identifier"]:
|
|
591
|
+
result = extract_identifier_from_declarator(child)
|
|
592
|
+
if result:
|
|
593
|
+
return result
|
|
594
|
+
return None
|
|
595
|
+
elif declarator_node.type == "pointer_declarator":
|
|
596
|
+
for child in declarator_node.children:
|
|
597
|
+
if child.type in [
|
|
598
|
+
"identifier",
|
|
599
|
+
"pointer_declarator",
|
|
600
|
+
"array_declarator",
|
|
601
|
+
"reference_declarator",
|
|
602
|
+
"qualified_identifier",
|
|
603
|
+
]:
|
|
604
|
+
return extract_identifier_from_declarator(child)
|
|
605
|
+
elif declarator_node.type == "reference_declarator":
|
|
606
|
+
for child in declarator_node.children:
|
|
607
|
+
if child.type in [
|
|
608
|
+
"identifier",
|
|
609
|
+
"pointer_declarator",
|
|
610
|
+
"array_declarator",
|
|
611
|
+
"reference_declarator",
|
|
612
|
+
"qualified_identifier",
|
|
613
|
+
]:
|
|
614
|
+
return extract_identifier_from_declarator(child)
|
|
615
|
+
elif declarator_node.type == "array_declarator":
|
|
616
|
+
if declarator_node.children:
|
|
617
|
+
return extract_identifier_from_declarator(declarator_node.children[0])
|
|
618
|
+
elif declarator_node.type == "function_declarator":
|
|
619
|
+
for child in declarator_node.children:
|
|
620
|
+
if child.type in [
|
|
621
|
+
"identifier",
|
|
622
|
+
"pointer_declarator",
|
|
623
|
+
"parenthesized_declarator",
|
|
624
|
+
"qualified_identifier",
|
|
625
|
+
]:
|
|
626
|
+
return extract_identifier_from_declarator(child)
|
|
627
|
+
elif declarator_node.type == "parenthesized_declarator":
|
|
628
|
+
for child in declarator_node.children:
|
|
629
|
+
if child.type in [
|
|
630
|
+
"identifier",
|
|
631
|
+
"pointer_declarator",
|
|
632
|
+
"array_declarator",
|
|
633
|
+
"reference_declarator",
|
|
634
|
+
"qualified_identifier",
|
|
635
|
+
]:
|
|
636
|
+
return extract_identifier_from_declarator(child)
|
|
637
|
+
return None
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
def extract_param_identifier(param_node):
|
|
641
|
+
"""Extract identifier from parameter_declaration"""
|
|
642
|
+
for child in param_node.children:
|
|
643
|
+
if child.type == "identifier":
|
|
644
|
+
return child
|
|
645
|
+
elif child.type in [
|
|
646
|
+
"pointer_declarator",
|
|
647
|
+
"array_declarator",
|
|
648
|
+
"function_declarator",
|
|
649
|
+
"reference_declarator",
|
|
650
|
+
]:
|
|
651
|
+
return extract_identifier_from_declarator(child)
|
|
652
|
+
return None
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def is_reference_variable(parser, node):
|
|
656
|
+
if node is None or node.type not in ["identifier"]:
|
|
657
|
+
return False
|
|
658
|
+
|
|
659
|
+
var_index = get_index(node, parser.index)
|
|
660
|
+
if var_index is None:
|
|
661
|
+
return False
|
|
662
|
+
|
|
663
|
+
if var_index not in parser.declaration_map:
|
|
664
|
+
return False
|
|
665
|
+
|
|
666
|
+
decl_index = parser.declaration_map[var_index]
|
|
667
|
+
|
|
668
|
+
def find_node_by_index(root, target_index):
|
|
669
|
+
stack = [root]
|
|
670
|
+
while stack:
|
|
671
|
+
current = stack.pop()
|
|
672
|
+
node_idx = get_index(current, parser.index)
|
|
673
|
+
if node_idx == target_index:
|
|
674
|
+
return current
|
|
675
|
+
for child in current.children:
|
|
676
|
+
stack.append(child)
|
|
677
|
+
return None
|
|
678
|
+
|
|
679
|
+
decl_node = find_node_by_index(parser.tree.root_node, decl_index)
|
|
680
|
+
|
|
681
|
+
if decl_node:
|
|
682
|
+
parent = decl_node.parent
|
|
683
|
+
depth = 0
|
|
684
|
+
while parent and depth < 5:
|
|
685
|
+
if parent.type == "reference_declarator":
|
|
686
|
+
return True
|
|
687
|
+
if parent.type in [
|
|
688
|
+
"parameter_declaration",
|
|
689
|
+
"declaration",
|
|
690
|
+
"function_definition",
|
|
691
|
+
"translation_unit",
|
|
692
|
+
]:
|
|
693
|
+
break
|
|
694
|
+
depth += 1
|
|
695
|
+
parent = parent.parent
|
|
696
|
+
|
|
697
|
+
return False
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
def extract_operator_text(assign_node, left_node, right_node):
|
|
701
|
+
left_text = left_node.text
|
|
702
|
+
right_text = right_node.text
|
|
703
|
+
operator_bytes = (
|
|
704
|
+
assign_node.text.split(left_text, 1)[-1].rsplit(right_text, 1)[0].strip()
|
|
705
|
+
)
|
|
706
|
+
return operator_bytes.decode()
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def add_entry(
|
|
710
|
+
parser,
|
|
711
|
+
rda_table,
|
|
712
|
+
statement_id,
|
|
713
|
+
used=None,
|
|
714
|
+
defined=None,
|
|
715
|
+
declaration=False,
|
|
716
|
+
core=None,
|
|
717
|
+
method_call=False,
|
|
718
|
+
has_initializer=False,
|
|
719
|
+
is_pointer_modification_at_call_site=False,
|
|
720
|
+
):
|
|
721
|
+
if statement_id not in rda_table:
|
|
722
|
+
rda_table[statement_id] = defaultdict(list)
|
|
723
|
+
|
|
724
|
+
if not used and not defined:
|
|
725
|
+
return
|
|
726
|
+
|
|
727
|
+
current_node = used or defined
|
|
728
|
+
if core is None:
|
|
729
|
+
core = current_node
|
|
730
|
+
|
|
731
|
+
if current_node.type in literal_types:
|
|
732
|
+
if used:
|
|
733
|
+
set_add(
|
|
734
|
+
rda_table[statement_id]["use"],
|
|
735
|
+
Literal(parser, current_node, statement_id),
|
|
736
|
+
)
|
|
737
|
+
return
|
|
738
|
+
|
|
739
|
+
if hasattr(current_node, "qualified_name"):
|
|
740
|
+
if defined is not None:
|
|
741
|
+
identifier = Identifier(
|
|
742
|
+
parser,
|
|
743
|
+
current_node,
|
|
744
|
+
statement_id,
|
|
745
|
+
full_ref=current_node,
|
|
746
|
+
declaration=declaration,
|
|
747
|
+
method_call=method_call,
|
|
748
|
+
has_initializer=has_initializer,
|
|
749
|
+
)
|
|
750
|
+
identifier.name = current_node.qualified_name
|
|
751
|
+
set_add(rda_table[statement_id]["def"], identifier)
|
|
752
|
+
return
|
|
753
|
+
|
|
754
|
+
if current_node.type == "field_expression":
|
|
755
|
+
argument = current_node.child_by_field_name("argument")
|
|
756
|
+
|
|
757
|
+
is_method_call = (
|
|
758
|
+
current_node.parent and current_node.parent.type == "call_expression"
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
if is_method_call:
|
|
762
|
+
if defined is not None:
|
|
763
|
+
set_add(
|
|
764
|
+
rda_table[statement_id]["def"],
|
|
765
|
+
Identifier(
|
|
766
|
+
parser,
|
|
767
|
+
argument,
|
|
768
|
+
statement_id,
|
|
769
|
+
full_ref=current_node,
|
|
770
|
+
declaration=declaration,
|
|
771
|
+
method_call=True,
|
|
772
|
+
has_initializer=has_initializer,
|
|
773
|
+
),
|
|
774
|
+
)
|
|
775
|
+
else:
|
|
776
|
+
set_add(
|
|
777
|
+
rda_table[statement_id]["use"],
|
|
778
|
+
Identifier(
|
|
779
|
+
parser, argument, full_ref=current_node, method_call=True
|
|
780
|
+
),
|
|
781
|
+
)
|
|
782
|
+
return
|
|
783
|
+
|
|
784
|
+
if defined is not None:
|
|
785
|
+
if argument:
|
|
786
|
+
set_add(
|
|
787
|
+
rda_table[statement_id]["def"],
|
|
788
|
+
Identifier(
|
|
789
|
+
parser,
|
|
790
|
+
argument,
|
|
791
|
+
statement_id,
|
|
792
|
+
full_ref=None,
|
|
793
|
+
declaration=declaration,
|
|
794
|
+
method_call=method_call,
|
|
795
|
+
has_initializer=has_initializer,
|
|
796
|
+
),
|
|
797
|
+
)
|
|
798
|
+
else:
|
|
799
|
+
if argument:
|
|
800
|
+
set_add(
|
|
801
|
+
rda_table[statement_id]["use"],
|
|
802
|
+
Identifier(
|
|
803
|
+
parser, argument, full_ref=None, method_call=method_call
|
|
804
|
+
),
|
|
805
|
+
)
|
|
806
|
+
return
|
|
807
|
+
|
|
808
|
+
if used and used.type == "unary_expression":
|
|
809
|
+
operator = None
|
|
810
|
+
argument = None
|
|
811
|
+
for child in used.children:
|
|
812
|
+
if child.type == "&":
|
|
813
|
+
operator = child
|
|
814
|
+
elif child.is_named:
|
|
815
|
+
argument = child
|
|
816
|
+
|
|
817
|
+
if operator is not None and argument is not None:
|
|
818
|
+
if argument.type in variable_type:
|
|
819
|
+
arg_index = get_index(argument, parser.index)
|
|
820
|
+
if arg_index and arg_index in parser.symbol_table["scope_map"]:
|
|
821
|
+
set_add(
|
|
822
|
+
rda_table[statement_id]["use"],
|
|
823
|
+
Identifier(parser, argument, full_ref=argument),
|
|
824
|
+
)
|
|
825
|
+
elif arg_index and arg_index in parser.method_map:
|
|
826
|
+
set_add(
|
|
827
|
+
rda_table[statement_id]["use"],
|
|
828
|
+
Identifier(parser, argument, full_ref=argument),
|
|
829
|
+
)
|
|
830
|
+
return
|
|
831
|
+
|
|
832
|
+
if current_node.type == "pointer_expression":
|
|
833
|
+
is_address_of = False
|
|
834
|
+
is_dereference = False
|
|
835
|
+
|
|
836
|
+
if current_node.children:
|
|
837
|
+
operator = current_node.children[0]
|
|
838
|
+
if operator.type == "&":
|
|
839
|
+
is_address_of = True
|
|
840
|
+
elif operator.type == "*":
|
|
841
|
+
is_dereference = True
|
|
842
|
+
|
|
843
|
+
pointer = current_node.child_by_field_name("argument")
|
|
844
|
+
|
|
845
|
+
if is_address_of:
|
|
846
|
+
if pointer and pointer.type in variable_type:
|
|
847
|
+
pointer_index = get_index(pointer, parser.index)
|
|
848
|
+
if pointer_index and pointer_index in parser.symbol_table["scope_map"]:
|
|
849
|
+
set_add(
|
|
850
|
+
rda_table[statement_id]["use"],
|
|
851
|
+
Identifier(parser, pointer, full_ref=pointer),
|
|
852
|
+
)
|
|
853
|
+
return
|
|
854
|
+
|
|
855
|
+
elif is_dereference:
|
|
856
|
+
if defined is not None:
|
|
857
|
+
pointer_index = get_index(pointer, parser.index)
|
|
858
|
+
if pointer_index and pointer_index in parser.symbol_table["scope_map"]:
|
|
859
|
+
set_add(
|
|
860
|
+
rda_table[statement_id]["use"],
|
|
861
|
+
Identifier(parser, pointer, full_ref=pointer),
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
set_add(
|
|
865
|
+
rda_table[statement_id]["def"],
|
|
866
|
+
Identifier(
|
|
867
|
+
parser,
|
|
868
|
+
pointer,
|
|
869
|
+
statement_id,
|
|
870
|
+
full_ref=core,
|
|
871
|
+
declaration=declaration,
|
|
872
|
+
has_initializer=has_initializer,
|
|
873
|
+
),
|
|
874
|
+
)
|
|
875
|
+
else:
|
|
876
|
+
set_add(
|
|
877
|
+
rda_table[statement_id]["use"],
|
|
878
|
+
Identifier(parser, pointer, full_ref=core),
|
|
879
|
+
)
|
|
880
|
+
return
|
|
881
|
+
|
|
882
|
+
if current_node.type == "subscript_expression":
|
|
883
|
+
array = current_node.child_by_field_name("argument")
|
|
884
|
+
index_expr = current_node.child_by_field_name("index")
|
|
885
|
+
|
|
886
|
+
if index_expr is None:
|
|
887
|
+
for child in current_node.children:
|
|
888
|
+
if child.type == "subscript_argument_list":
|
|
889
|
+
if child.named_children:
|
|
890
|
+
index_expr = child.named_children[0]
|
|
891
|
+
break
|
|
892
|
+
|
|
893
|
+
if defined is not None:
|
|
894
|
+
set_add(
|
|
895
|
+
rda_table[statement_id]["def"],
|
|
896
|
+
Identifier(
|
|
897
|
+
parser,
|
|
898
|
+
array,
|
|
899
|
+
statement_id,
|
|
900
|
+
full_ref=core,
|
|
901
|
+
declaration=declaration,
|
|
902
|
+
has_initializer=has_initializer,
|
|
903
|
+
),
|
|
904
|
+
)
|
|
905
|
+
set_add(
|
|
906
|
+
rda_table[statement_id]["use"], Identifier(parser, array, full_ref=core)
|
|
907
|
+
)
|
|
908
|
+
|
|
909
|
+
if index_expr:
|
|
910
|
+
if index_expr.type in variable_type:
|
|
911
|
+
index_id = get_index(index_expr, parser.index)
|
|
912
|
+
if index_id and index_id in parser.symbol_table["scope_map"]:
|
|
913
|
+
set_add(
|
|
914
|
+
rda_table[statement_id]["use"],
|
|
915
|
+
Identifier(parser, index_expr, full_ref=index_expr),
|
|
916
|
+
)
|
|
917
|
+
elif index_expr.type in literal_types:
|
|
918
|
+
set_add(
|
|
919
|
+
rda_table[statement_id]["use"],
|
|
920
|
+
Literal(parser, index_expr, statement_id),
|
|
921
|
+
)
|
|
922
|
+
else:
|
|
923
|
+
identifiers_in_index = recursively_get_children_of_types(
|
|
924
|
+
index_expr,
|
|
925
|
+
variable_type + ["field_expression"],
|
|
926
|
+
index=parser.index,
|
|
927
|
+
check_list=parser.symbol_table["scope_map"],
|
|
928
|
+
)
|
|
929
|
+
for identifier in identifiers_in_index:
|
|
930
|
+
set_add(
|
|
931
|
+
rda_table[statement_id]["use"],
|
|
932
|
+
Identifier(parser, identifier, full_ref=identifier),
|
|
933
|
+
)
|
|
934
|
+
literals_in_index = recursively_get_children_of_types(
|
|
935
|
+
index_expr, literal_types, index=parser.index
|
|
936
|
+
)
|
|
937
|
+
for literal in literals_in_index:
|
|
938
|
+
set_add(
|
|
939
|
+
rda_table[statement_id]["use"],
|
|
940
|
+
Literal(parser, literal, statement_id),
|
|
941
|
+
)
|
|
942
|
+
return
|
|
943
|
+
|
|
944
|
+
if current_node.type == "qualified_identifier":
|
|
945
|
+
innermost_id = extract_identifier_from_declarator(current_node)
|
|
946
|
+
|
|
947
|
+
if method_call:
|
|
948
|
+
if defined is not None:
|
|
949
|
+
set_add(
|
|
950
|
+
rda_table[statement_id]["def"],
|
|
951
|
+
Identifier(
|
|
952
|
+
parser,
|
|
953
|
+
current_node,
|
|
954
|
+
statement_id,
|
|
955
|
+
full_ref=current_node,
|
|
956
|
+
declaration=declaration,
|
|
957
|
+
method_call=method_call,
|
|
958
|
+
has_initializer=has_initializer,
|
|
959
|
+
),
|
|
960
|
+
)
|
|
961
|
+
else:
|
|
962
|
+
set_add(
|
|
963
|
+
rda_table[statement_id]["use"],
|
|
964
|
+
Identifier(
|
|
965
|
+
parser,
|
|
966
|
+
current_node,
|
|
967
|
+
statement_id,
|
|
968
|
+
full_ref=current_node,
|
|
969
|
+
method_call=method_call,
|
|
970
|
+
),
|
|
971
|
+
)
|
|
972
|
+
return
|
|
973
|
+
|
|
974
|
+
if innermost_id is None:
|
|
975
|
+
return
|
|
976
|
+
|
|
977
|
+
node_index = get_index(innermost_id, parser.index)
|
|
978
|
+
if node_index is None or node_index not in parser.symbol_table["scope_map"]:
|
|
979
|
+
if defined is not None:
|
|
980
|
+
set_add(
|
|
981
|
+
rda_table[statement_id]["def"],
|
|
982
|
+
Identifier(
|
|
983
|
+
parser,
|
|
984
|
+
current_node,
|
|
985
|
+
statement_id,
|
|
986
|
+
full_ref=current_node,
|
|
987
|
+
declaration=declaration,
|
|
988
|
+
method_call=method_call,
|
|
989
|
+
has_initializer=has_initializer,
|
|
990
|
+
),
|
|
991
|
+
)
|
|
992
|
+
else:
|
|
993
|
+
set_add(
|
|
994
|
+
rda_table[statement_id]["use"],
|
|
995
|
+
Identifier(
|
|
996
|
+
parser,
|
|
997
|
+
current_node,
|
|
998
|
+
statement_id,
|
|
999
|
+
full_ref=current_node,
|
|
1000
|
+
method_call=method_call,
|
|
1001
|
+
),
|
|
1002
|
+
)
|
|
1003
|
+
return
|
|
1004
|
+
|
|
1005
|
+
if defined is not None:
|
|
1006
|
+
set_add(
|
|
1007
|
+
rda_table[statement_id]["def"],
|
|
1008
|
+
Identifier(
|
|
1009
|
+
parser,
|
|
1010
|
+
innermost_id,
|
|
1011
|
+
statement_id,
|
|
1012
|
+
full_ref=current_node,
|
|
1013
|
+
declaration=declaration,
|
|
1014
|
+
method_call=method_call,
|
|
1015
|
+
has_initializer=has_initializer,
|
|
1016
|
+
),
|
|
1017
|
+
)
|
|
1018
|
+
else:
|
|
1019
|
+
set_add(
|
|
1020
|
+
rda_table[statement_id]["use"],
|
|
1021
|
+
Identifier(
|
|
1022
|
+
parser, innermost_id, full_ref=current_node, method_call=method_call
|
|
1023
|
+
),
|
|
1024
|
+
)
|
|
1025
|
+
return
|
|
1026
|
+
|
|
1027
|
+
if current_node.type == "this":
|
|
1028
|
+
if used:
|
|
1029
|
+
set_add(
|
|
1030
|
+
rda_table[statement_id]["use"],
|
|
1031
|
+
Identifier(parser, current_node, full_ref=current_node),
|
|
1032
|
+
)
|
|
1033
|
+
return
|
|
1034
|
+
|
|
1035
|
+
node_index = get_index(current_node, parser.index)
|
|
1036
|
+
if node_index is None or node_index not in parser.symbol_table["scope_map"]:
|
|
1037
|
+
if defined is not None:
|
|
1038
|
+
set_add(
|
|
1039
|
+
rda_table[statement_id]["def"],
|
|
1040
|
+
Identifier(
|
|
1041
|
+
parser,
|
|
1042
|
+
defined,
|
|
1043
|
+
statement_id,
|
|
1044
|
+
full_ref=core,
|
|
1045
|
+
declaration=declaration,
|
|
1046
|
+
method_call=method_call,
|
|
1047
|
+
has_initializer=has_initializer,
|
|
1048
|
+
),
|
|
1049
|
+
)
|
|
1050
|
+
else:
|
|
1051
|
+
set_add(
|
|
1052
|
+
rda_table[statement_id]["use"],
|
|
1053
|
+
Identifier(
|
|
1054
|
+
parser, used, statement_id, full_ref=core, method_call=method_call
|
|
1055
|
+
),
|
|
1056
|
+
)
|
|
1057
|
+
return
|
|
1058
|
+
|
|
1059
|
+
if defined is not None:
|
|
1060
|
+
set_add(
|
|
1061
|
+
rda_table[statement_id]["def"],
|
|
1062
|
+
Identifier(
|
|
1063
|
+
parser,
|
|
1064
|
+
defined,
|
|
1065
|
+
statement_id,
|
|
1066
|
+
full_ref=core,
|
|
1067
|
+
declaration=declaration,
|
|
1068
|
+
method_call=method_call,
|
|
1069
|
+
has_initializer=has_initializer,
|
|
1070
|
+
is_pointer_modification_at_call_site=is_pointer_modification_at_call_site,
|
|
1071
|
+
),
|
|
1072
|
+
)
|
|
1073
|
+
else:
|
|
1074
|
+
set_add(
|
|
1075
|
+
rda_table[statement_id]["use"],
|
|
1076
|
+
Identifier(
|
|
1077
|
+
parser, used, statement_id, full_ref=core, method_call=method_call
|
|
1078
|
+
),
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
def discover_lambdas(parser, CFG_results):
|
|
1083
|
+
lambda_map = {}
|
|
1084
|
+
index = parser.index
|
|
1085
|
+
tree = parser.tree
|
|
1086
|
+
cfg_nodes = CFG_results.graph.nodes
|
|
1087
|
+
|
|
1088
|
+
for node in traverse_tree(tree, ["lambda_expression"]):
|
|
1089
|
+
if node.type != "lambda_expression":
|
|
1090
|
+
continue
|
|
1091
|
+
|
|
1092
|
+
parent = node.parent
|
|
1093
|
+
variable_name = None
|
|
1094
|
+
definition_node_id = None
|
|
1095
|
+
|
|
1096
|
+
if parent and parent.type == "init_declarator":
|
|
1097
|
+
declarator = parent.child_by_field_name("declarator")
|
|
1098
|
+
if declarator and declarator.type == "identifier":
|
|
1099
|
+
variable_name = st(declarator)
|
|
1100
|
+
|
|
1101
|
+
statement = parent.parent
|
|
1102
|
+
if statement:
|
|
1103
|
+
definition_node_id = get_index(statement, index)
|
|
1104
|
+
|
|
1105
|
+
if not variable_name or not definition_node_id:
|
|
1106
|
+
continue
|
|
1107
|
+
|
|
1108
|
+
body_nodes = []
|
|
1109
|
+
for child in node.children:
|
|
1110
|
+
if child.type == "compound_statement":
|
|
1111
|
+
for stmt in child.named_children:
|
|
1112
|
+
stmt_id = get_index(stmt, index)
|
|
1113
|
+
if stmt_id and stmt_id in cfg_nodes:
|
|
1114
|
+
body_nodes.append(stmt_id)
|
|
1115
|
+
break
|
|
1116
|
+
|
|
1117
|
+
captures = []
|
|
1118
|
+
for child in node.children:
|
|
1119
|
+
if child.type == "lambda_capture_specifier":
|
|
1120
|
+
for capture in child.named_children:
|
|
1121
|
+
if capture.type in variable_type:
|
|
1122
|
+
captures.append(st(capture))
|
|
1123
|
+
break
|
|
1124
|
+
|
|
1125
|
+
lambda_node_id = get_index(node, index)
|
|
1126
|
+
|
|
1127
|
+
lambda_map[variable_name] = {
|
|
1128
|
+
"definition_node": definition_node_id,
|
|
1129
|
+
"lambda_node": lambda_node_id,
|
|
1130
|
+
"body_nodes": body_nodes,
|
|
1131
|
+
"captures": captures,
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if debug:
|
|
1135
|
+
logger.info(
|
|
1136
|
+
f"Discovered lambda: {variable_name} at node {definition_node_id}, "
|
|
1137
|
+
f"body nodes: {body_nodes}, captures: {captures}"
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
return lambda_map
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
def is_return_value_used(call_expr_statement):
|
|
1144
|
+
if call_expr_statement.type == "declaration":
|
|
1145
|
+
for child in call_expr_statement.children:
|
|
1146
|
+
if child.type == "init_declarator":
|
|
1147
|
+
return True
|
|
1148
|
+
return False
|
|
1149
|
+
|
|
1150
|
+
if call_expr_statement.type == "expression_statement":
|
|
1151
|
+
if len(call_expr_statement.named_children) == 1:
|
|
1152
|
+
child = call_expr_statement.named_children[0]
|
|
1153
|
+
if child.type == "call_expression":
|
|
1154
|
+
return False
|
|
1155
|
+
|
|
1156
|
+
parent = call_expr_statement.parent
|
|
1157
|
+
while parent:
|
|
1158
|
+
parent_type = parent.type
|
|
1159
|
+
|
|
1160
|
+
if parent_type in ["init_declarator", "assignment_expression"]:
|
|
1161
|
+
return True
|
|
1162
|
+
|
|
1163
|
+
if parent_type == "return_statement":
|
|
1164
|
+
return True
|
|
1165
|
+
|
|
1166
|
+
if parent_type == "argument_list":
|
|
1167
|
+
return True
|
|
1168
|
+
|
|
1169
|
+
if parent_type in [
|
|
1170
|
+
"if_statement",
|
|
1171
|
+
"while_statement",
|
|
1172
|
+
"for_statement",
|
|
1173
|
+
"do_statement",
|
|
1174
|
+
"switch_statement",
|
|
1175
|
+
]:
|
|
1176
|
+
return True
|
|
1177
|
+
|
|
1178
|
+
if parent_type == "expression_statement":
|
|
1179
|
+
return False
|
|
1180
|
+
|
|
1181
|
+
parent = parent.parent
|
|
1182
|
+
|
|
1183
|
+
return False
|
|
1184
|
+
|
|
1185
|
+
|
|
1186
|
+
def collect_function_metadata(parser):
|
|
1187
|
+
"""
|
|
1188
|
+
Collect metadata about function definitions.
|
|
1189
|
+
|
|
1190
|
+
Returns two dicts:
|
|
1191
|
+
- metadata_by_name: simple_name -> metadata (may overwrite for same-named functions)
|
|
1192
|
+
- metadata_by_id: func_def_id -> metadata (unique per function)
|
|
1193
|
+
|
|
1194
|
+
Each metadata entry contains:
|
|
1195
|
+
- "params": list of (param_name, is_pointer, is_reference, param_idx)
|
|
1196
|
+
- "node": the function_definition AST node
|
|
1197
|
+
- "func_name": the simple function name
|
|
1198
|
+
|
|
1199
|
+
Note: metadata_by_name is kept for backward compatibility but may lose information
|
|
1200
|
+
when multiple functions have the same name. Use metadata_by_id for precise lookup.
|
|
1201
|
+
"""
|
|
1202
|
+
metadata_by_name = {}
|
|
1203
|
+
metadata_by_id = {}
|
|
1204
|
+
index = parser.index
|
|
1205
|
+
|
|
1206
|
+
for node in traverse_tree(parser.tree.root_node):
|
|
1207
|
+
if node.type == "function_definition":
|
|
1208
|
+
func_name = None
|
|
1209
|
+
params = []
|
|
1210
|
+
|
|
1211
|
+
for child in node.named_children:
|
|
1212
|
+
if child.type == "function_declarator":
|
|
1213
|
+
declarator = child.child_by_field_name("declarator")
|
|
1214
|
+
if declarator:
|
|
1215
|
+
if declarator.type in ["identifier", "field_identifier"]:
|
|
1216
|
+
func_name = st(declarator)
|
|
1217
|
+
elif declarator.type in [
|
|
1218
|
+
"pointer_declarator",
|
|
1219
|
+
"reference_declarator",
|
|
1220
|
+
]:
|
|
1221
|
+
inner = declarator
|
|
1222
|
+
while inner and inner.type in [
|
|
1223
|
+
"pointer_declarator",
|
|
1224
|
+
"reference_declarator",
|
|
1225
|
+
]:
|
|
1226
|
+
inner_declarator = inner.child_by_field_name(
|
|
1227
|
+
"declarator"
|
|
1228
|
+
)
|
|
1229
|
+
if inner_declarator:
|
|
1230
|
+
inner = inner_declarator
|
|
1231
|
+
else:
|
|
1232
|
+
break
|
|
1233
|
+
if inner and inner.type == "identifier":
|
|
1234
|
+
func_name = st(inner)
|
|
1235
|
+
elif declarator.type == "qualified_identifier":
|
|
1236
|
+
name_node = declarator.child_by_field_name("name")
|
|
1237
|
+
if name_node:
|
|
1238
|
+
func_name = st(name_node)
|
|
1239
|
+
|
|
1240
|
+
param_list = child.child_by_field_name("parameters")
|
|
1241
|
+
if param_list:
|
|
1242
|
+
param_idx = 0
|
|
1243
|
+
for param in param_list.named_children:
|
|
1244
|
+
if param.type == "parameter_declaration":
|
|
1245
|
+
param_name = None
|
|
1246
|
+
is_pointer = False
|
|
1247
|
+
is_reference = False
|
|
1248
|
+
|
|
1249
|
+
for p_child in param.named_children:
|
|
1250
|
+
if p_child.type in [
|
|
1251
|
+
"pointer_declarator",
|
|
1252
|
+
"reference_declarator",
|
|
1253
|
+
]:
|
|
1254
|
+
if p_child.type == "pointer_declarator":
|
|
1255
|
+
is_pointer = True
|
|
1256
|
+
else:
|
|
1257
|
+
is_reference = True
|
|
1258
|
+
inner = p_child
|
|
1259
|
+
while inner:
|
|
1260
|
+
if inner.type == "identifier":
|
|
1261
|
+
param_name = st(inner)
|
|
1262
|
+
break
|
|
1263
|
+
elif inner.type in [
|
|
1264
|
+
"pointer_declarator",
|
|
1265
|
+
"reference_declarator",
|
|
1266
|
+
]:
|
|
1267
|
+
inner_decl = inner.child_by_field_name(
|
|
1268
|
+
"declarator"
|
|
1269
|
+
)
|
|
1270
|
+
if inner_decl:
|
|
1271
|
+
inner = inner_decl
|
|
1272
|
+
else:
|
|
1273
|
+
if inner.named_children:
|
|
1274
|
+
for (
|
|
1275
|
+
child
|
|
1276
|
+
) in inner.named_children:
|
|
1277
|
+
if (
|
|
1278
|
+
child.type
|
|
1279
|
+
== "identifier"
|
|
1280
|
+
):
|
|
1281
|
+
param_name = st(child)
|
|
1282
|
+
break
|
|
1283
|
+
break
|
|
1284
|
+
else:
|
|
1285
|
+
break
|
|
1286
|
+
elif p_child.type == "identifier":
|
|
1287
|
+
if param_name is None:
|
|
1288
|
+
param_name = st(p_child)
|
|
1289
|
+
|
|
1290
|
+
if param_name:
|
|
1291
|
+
params.append(
|
|
1292
|
+
(
|
|
1293
|
+
param_name,
|
|
1294
|
+
is_pointer,
|
|
1295
|
+
is_reference,
|
|
1296
|
+
param_idx,
|
|
1297
|
+
)
|
|
1298
|
+
)
|
|
1299
|
+
param_idx += 1
|
|
1300
|
+
break
|
|
1301
|
+
|
|
1302
|
+
if func_name:
|
|
1303
|
+
func_def_id = get_index(node, index)
|
|
1304
|
+
meta = {"params": params, "node": node, "func_name": func_name}
|
|
1305
|
+
metadata_by_name[func_name] = meta
|
|
1306
|
+
if func_def_id is not None:
|
|
1307
|
+
metadata_by_id[func_def_id] = meta
|
|
1308
|
+
|
|
1309
|
+
return metadata_by_name, metadata_by_id
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
def analyze_pointer_modifications(parser, function_metadata):
|
|
1313
|
+
modifications = {}
|
|
1314
|
+
|
|
1315
|
+
for func_name, meta in function_metadata.items():
|
|
1316
|
+
modified_params = set()
|
|
1317
|
+
func_node = meta["node"]
|
|
1318
|
+
|
|
1319
|
+
param_name_to_idx = {}
|
|
1320
|
+
for param_name, is_pointer, is_reference, param_idx in meta["params"]:
|
|
1321
|
+
if is_pointer or is_reference:
|
|
1322
|
+
param_name_to_idx[param_name] = param_idx
|
|
1323
|
+
|
|
1324
|
+
if not param_name_to_idx:
|
|
1325
|
+
modifications[func_name] = modified_params
|
|
1326
|
+
continue
|
|
1327
|
+
|
|
1328
|
+
for node in traverse_tree(func_node):
|
|
1329
|
+
if node.type == "assignment_expression":
|
|
1330
|
+
left = node.child_by_field_name("left")
|
|
1331
|
+
if left:
|
|
1332
|
+
if left.type == "pointer_expression":
|
|
1333
|
+
arg = left.child_by_field_name("argument")
|
|
1334
|
+
if arg and arg.type == "identifier":
|
|
1335
|
+
var_name = st(arg)
|
|
1336
|
+
if var_name in param_name_to_idx:
|
|
1337
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1338
|
+
|
|
1339
|
+
elif left.type == "subscript_expression":
|
|
1340
|
+
array_arg = left.child_by_field_name("argument")
|
|
1341
|
+
if array_arg and array_arg.type == "identifier":
|
|
1342
|
+
var_name = st(array_arg)
|
|
1343
|
+
if var_name in param_name_to_idx:
|
|
1344
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1345
|
+
|
|
1346
|
+
elif left.type == "field_expression":
|
|
1347
|
+
obj = left.child_by_field_name("argument")
|
|
1348
|
+
if obj and obj.type == "identifier":
|
|
1349
|
+
var_name = st(obj)
|
|
1350
|
+
if var_name in param_name_to_idx:
|
|
1351
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1352
|
+
|
|
1353
|
+
elif left.type == "identifier":
|
|
1354
|
+
var_name = st(left)
|
|
1355
|
+
if var_name in param_name_to_idx:
|
|
1356
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1357
|
+
|
|
1358
|
+
elif node.type == "update_expression":
|
|
1359
|
+
arg = node.child_by_field_name("argument")
|
|
1360
|
+
if arg:
|
|
1361
|
+
if arg.type == "pointer_expression":
|
|
1362
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1363
|
+
if inner_arg and inner_arg.type == "identifier":
|
|
1364
|
+
var_name = st(inner_arg)
|
|
1365
|
+
if var_name in param_name_to_idx:
|
|
1366
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1367
|
+
elif arg.type == "subscript_expression":
|
|
1368
|
+
array_arg = arg.child_by_field_name("argument")
|
|
1369
|
+
if array_arg and array_arg.type == "identifier":
|
|
1370
|
+
var_name = st(array_arg)
|
|
1371
|
+
if var_name in param_name_to_idx:
|
|
1372
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1373
|
+
elif arg.type == "field_expression":
|
|
1374
|
+
obj = arg.child_by_field_name("argument")
|
|
1375
|
+
if obj and obj.type == "identifier":
|
|
1376
|
+
var_name = st(obj)
|
|
1377
|
+
if var_name in param_name_to_idx:
|
|
1378
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1379
|
+
elif arg.type == "identifier":
|
|
1380
|
+
var_name = st(arg)
|
|
1381
|
+
if var_name in param_name_to_idx:
|
|
1382
|
+
modified_params.add(param_name_to_idx[var_name])
|
|
1383
|
+
|
|
1384
|
+
modifications[func_name] = modified_params
|
|
1385
|
+
|
|
1386
|
+
return modifications
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
def build_rda_table(
|
|
1390
|
+
parser,
|
|
1391
|
+
CFG_results,
|
|
1392
|
+
lambda_map=None,
|
|
1393
|
+
function_metadata=None,
|
|
1394
|
+
pointer_modifications=None,
|
|
1395
|
+
):
|
|
1396
|
+
if lambda_map is None:
|
|
1397
|
+
lambda_map = {}
|
|
1398
|
+
|
|
1399
|
+
rda_table = {}
|
|
1400
|
+
index = parser.index
|
|
1401
|
+
tree = parser.tree
|
|
1402
|
+
|
|
1403
|
+
inner_types_local = [
|
|
1404
|
+
"parenthesized_expression",
|
|
1405
|
+
"binary_expression",
|
|
1406
|
+
"unary_expression",
|
|
1407
|
+
]
|
|
1408
|
+
handled_cases = [
|
|
1409
|
+
"compound_statement",
|
|
1410
|
+
"translation_unit",
|
|
1411
|
+
"class_specifier",
|
|
1412
|
+
"struct_specifier",
|
|
1413
|
+
"namespace_definition",
|
|
1414
|
+
]
|
|
1415
|
+
|
|
1416
|
+
for root_node in traverse_tree(tree, []):
|
|
1417
|
+
if not root_node.is_named:
|
|
1418
|
+
continue
|
|
1419
|
+
|
|
1420
|
+
if root_node.type == "return_statement":
|
|
1421
|
+
parent_id = get_index(root_node, index)
|
|
1422
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1423
|
+
continue
|
|
1424
|
+
|
|
1425
|
+
return_expr = (
|
|
1426
|
+
root_node.named_children[0] if root_node.named_children else None
|
|
1427
|
+
)
|
|
1428
|
+
if (
|
|
1429
|
+
return_expr
|
|
1430
|
+
and return_expr.type
|
|
1431
|
+
in variable_type
|
|
1432
|
+
+ ["field_expression", "pointer_expression", "subscript_expression"]
|
|
1433
|
+
+ literal_types
|
|
1434
|
+
):
|
|
1435
|
+
add_entry(parser, rda_table, parent_id, used=return_expr)
|
|
1436
|
+
else:
|
|
1437
|
+
vars_used = recursively_get_children_of_types(
|
|
1438
|
+
root_node,
|
|
1439
|
+
variable_type
|
|
1440
|
+
+ [
|
|
1441
|
+
"field_expression",
|
|
1442
|
+
"pointer_expression",
|
|
1443
|
+
"subscript_expression",
|
|
1444
|
+
],
|
|
1445
|
+
index=parser.index,
|
|
1446
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1447
|
+
)
|
|
1448
|
+
for var in vars_used:
|
|
1449
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
1450
|
+
|
|
1451
|
+
literals_used = recursively_get_children_of_types(
|
|
1452
|
+
root_node, literal_types, index=parser.index
|
|
1453
|
+
)
|
|
1454
|
+
for literal in literals_used:
|
|
1455
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1456
|
+
|
|
1457
|
+
elif root_node.type in def_statement:
|
|
1458
|
+
parent_statement = return_first_parent_of_types(
|
|
1459
|
+
root_node, statement_types["node_list_type"]
|
|
1460
|
+
)
|
|
1461
|
+
if parent_statement is None:
|
|
1462
|
+
continue
|
|
1463
|
+
|
|
1464
|
+
parent_id = get_index(parent_statement, index)
|
|
1465
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1466
|
+
if parent_statement and parent_statement.type in inner_types_local:
|
|
1467
|
+
parent_statement = return_first_parent_of_types(
|
|
1468
|
+
parent_statement, statement_types["node_list_type"]
|
|
1469
|
+
)
|
|
1470
|
+
parent_id = get_index(parent_statement, index)
|
|
1471
|
+
elif parent_statement.type in handled_cases:
|
|
1472
|
+
continue
|
|
1473
|
+
else:
|
|
1474
|
+
continue
|
|
1475
|
+
|
|
1476
|
+
declarator = root_node.child_by_field_name("declarator")
|
|
1477
|
+
if declarator is None and len(root_node.children) > 0:
|
|
1478
|
+
declarator = root_node.children[0]
|
|
1479
|
+
|
|
1480
|
+
var_identifier = extract_identifier_from_declarator(declarator)
|
|
1481
|
+
|
|
1482
|
+
initializer = root_node.child_by_field_name("value")
|
|
1483
|
+
has_initializer = initializer is not None
|
|
1484
|
+
|
|
1485
|
+
if var_identifier:
|
|
1486
|
+
add_entry(
|
|
1487
|
+
parser,
|
|
1488
|
+
rda_table,
|
|
1489
|
+
parent_id,
|
|
1490
|
+
defined=var_identifier,
|
|
1491
|
+
declaration=True,
|
|
1492
|
+
has_initializer=has_initializer,
|
|
1493
|
+
)
|
|
1494
|
+
|
|
1495
|
+
if initializer:
|
|
1496
|
+
if initializer.type == "lambda_expression":
|
|
1497
|
+
for child in initializer.children:
|
|
1498
|
+
if child.type == "lambda_capture_specifier":
|
|
1499
|
+
for capture in child.named_children:
|
|
1500
|
+
if capture.type in variable_type:
|
|
1501
|
+
add_entry(
|
|
1502
|
+
parser, rda_table, parent_id, used=capture
|
|
1503
|
+
)
|
|
1504
|
+
elif (
|
|
1505
|
+
initializer.type
|
|
1506
|
+
in variable_type
|
|
1507
|
+
+ [
|
|
1508
|
+
"field_expression",
|
|
1509
|
+
"pointer_expression",
|
|
1510
|
+
"subscript_expression",
|
|
1511
|
+
"unary_expression",
|
|
1512
|
+
]
|
|
1513
|
+
+ literal_types
|
|
1514
|
+
):
|
|
1515
|
+
add_entry(parser, rda_table, parent_id, used=initializer)
|
|
1516
|
+
else:
|
|
1517
|
+
vars_used = recursively_get_children_of_types(
|
|
1518
|
+
initializer,
|
|
1519
|
+
variable_type + ["field_expression"],
|
|
1520
|
+
index=parser.index,
|
|
1521
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1522
|
+
)
|
|
1523
|
+
for var in vars_used:
|
|
1524
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
1525
|
+
literals_used = recursively_get_children_of_types(
|
|
1526
|
+
initializer, literal_types, index=parser.index
|
|
1527
|
+
)
|
|
1528
|
+
for literal in literals_used:
|
|
1529
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1530
|
+
|
|
1531
|
+
elif root_node.type in declaration_statement:
|
|
1532
|
+
parent_id = get_index(root_node, index)
|
|
1533
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1534
|
+
continue
|
|
1535
|
+
|
|
1536
|
+
has_init_declarator = any(
|
|
1537
|
+
child.type == "init_declarator" for child in root_node.named_children
|
|
1538
|
+
)
|
|
1539
|
+
if has_init_declarator:
|
|
1540
|
+
continue
|
|
1541
|
+
|
|
1542
|
+
for child in root_node.named_children:
|
|
1543
|
+
if child.type == "identifier":
|
|
1544
|
+
child_id = get_index(child, index)
|
|
1545
|
+
if child_id and child_id in parser.symbol_table["scope_map"]:
|
|
1546
|
+
add_entry(
|
|
1547
|
+
parser,
|
|
1548
|
+
rda_table,
|
|
1549
|
+
parent_id,
|
|
1550
|
+
defined=child,
|
|
1551
|
+
declaration=True,
|
|
1552
|
+
)
|
|
1553
|
+
elif child.type in [
|
|
1554
|
+
"pointer_declarator",
|
|
1555
|
+
"array_declarator",
|
|
1556
|
+
"reference_declarator",
|
|
1557
|
+
]:
|
|
1558
|
+
var_identifier = extract_identifier_from_declarator(child)
|
|
1559
|
+
if var_identifier:
|
|
1560
|
+
var_id = get_index(var_identifier, index)
|
|
1561
|
+
if var_id and var_id in parser.symbol_table["scope_map"]:
|
|
1562
|
+
add_entry(
|
|
1563
|
+
parser,
|
|
1564
|
+
rda_table,
|
|
1565
|
+
parent_id,
|
|
1566
|
+
defined=var_identifier,
|
|
1567
|
+
declaration=True,
|
|
1568
|
+
)
|
|
1569
|
+
|
|
1570
|
+
elif root_node.type in assignment:
|
|
1571
|
+
parent_statement = return_first_parent_of_types(
|
|
1572
|
+
root_node, statement_types["node_list_type"]
|
|
1573
|
+
)
|
|
1574
|
+
if parent_statement is None:
|
|
1575
|
+
continue
|
|
1576
|
+
|
|
1577
|
+
parent_id = get_index(parent_statement, index)
|
|
1578
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1579
|
+
if parent_statement and parent_statement.type in inner_types_local:
|
|
1580
|
+
parent_statement = return_first_parent_of_types(
|
|
1581
|
+
parent_statement, statement_types["node_list_type"]
|
|
1582
|
+
)
|
|
1583
|
+
parent_id = get_index(parent_statement, index)
|
|
1584
|
+
elif parent_statement.type in handled_cases:
|
|
1585
|
+
continue
|
|
1586
|
+
else:
|
|
1587
|
+
continue
|
|
1588
|
+
|
|
1589
|
+
left_node = root_node.child_by_field_name("left")
|
|
1590
|
+
right_node = root_node.child_by_field_name("right")
|
|
1591
|
+
|
|
1592
|
+
if left_node is None or right_node is None:
|
|
1593
|
+
continue
|
|
1594
|
+
|
|
1595
|
+
operator_text = extract_operator_text(root_node, left_node, right_node)
|
|
1596
|
+
|
|
1597
|
+
if operator_text != "=":
|
|
1598
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
1599
|
+
else:
|
|
1600
|
+
if left_node.type == "field_expression":
|
|
1601
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
1602
|
+
elif left_node.type in variable_type:
|
|
1603
|
+
var_type = get_variable_type(parser, left_node)
|
|
1604
|
+
|
|
1605
|
+
if is_class_or_struct_type(
|
|
1606
|
+
parser, var_type
|
|
1607
|
+
) or is_reference_variable(parser, left_node):
|
|
1608
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
1609
|
+
else:
|
|
1610
|
+
left_node_index = get_index(left_node, index)
|
|
1611
|
+
if (
|
|
1612
|
+
left_node_index
|
|
1613
|
+
and left_node_index in parser.symbol_table["scope_map"]
|
|
1614
|
+
):
|
|
1615
|
+
is_init_declarator = False
|
|
1616
|
+
check_parent = root_node.parent
|
|
1617
|
+
while check_parent:
|
|
1618
|
+
if check_parent.type == "init_declarator":
|
|
1619
|
+
is_init_declarator = True
|
|
1620
|
+
break
|
|
1621
|
+
if check_parent.type in statement_types.get(
|
|
1622
|
+
"node_list_type", []
|
|
1623
|
+
):
|
|
1624
|
+
break
|
|
1625
|
+
check_parent = check_parent.parent
|
|
1626
|
+
|
|
1627
|
+
if not is_init_declarator:
|
|
1628
|
+
add_entry(parser, rda_table, parent_id, used=left_node)
|
|
1629
|
+
|
|
1630
|
+
add_entry(parser, rda_table, parent_id, defined=left_node)
|
|
1631
|
+
|
|
1632
|
+
if (
|
|
1633
|
+
right_node.type
|
|
1634
|
+
in variable_type
|
|
1635
|
+
+ [
|
|
1636
|
+
"field_expression",
|
|
1637
|
+
"pointer_expression",
|
|
1638
|
+
"subscript_expression",
|
|
1639
|
+
"unary_expression",
|
|
1640
|
+
]
|
|
1641
|
+
+ literal_types
|
|
1642
|
+
):
|
|
1643
|
+
add_entry(parser, rda_table, parent_id, used=right_node)
|
|
1644
|
+
else:
|
|
1645
|
+
vars_used = recursively_get_children_of_types(
|
|
1646
|
+
right_node,
|
|
1647
|
+
variable_type + ["field_expression"],
|
|
1648
|
+
index=parser.index,
|
|
1649
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1650
|
+
)
|
|
1651
|
+
for var in vars_used:
|
|
1652
|
+
add_entry(parser, rda_table, parent_id, used=var)
|
|
1653
|
+
literals_used = recursively_get_children_of_types(
|
|
1654
|
+
right_node, literal_types, index=parser.index
|
|
1655
|
+
)
|
|
1656
|
+
for literal in literals_used:
|
|
1657
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
1658
|
+
|
|
1659
|
+
elif root_node.type in increment_statement:
|
|
1660
|
+
parent_statement = return_first_parent_of_types(
|
|
1661
|
+
root_node, statement_types["node_list_type"]
|
|
1662
|
+
)
|
|
1663
|
+
if parent_statement is None:
|
|
1664
|
+
continue
|
|
1665
|
+
|
|
1666
|
+
parent_id = get_index(parent_statement, index)
|
|
1667
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1668
|
+
if parent_statement and parent_statement.type in inner_types_local:
|
|
1669
|
+
parent_statement = return_first_parent_of_types(
|
|
1670
|
+
parent_statement, statement_types["node_list_type"]
|
|
1671
|
+
)
|
|
1672
|
+
parent_id = get_index(parent_statement, index)
|
|
1673
|
+
elif parent_statement.type in handled_cases:
|
|
1674
|
+
continue
|
|
1675
|
+
else:
|
|
1676
|
+
continue
|
|
1677
|
+
|
|
1678
|
+
if root_node.type in variable_type + ["field_expression"]:
|
|
1679
|
+
add_entry(parser, rda_table, parent_id, used=root_node)
|
|
1680
|
+
add_entry(parser, rda_table, parent_id, defined=root_node)
|
|
1681
|
+
else:
|
|
1682
|
+
identifiers = recursively_get_children_of_types(
|
|
1683
|
+
root_node,
|
|
1684
|
+
variable_type + ["field_expression"],
|
|
1685
|
+
index=parser.index,
|
|
1686
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1687
|
+
)
|
|
1688
|
+
for identifier in identifiers:
|
|
1689
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1690
|
+
add_entry(parser, rda_table, parent_id, defined=identifier)
|
|
1691
|
+
|
|
1692
|
+
elif root_node.type in function_calls:
|
|
1693
|
+
parent_statement = return_first_parent_of_types(
|
|
1694
|
+
root_node, statement_types["node_list_type"]
|
|
1695
|
+
)
|
|
1696
|
+
if parent_statement is None:
|
|
1697
|
+
continue
|
|
1698
|
+
|
|
1699
|
+
parent_id = get_index(parent_statement, index)
|
|
1700
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
1701
|
+
if parent_statement and parent_statement.type in inner_types_local:
|
|
1702
|
+
parent_statement = return_first_parent_of_types(
|
|
1703
|
+
parent_statement, statement_types["node_list_type"]
|
|
1704
|
+
)
|
|
1705
|
+
parent_id = get_index(parent_statement, index)
|
|
1706
|
+
elif parent_statement.type in handled_cases:
|
|
1707
|
+
continue
|
|
1708
|
+
else:
|
|
1709
|
+
continue
|
|
1710
|
+
|
|
1711
|
+
function_node = root_node.child_by_field_name("function")
|
|
1712
|
+
function_name = None
|
|
1713
|
+
method_name_for_lookup = None
|
|
1714
|
+
|
|
1715
|
+
if function_node:
|
|
1716
|
+
function_name = st(function_node)
|
|
1717
|
+
|
|
1718
|
+
if function_node.type == "field_expression":
|
|
1719
|
+
argument = function_node.child_by_field_name("argument")
|
|
1720
|
+
if argument:
|
|
1721
|
+
add_entry(parser, rda_table, parent_id, used=argument)
|
|
1722
|
+
field = function_node.child_by_field_name("field")
|
|
1723
|
+
if field:
|
|
1724
|
+
method_name_for_lookup = st(field)
|
|
1725
|
+
elif function_node.type in variable_type:
|
|
1726
|
+
add_entry(
|
|
1727
|
+
parser,
|
|
1728
|
+
rda_table,
|
|
1729
|
+
parent_id,
|
|
1730
|
+
used=function_node,
|
|
1731
|
+
method_call=True,
|
|
1732
|
+
)
|
|
1733
|
+
elif function_node.type == "qualified_identifier":
|
|
1734
|
+
add_entry(
|
|
1735
|
+
parser,
|
|
1736
|
+
rda_table,
|
|
1737
|
+
parent_id,
|
|
1738
|
+
used=function_node,
|
|
1739
|
+
method_call=True,
|
|
1740
|
+
)
|
|
1741
|
+
|
|
1742
|
+
is_input_function = function_name in input_functions or (
|
|
1743
|
+
function_name and any(inp in function_name for inp in ["cin", "scanf"])
|
|
1744
|
+
)
|
|
1745
|
+
|
|
1746
|
+
is_variadic_macro = function_name in ["va_start", "va_arg", "va_end"]
|
|
1747
|
+
|
|
1748
|
+
args_node = root_node.child_by_field_name("arguments")
|
|
1749
|
+
if args_node:
|
|
1750
|
+
arg_list = list(args_node.named_children)
|
|
1751
|
+
for idx, arg in enumerate(arg_list):
|
|
1752
|
+
if is_variadic_macro:
|
|
1753
|
+
if function_name == "va_start" and idx == 0:
|
|
1754
|
+
if arg.type in variable_type:
|
|
1755
|
+
add_entry(
|
|
1756
|
+
parser,
|
|
1757
|
+
rda_table,
|
|
1758
|
+
parent_id,
|
|
1759
|
+
defined=arg,
|
|
1760
|
+
declaration=False,
|
|
1761
|
+
has_initializer=True,
|
|
1762
|
+
)
|
|
1763
|
+
else:
|
|
1764
|
+
identifiers_defined = recursively_get_children_of_types(
|
|
1765
|
+
arg,
|
|
1766
|
+
variable_type,
|
|
1767
|
+
index=parser.index,
|
|
1768
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1769
|
+
)
|
|
1770
|
+
for identifier in identifiers_defined:
|
|
1771
|
+
add_entry(
|
|
1772
|
+
parser,
|
|
1773
|
+
rda_table,
|
|
1774
|
+
parent_id,
|
|
1775
|
+
defined=identifier,
|
|
1776
|
+
declaration=False,
|
|
1777
|
+
has_initializer=True,
|
|
1778
|
+
)
|
|
1779
|
+
continue
|
|
1780
|
+
|
|
1781
|
+
elif function_name == "va_arg" and idx == 0:
|
|
1782
|
+
if arg.type in variable_type:
|
|
1783
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1784
|
+
add_entry(
|
|
1785
|
+
parser,
|
|
1786
|
+
rda_table,
|
|
1787
|
+
parent_id,
|
|
1788
|
+
defined=arg,
|
|
1789
|
+
declaration=False,
|
|
1790
|
+
)
|
|
1791
|
+
else:
|
|
1792
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1793
|
+
arg,
|
|
1794
|
+
variable_type,
|
|
1795
|
+
index=parser.index,
|
|
1796
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1797
|
+
)
|
|
1798
|
+
for identifier in identifiers_used:
|
|
1799
|
+
add_entry(
|
|
1800
|
+
parser, rda_table, parent_id, used=identifier
|
|
1801
|
+
)
|
|
1802
|
+
add_entry(
|
|
1803
|
+
parser,
|
|
1804
|
+
rda_table,
|
|
1805
|
+
parent_id,
|
|
1806
|
+
defined=identifier,
|
|
1807
|
+
declaration=False,
|
|
1808
|
+
)
|
|
1809
|
+
continue
|
|
1810
|
+
|
|
1811
|
+
if is_input_function:
|
|
1812
|
+
if arg.type == "unary_expression":
|
|
1813
|
+
has_address_of = any(
|
|
1814
|
+
child.type == "&" for child in arg.children
|
|
1815
|
+
)
|
|
1816
|
+
if has_address_of:
|
|
1817
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1818
|
+
if inner_arg:
|
|
1819
|
+
if inner_arg.type in variable_type:
|
|
1820
|
+
add_entry(
|
|
1821
|
+
parser,
|
|
1822
|
+
rda_table,
|
|
1823
|
+
parent_id,
|
|
1824
|
+
defined=inner_arg,
|
|
1825
|
+
declaration=False,
|
|
1826
|
+
)
|
|
1827
|
+
elif inner_arg.type in [
|
|
1828
|
+
"field_expression",
|
|
1829
|
+
"subscript_expression",
|
|
1830
|
+
]:
|
|
1831
|
+
add_entry(
|
|
1832
|
+
parser,
|
|
1833
|
+
rda_table,
|
|
1834
|
+
parent_id,
|
|
1835
|
+
defined=inner_arg,
|
|
1836
|
+
declaration=False,
|
|
1837
|
+
)
|
|
1838
|
+
continue
|
|
1839
|
+
if arg.type in variable_type + ["field_expression"]:
|
|
1840
|
+
add_entry(
|
|
1841
|
+
parser,
|
|
1842
|
+
rda_table,
|
|
1843
|
+
parent_id,
|
|
1844
|
+
defined=arg,
|
|
1845
|
+
declaration=False,
|
|
1846
|
+
)
|
|
1847
|
+
continue
|
|
1848
|
+
|
|
1849
|
+
if not is_input_function and not is_variadic_macro:
|
|
1850
|
+
modifies_params = set()
|
|
1851
|
+
lookup_name = (
|
|
1852
|
+
method_name_for_lookup
|
|
1853
|
+
if method_name_for_lookup
|
|
1854
|
+
else function_name
|
|
1855
|
+
)
|
|
1856
|
+
if (
|
|
1857
|
+
lookup_name
|
|
1858
|
+
and function_metadata
|
|
1859
|
+
and lookup_name in function_metadata
|
|
1860
|
+
):
|
|
1861
|
+
if (
|
|
1862
|
+
pointer_modifications
|
|
1863
|
+
and lookup_name in pointer_modifications
|
|
1864
|
+
):
|
|
1865
|
+
modifies_params = pointer_modifications[lookup_name]
|
|
1866
|
+
|
|
1867
|
+
is_modified_param = idx in modifies_params
|
|
1868
|
+
|
|
1869
|
+
if is_modified_param:
|
|
1870
|
+
if arg.type == "pointer_expression":
|
|
1871
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1872
|
+
if not inner_arg:
|
|
1873
|
+
inner_arg = (
|
|
1874
|
+
arg.named_children[0]
|
|
1875
|
+
if arg.named_children
|
|
1876
|
+
else None
|
|
1877
|
+
)
|
|
1878
|
+
|
|
1879
|
+
if inner_arg:
|
|
1880
|
+
if inner_arg.type in variable_type:
|
|
1881
|
+
add_entry(
|
|
1882
|
+
parser, rda_table, parent_id, used=inner_arg
|
|
1883
|
+
)
|
|
1884
|
+
add_entry(
|
|
1885
|
+
parser,
|
|
1886
|
+
rda_table,
|
|
1887
|
+
parent_id,
|
|
1888
|
+
defined=inner_arg,
|
|
1889
|
+
declaration=False,
|
|
1890
|
+
is_pointer_modification_at_call_site=True,
|
|
1891
|
+
)
|
|
1892
|
+
elif inner_arg.type in [
|
|
1893
|
+
"field_expression",
|
|
1894
|
+
"subscript_expression",
|
|
1895
|
+
]:
|
|
1896
|
+
add_entry(
|
|
1897
|
+
parser, rda_table, parent_id, used=inner_arg
|
|
1898
|
+
)
|
|
1899
|
+
add_entry(
|
|
1900
|
+
parser,
|
|
1901
|
+
rda_table,
|
|
1902
|
+
parent_id,
|
|
1903
|
+
defined=inner_arg,
|
|
1904
|
+
declaration=False,
|
|
1905
|
+
is_pointer_modification_at_call_site=True,
|
|
1906
|
+
)
|
|
1907
|
+
if inner_arg.type == "subscript_expression":
|
|
1908
|
+
index_expr = inner_arg.child_by_field_name(
|
|
1909
|
+
"index"
|
|
1910
|
+
)
|
|
1911
|
+
if index_expr:
|
|
1912
|
+
vars_in_index = (
|
|
1913
|
+
recursively_get_children_of_types(
|
|
1914
|
+
index_expr,
|
|
1915
|
+
variable_type
|
|
1916
|
+
+ ["field_expression"],
|
|
1917
|
+
index=parser.index,
|
|
1918
|
+
check_list=parser.symbol_table[
|
|
1919
|
+
"scope_map"
|
|
1920
|
+
],
|
|
1921
|
+
)
|
|
1922
|
+
)
|
|
1923
|
+
for var in vars_in_index:
|
|
1924
|
+
add_entry(
|
|
1925
|
+
parser,
|
|
1926
|
+
rda_table,
|
|
1927
|
+
parent_id,
|
|
1928
|
+
used=var,
|
|
1929
|
+
)
|
|
1930
|
+
continue
|
|
1931
|
+
elif arg.type == "unary_expression":
|
|
1932
|
+
has_address_of = any(
|
|
1933
|
+
child.type == "&" for child in arg.children
|
|
1934
|
+
)
|
|
1935
|
+
if has_address_of:
|
|
1936
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
1937
|
+
if inner_arg:
|
|
1938
|
+
if inner_arg.type in variable_type:
|
|
1939
|
+
add_entry(
|
|
1940
|
+
parser,
|
|
1941
|
+
rda_table,
|
|
1942
|
+
parent_id,
|
|
1943
|
+
used=inner_arg,
|
|
1944
|
+
)
|
|
1945
|
+
add_entry(
|
|
1946
|
+
parser,
|
|
1947
|
+
rda_table,
|
|
1948
|
+
parent_id,
|
|
1949
|
+
defined=inner_arg,
|
|
1950
|
+
declaration=False,
|
|
1951
|
+
is_pointer_modification_at_call_site=True,
|
|
1952
|
+
)
|
|
1953
|
+
elif inner_arg.type in [
|
|
1954
|
+
"field_expression",
|
|
1955
|
+
"subscript_expression",
|
|
1956
|
+
]:
|
|
1957
|
+
add_entry(
|
|
1958
|
+
parser,
|
|
1959
|
+
rda_table,
|
|
1960
|
+
parent_id,
|
|
1961
|
+
used=inner_arg,
|
|
1962
|
+
)
|
|
1963
|
+
add_entry(
|
|
1964
|
+
parser,
|
|
1965
|
+
rda_table,
|
|
1966
|
+
parent_id,
|
|
1967
|
+
defined=inner_arg,
|
|
1968
|
+
declaration=False,
|
|
1969
|
+
is_pointer_modification_at_call_site=True,
|
|
1970
|
+
)
|
|
1971
|
+
continue
|
|
1972
|
+
|
|
1973
|
+
elif arg.type in variable_type + ["field_expression"]:
|
|
1974
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1975
|
+
add_entry(
|
|
1976
|
+
parser,
|
|
1977
|
+
rda_table,
|
|
1978
|
+
parent_id,
|
|
1979
|
+
defined=arg,
|
|
1980
|
+
declaration=False,
|
|
1981
|
+
is_pointer_modification_at_call_site=True,
|
|
1982
|
+
)
|
|
1983
|
+
continue
|
|
1984
|
+
|
|
1985
|
+
if arg.type in variable_type + ["field_expression"]:
|
|
1986
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1987
|
+
elif arg.type in literal_types:
|
|
1988
|
+
add_entry(parser, rda_table, parent_id, used=arg)
|
|
1989
|
+
else:
|
|
1990
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1991
|
+
arg,
|
|
1992
|
+
variable_type + ["field_expression"],
|
|
1993
|
+
index=parser.index,
|
|
1994
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1995
|
+
)
|
|
1996
|
+
for identifier in identifiers_used:
|
|
1997
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1998
|
+
literals_used = recursively_get_children_of_types(
|
|
1999
|
+
arg, literal_types, index=parser.index
|
|
2000
|
+
)
|
|
2001
|
+
for literal in literals_used:
|
|
2002
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
2003
|
+
|
|
2004
|
+
elif root_node.type == "function_definition":
|
|
2005
|
+
parent_id = get_index(root_node, index)
|
|
2006
|
+
if parent_id is None:
|
|
2007
|
+
continue
|
|
2008
|
+
|
|
2009
|
+
declarator = root_node.child_by_field_name("declarator")
|
|
2010
|
+
if declarator:
|
|
2011
|
+
func_declarator = declarator
|
|
2012
|
+
while func_declarator and func_declarator.type in [
|
|
2013
|
+
"pointer_declarator",
|
|
2014
|
+
"reference_declarator",
|
|
2015
|
+
]:
|
|
2016
|
+
for child in func_declarator.children:
|
|
2017
|
+
if child.type == "function_declarator":
|
|
2018
|
+
func_declarator = child
|
|
2019
|
+
break
|
|
2020
|
+
else:
|
|
2021
|
+
break
|
|
2022
|
+
|
|
2023
|
+
if func_declarator and func_declarator.type == "function_declarator":
|
|
2024
|
+
func_name_node = func_declarator.child_by_field_name("declarator")
|
|
2025
|
+
if func_name_node and func_name_node.type in variable_type:
|
|
2026
|
+
func_name_idx = get_index(func_name_node, index)
|
|
2027
|
+
if (
|
|
2028
|
+
func_name_idx
|
|
2029
|
+
and func_name_idx in parser.symbol_table["scope_map"]
|
|
2030
|
+
):
|
|
2031
|
+
namespace_name = get_namespace_for_node(root_node, parser)
|
|
2032
|
+
|
|
2033
|
+
if namespace_name:
|
|
2034
|
+
qualified_name = (
|
|
2035
|
+
f"{namespace_name}::{st(func_name_node)}"
|
|
2036
|
+
)
|
|
2037
|
+
|
|
2038
|
+
class PseudoNode:
|
|
2039
|
+
def __init__(self, name, real_node):
|
|
2040
|
+
self.type = "qualified_function"
|
|
2041
|
+
self.text = name.encode("utf-8")
|
|
2042
|
+
self.qualified_name = name
|
|
2043
|
+
self.parent = (
|
|
2044
|
+
real_node.parent if real_node else None
|
|
2045
|
+
)
|
|
2046
|
+
self.real_node = real_node
|
|
2047
|
+
|
|
2048
|
+
pseudo_node = PseudoNode(qualified_name, func_name_node)
|
|
2049
|
+
add_entry(
|
|
2050
|
+
parser,
|
|
2051
|
+
rda_table,
|
|
2052
|
+
parent_id,
|
|
2053
|
+
defined=pseudo_node,
|
|
2054
|
+
declaration=True,
|
|
2055
|
+
)
|
|
2056
|
+
else:
|
|
2057
|
+
add_entry(
|
|
2058
|
+
parser,
|
|
2059
|
+
rda_table,
|
|
2060
|
+
parent_id,
|
|
2061
|
+
defined=func_name_node,
|
|
2062
|
+
declaration=True,
|
|
2063
|
+
)
|
|
2064
|
+
|
|
2065
|
+
param_list = func_declarator.child_by_field_name("parameters")
|
|
2066
|
+
if param_list:
|
|
2067
|
+
for param in param_list.named_children:
|
|
2068
|
+
if param.type in [
|
|
2069
|
+
"parameter_declaration",
|
|
2070
|
+
"optional_parameter_declaration",
|
|
2071
|
+
]:
|
|
2072
|
+
param_id = extract_param_identifier(param)
|
|
2073
|
+
if param_id:
|
|
2074
|
+
add_entry(
|
|
2075
|
+
parser,
|
|
2076
|
+
rda_table,
|
|
2077
|
+
parent_id,
|
|
2078
|
+
defined=param_id,
|
|
2079
|
+
declaration=True,
|
|
2080
|
+
has_initializer=True,
|
|
2081
|
+
)
|
|
2082
|
+
|
|
2083
|
+
elif root_node.type == "if_statement":
|
|
2084
|
+
parent_id = get_index(root_node, index)
|
|
2085
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2086
|
+
continue
|
|
2087
|
+
|
|
2088
|
+
condition = root_node.child_by_field_name("condition")
|
|
2089
|
+
if condition:
|
|
2090
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2091
|
+
condition,
|
|
2092
|
+
variable_type + ["field_expression"],
|
|
2093
|
+
index=parser.index,
|
|
2094
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2095
|
+
)
|
|
2096
|
+
for identifier in identifiers_used:
|
|
2097
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2098
|
+
|
|
2099
|
+
elif root_node.type == "while_statement":
|
|
2100
|
+
parent_id = get_index(root_node, index)
|
|
2101
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2102
|
+
continue
|
|
2103
|
+
|
|
2104
|
+
condition = root_node.child_by_field_name("condition")
|
|
2105
|
+
if condition:
|
|
2106
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2107
|
+
condition,
|
|
2108
|
+
variable_type + ["field_expression"],
|
|
2109
|
+
index=parser.index,
|
|
2110
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2111
|
+
)
|
|
2112
|
+
for identifier in identifiers_used:
|
|
2113
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2114
|
+
|
|
2115
|
+
elif root_node.type == "for_statement":
|
|
2116
|
+
parent_id = get_index(root_node, index)
|
|
2117
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2118
|
+
continue
|
|
2119
|
+
|
|
2120
|
+
condition = root_node.child_by_field_name("condition")
|
|
2121
|
+
if condition:
|
|
2122
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2123
|
+
condition,
|
|
2124
|
+
variable_type + ["field_expression"],
|
|
2125
|
+
index=parser.index,
|
|
2126
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2127
|
+
)
|
|
2128
|
+
for identifier in identifiers_used:
|
|
2129
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2130
|
+
|
|
2131
|
+
elif root_node.type == "for_range_loop":
|
|
2132
|
+
parent_id = get_index(root_node, index)
|
|
2133
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2134
|
+
continue
|
|
2135
|
+
|
|
2136
|
+
declarator = root_node.child_by_field_name("declarator")
|
|
2137
|
+
if declarator:
|
|
2138
|
+
var_id = extract_identifier_from_declarator(declarator)
|
|
2139
|
+
if var_id:
|
|
2140
|
+
add_entry(
|
|
2141
|
+
parser, rda_table, parent_id, defined=var_id, declaration=True
|
|
2142
|
+
)
|
|
2143
|
+
|
|
2144
|
+
range_expr = root_node.child_by_field_name("right")
|
|
2145
|
+
if range_expr:
|
|
2146
|
+
if range_expr.type in variable_type + ["field_expression"]:
|
|
2147
|
+
add_entry(parser, rda_table, parent_id, used=range_expr)
|
|
2148
|
+
else:
|
|
2149
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2150
|
+
range_expr,
|
|
2151
|
+
variable_type + ["field_expression"],
|
|
2152
|
+
index=parser.index,
|
|
2153
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2154
|
+
)
|
|
2155
|
+
for identifier in identifiers_used:
|
|
2156
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2157
|
+
|
|
2158
|
+
elif root_node.type == "do_statement":
|
|
2159
|
+
pass
|
|
2160
|
+
|
|
2161
|
+
elif (
|
|
2162
|
+
root_node.type == "parenthesized_expression"
|
|
2163
|
+
and root_node.parent is not None
|
|
2164
|
+
and root_node.parent.type == "do_statement"
|
|
2165
|
+
):
|
|
2166
|
+
parent_id = get_index(root_node, index)
|
|
2167
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2168
|
+
continue
|
|
2169
|
+
|
|
2170
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2171
|
+
root_node,
|
|
2172
|
+
variable_type + ["field_expression"],
|
|
2173
|
+
index=parser.index,
|
|
2174
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2175
|
+
)
|
|
2176
|
+
for identifier in identifiers_used:
|
|
2177
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2178
|
+
|
|
2179
|
+
elif root_node.type == "switch_statement":
|
|
2180
|
+
parent_id = get_index(root_node, index)
|
|
2181
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2182
|
+
continue
|
|
2183
|
+
|
|
2184
|
+
condition = root_node.child_by_field_name("condition")
|
|
2185
|
+
if condition:
|
|
2186
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2187
|
+
condition,
|
|
2188
|
+
variable_type + ["field_expression"],
|
|
2189
|
+
index=parser.index,
|
|
2190
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2191
|
+
)
|
|
2192
|
+
for identifier in identifiers_used:
|
|
2193
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2194
|
+
|
|
2195
|
+
elif root_node.type == "conditional_expression":
|
|
2196
|
+
parent_statement = return_first_parent_of_types(
|
|
2197
|
+
root_node, statement_types["node_list_type"]
|
|
2198
|
+
)
|
|
2199
|
+
if parent_statement is None:
|
|
2200
|
+
continue
|
|
2201
|
+
|
|
2202
|
+
parent_id = get_index(parent_statement, index)
|
|
2203
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2204
|
+
if parent_statement and parent_statement.type in inner_types_local:
|
|
2205
|
+
parent_statement = return_first_parent_of_types(
|
|
2206
|
+
parent_statement, statement_types["node_list_type"]
|
|
2207
|
+
)
|
|
2208
|
+
parent_id = get_index(parent_statement, index)
|
|
2209
|
+
elif parent_statement.type in handled_cases:
|
|
2210
|
+
continue
|
|
2211
|
+
else:
|
|
2212
|
+
continue
|
|
2213
|
+
|
|
2214
|
+
condition = root_node.child_by_field_name("condition")
|
|
2215
|
+
if condition:
|
|
2216
|
+
if (
|
|
2217
|
+
condition.type
|
|
2218
|
+
in variable_type
|
|
2219
|
+
+ [
|
|
2220
|
+
"field_expression",
|
|
2221
|
+
"pointer_expression",
|
|
2222
|
+
"subscript_expression",
|
|
2223
|
+
"unary_expression",
|
|
2224
|
+
]
|
|
2225
|
+
+ literal_types
|
|
2226
|
+
):
|
|
2227
|
+
add_entry(parser, rda_table, parent_id, used=condition)
|
|
2228
|
+
else:
|
|
2229
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2230
|
+
condition,
|
|
2231
|
+
variable_type + ["field_expression"],
|
|
2232
|
+
index=parser.index,
|
|
2233
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2234
|
+
)
|
|
2235
|
+
for identifier in identifiers_used:
|
|
2236
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2237
|
+
literals_used = recursively_get_children_of_types(
|
|
2238
|
+
condition, literal_types, index=parser.index
|
|
2239
|
+
)
|
|
2240
|
+
for literal in literals_used:
|
|
2241
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
2242
|
+
|
|
2243
|
+
consequence = root_node.child_by_field_name("consequence")
|
|
2244
|
+
if consequence:
|
|
2245
|
+
if consequence.type in variable_type + ["field_expression"]:
|
|
2246
|
+
add_entry(parser, rda_table, parent_id, used=consequence)
|
|
2247
|
+
elif consequence.type in literal_types:
|
|
2248
|
+
add_entry(parser, rda_table, parent_id, used=consequence)
|
|
2249
|
+
else:
|
|
2250
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2251
|
+
consequence,
|
|
2252
|
+
variable_type + ["field_expression"],
|
|
2253
|
+
index=parser.index,
|
|
2254
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2255
|
+
)
|
|
2256
|
+
for identifier in identifiers_used:
|
|
2257
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2258
|
+
literals_used = recursively_get_children_of_types(
|
|
2259
|
+
consequence, literal_types, index=parser.index
|
|
2260
|
+
)
|
|
2261
|
+
for literal in literals_used:
|
|
2262
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
2263
|
+
|
|
2264
|
+
alternative = root_node.child_by_field_name("alternative")
|
|
2265
|
+
if alternative:
|
|
2266
|
+
if alternative.type in variable_type + ["field_expression"]:
|
|
2267
|
+
add_entry(parser, rda_table, parent_id, used=alternative)
|
|
2268
|
+
elif alternative.type in literal_types:
|
|
2269
|
+
add_entry(parser, rda_table, parent_id, used=alternative)
|
|
2270
|
+
else:
|
|
2271
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2272
|
+
alternative,
|
|
2273
|
+
variable_type + ["field_expression"],
|
|
2274
|
+
index=parser.index,
|
|
2275
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2276
|
+
)
|
|
2277
|
+
for identifier in identifiers_used:
|
|
2278
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2279
|
+
literals_used = recursively_get_children_of_types(
|
|
2280
|
+
alternative, literal_types, index=parser.index
|
|
2281
|
+
)
|
|
2282
|
+
for literal in literals_used:
|
|
2283
|
+
add_entry(parser, rda_table, parent_id, used=literal)
|
|
2284
|
+
|
|
2285
|
+
elif root_node.type == "lambda_expression":
|
|
2286
|
+
parent_id = get_index(root_node, index)
|
|
2287
|
+
if parent_id is None:
|
|
2288
|
+
continue
|
|
2289
|
+
|
|
2290
|
+
for child in root_node.children:
|
|
2291
|
+
if child.type == "lambda_capture_specifier":
|
|
2292
|
+
for capture in child.named_children:
|
|
2293
|
+
if capture.type in variable_type:
|
|
2294
|
+
add_entry(parser, rda_table, parent_id, used=capture)
|
|
2295
|
+
|
|
2296
|
+
elif root_node.type == "catch_clause":
|
|
2297
|
+
parent_id = get_index(root_node, index)
|
|
2298
|
+
if parent_id is None:
|
|
2299
|
+
continue
|
|
2300
|
+
|
|
2301
|
+
for child in root_node.children:
|
|
2302
|
+
if child.type == "parameter_list":
|
|
2303
|
+
for param in child.named_children:
|
|
2304
|
+
if param.type == "parameter_declaration":
|
|
2305
|
+
param_id = extract_param_identifier(param)
|
|
2306
|
+
if param_id:
|
|
2307
|
+
add_entry(
|
|
2308
|
+
parser,
|
|
2309
|
+
rda_table,
|
|
2310
|
+
parent_id,
|
|
2311
|
+
defined=param_id,
|
|
2312
|
+
declaration=True,
|
|
2313
|
+
)
|
|
2314
|
+
|
|
2315
|
+
elif root_node.type == "throw_statement":
|
|
2316
|
+
parent_id = get_index(root_node, index)
|
|
2317
|
+
if parent_id is None:
|
|
2318
|
+
continue
|
|
2319
|
+
|
|
2320
|
+
identifiers_used = recursively_get_children_of_types(
|
|
2321
|
+
root_node,
|
|
2322
|
+
variable_type + ["field_expression"],
|
|
2323
|
+
index=parser.index,
|
|
2324
|
+
check_list=parser.symbol_table["scope_map"],
|
|
2325
|
+
)
|
|
2326
|
+
for identifier in identifiers_used:
|
|
2327
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
2328
|
+
|
|
2329
|
+
else:
|
|
2330
|
+
if root_node.type not in variable_type:
|
|
2331
|
+
continue
|
|
2332
|
+
|
|
2333
|
+
in_do_while_condition = False
|
|
2334
|
+
temp_parent = root_node.parent
|
|
2335
|
+
while temp_parent is not None:
|
|
2336
|
+
if (
|
|
2337
|
+
temp_parent.type == "parenthesized_expression"
|
|
2338
|
+
and temp_parent.parent is not None
|
|
2339
|
+
and temp_parent.parent.type == "do_statement"
|
|
2340
|
+
):
|
|
2341
|
+
in_do_while_condition = True
|
|
2342
|
+
break
|
|
2343
|
+
temp_parent = temp_parent.parent
|
|
2344
|
+
|
|
2345
|
+
if in_do_while_condition:
|
|
2346
|
+
continue
|
|
2347
|
+
|
|
2348
|
+
handled_types_local = (
|
|
2349
|
+
def_statement
|
|
2350
|
+
+ assignment
|
|
2351
|
+
+ increment_statement
|
|
2352
|
+
+ function_calls
|
|
2353
|
+
+ declaration_statement
|
|
2354
|
+
+ [
|
|
2355
|
+
"return_statement",
|
|
2356
|
+
"catch_clause",
|
|
2357
|
+
"throw_statement",
|
|
2358
|
+
"conditional_expression",
|
|
2359
|
+
]
|
|
2360
|
+
)
|
|
2361
|
+
parent_statement = return_first_parent_of_types(
|
|
2362
|
+
root_node,
|
|
2363
|
+
statement_types["non_control_statement"]
|
|
2364
|
+
+ statement_types["control_statement"],
|
|
2365
|
+
stop_types=statement_types.get("statement_holders", [])
|
|
2366
|
+
+ handled_types_local,
|
|
2367
|
+
)
|
|
2368
|
+
|
|
2369
|
+
if parent_statement is None:
|
|
2370
|
+
continue
|
|
2371
|
+
|
|
2372
|
+
parent_id = get_index(parent_statement, index)
|
|
2373
|
+
if parent_id is None or parent_id not in CFG_results.graph.nodes:
|
|
2374
|
+
continue
|
|
2375
|
+
|
|
2376
|
+
if parent_statement.type in declaration_statement:
|
|
2377
|
+
continue
|
|
2378
|
+
|
|
2379
|
+
immediate_parent = root_node.parent
|
|
2380
|
+
if immediate_parent and immediate_parent.type == "pointer_expression":
|
|
2381
|
+
continue
|
|
2382
|
+
|
|
2383
|
+
add_entry(parser, rda_table, parent_id, used=root_node)
|
|
2384
|
+
|
|
2385
|
+
return rda_table
|
|
2386
|
+
|
|
2387
|
+
|
|
2388
|
+
def start_rda(index, rda_table, cfg_graph, pre_solve=False):
|
|
2389
|
+
graph = copy.deepcopy(cfg_graph)
|
|
2390
|
+
if pre_solve:
|
|
2391
|
+
remove_edges = []
|
|
2392
|
+
for edge in graph.edges:
|
|
2393
|
+
edge_data = graph.edges[edge]
|
|
2394
|
+
if "label" in edge_data and edge_data["label"] in [
|
|
2395
|
+
"method_call",
|
|
2396
|
+
"method_return",
|
|
2397
|
+
"class_return",
|
|
2398
|
+
"constructor_call",
|
|
2399
|
+
]:
|
|
2400
|
+
remove_edges.append(edge)
|
|
2401
|
+
graph.remove_edges_from(remove_edges)
|
|
2402
|
+
|
|
2403
|
+
cfg = graph
|
|
2404
|
+
nodes = graph.nodes
|
|
2405
|
+
|
|
2406
|
+
old_result = {}
|
|
2407
|
+
for node in nodes:
|
|
2408
|
+
old_result[node] = {"IN": set(), "OUT": set()}
|
|
2409
|
+
|
|
2410
|
+
new_result = copy.deepcopy(old_result)
|
|
2411
|
+
iteration = 0
|
|
2412
|
+
|
|
2413
|
+
while True:
|
|
2414
|
+
iteration += 1
|
|
2415
|
+
|
|
2416
|
+
for node in nodes:
|
|
2417
|
+
predecessors = [s for (s, t) in cfg.in_edges(node)]
|
|
2418
|
+
|
|
2419
|
+
in_set = set()
|
|
2420
|
+
for pred in predecessors:
|
|
2421
|
+
in_set = in_set.union(old_result[pred]["OUT"])
|
|
2422
|
+
|
|
2423
|
+
new_result[node]["IN"] = in_set
|
|
2424
|
+
|
|
2425
|
+
def_info = rda_table[node]["def"] if node in rda_table else set()
|
|
2426
|
+
names_defined = [d.name for d in def_info]
|
|
2427
|
+
|
|
2428
|
+
surviving_defs = set()
|
|
2429
|
+
for incoming_def in in_set:
|
|
2430
|
+
if incoming_def.name not in names_defined:
|
|
2431
|
+
surviving_defs.add(incoming_def)
|
|
2432
|
+
|
|
2433
|
+
new_result[node]["OUT"] = surviving_defs.union(def_info)
|
|
2434
|
+
|
|
2435
|
+
ddiff = DeepDiff(old_result, new_result, ignore_order=True)
|
|
2436
|
+
if ddiff == {}:
|
|
2437
|
+
if debug:
|
|
2438
|
+
logger.info("RDA: Converged in {} iterations", iteration)
|
|
2439
|
+
break
|
|
2440
|
+
|
|
2441
|
+
old_result = copy.deepcopy(new_result)
|
|
2442
|
+
|
|
2443
|
+
return new_result
|
|
2444
|
+
|
|
2445
|
+
|
|
2446
|
+
def add_edge(final_graph, source, target, attrib=None):
|
|
2447
|
+
if attrib is not None:
|
|
2448
|
+
used_def = attrib.get("used_def", None)
|
|
2449
|
+
edge_type = attrib.get("edge_type", None)
|
|
2450
|
+
dataflow_type = attrib.get("dataflow_type", None)
|
|
2451
|
+
|
|
2452
|
+
for u, v, k, data in final_graph.edges(keys=True, data=True):
|
|
2453
|
+
if (
|
|
2454
|
+
u == source
|
|
2455
|
+
and v == target
|
|
2456
|
+
and data.get("used_def") == used_def
|
|
2457
|
+
and data.get("edge_type") == edge_type
|
|
2458
|
+
and data.get("dataflow_type") == dataflow_type
|
|
2459
|
+
):
|
|
2460
|
+
return
|
|
2461
|
+
|
|
2462
|
+
final_graph.add_edge(source, target)
|
|
2463
|
+
if attrib is not None:
|
|
2464
|
+
edge_keys = [
|
|
2465
|
+
k for u, v, k in final_graph.edges(keys=True) if u == source and v == target
|
|
2466
|
+
]
|
|
2467
|
+
if edge_keys:
|
|
2468
|
+
edge_key = max(edge_keys)
|
|
2469
|
+
else:
|
|
2470
|
+
edge_key = 0
|
|
2471
|
+
nx.set_edge_attributes(final_graph, {(source, target, edge_key): attrib})
|
|
2472
|
+
|
|
2473
|
+
|
|
2474
|
+
def name_match_with_fields(use_name, def_name):
|
|
2475
|
+
if use_name == def_name:
|
|
2476
|
+
return True
|
|
2477
|
+
|
|
2478
|
+
if "." in use_name:
|
|
2479
|
+
base_obj = use_name.split(".")[0]
|
|
2480
|
+
if def_name == base_obj:
|
|
2481
|
+
return True
|
|
2482
|
+
|
|
2483
|
+
return False
|
|
2484
|
+
|
|
2485
|
+
|
|
2486
|
+
def get_required_edges_from_def_to_use(
|
|
2487
|
+
index,
|
|
2488
|
+
cfg,
|
|
2489
|
+
rda_solution,
|
|
2490
|
+
rda_table,
|
|
2491
|
+
graph_nodes,
|
|
2492
|
+
processed_edges,
|
|
2493
|
+
properties,
|
|
2494
|
+
lambda_map=None,
|
|
2495
|
+
node_list=None,
|
|
2496
|
+
parser=None,
|
|
2497
|
+
):
|
|
2498
|
+
if lambda_map is None:
|
|
2499
|
+
lambda_map = {}
|
|
2500
|
+
if node_list is None:
|
|
2501
|
+
node_list = {}
|
|
2502
|
+
final_graph = copy.deepcopy(cfg)
|
|
2503
|
+
final_graph.remove_edges_from(list(final_graph.edges()))
|
|
2504
|
+
|
|
2505
|
+
for node in graph_nodes:
|
|
2506
|
+
if node not in rda_table:
|
|
2507
|
+
continue
|
|
2508
|
+
|
|
2509
|
+
use_info = rda_table[node]["use"]
|
|
2510
|
+
|
|
2511
|
+
for used in use_info:
|
|
2512
|
+
if isinstance(used, Literal):
|
|
2513
|
+
used.satisfied = True
|
|
2514
|
+
continue
|
|
2515
|
+
|
|
2516
|
+
matching_defs = []
|
|
2517
|
+
matching_field_defs = []
|
|
2518
|
+
|
|
2519
|
+
for available_def in rda_solution[node]["IN"]:
|
|
2520
|
+
if parser.src_language != "cpp":
|
|
2521
|
+
if hasattr(available_def, "declaration") and hasattr(
|
|
2522
|
+
available_def, "has_initializer"
|
|
2523
|
+
):
|
|
2524
|
+
if (
|
|
2525
|
+
available_def.declaration
|
|
2526
|
+
and not available_def.has_initializer
|
|
2527
|
+
):
|
|
2528
|
+
continue
|
|
2529
|
+
|
|
2530
|
+
if available_def.name == used.name:
|
|
2531
|
+
if scope_check(available_def.scope, used.variable_scope):
|
|
2532
|
+
matching_defs.append(available_def)
|
|
2533
|
+
elif "." in used.name or "." in available_def.name:
|
|
2534
|
+
if name_match_with_fields(used.name, available_def.name):
|
|
2535
|
+
if scope_check(available_def.scope, used.variable_scope):
|
|
2536
|
+
matching_field_defs.append(available_def)
|
|
2537
|
+
|
|
2538
|
+
def_info = rda_table[node]["def"] if node in rda_table else []
|
|
2539
|
+
defines_same_var = any(d.name == used.name for d in def_info)
|
|
2540
|
+
|
|
2541
|
+
if defines_same_var:
|
|
2542
|
+
if matching_defs:
|
|
2543
|
+
node_key = (
|
|
2544
|
+
read_index(index, node) if node in index.values() else None
|
|
2545
|
+
)
|
|
2546
|
+
ast_node = (
|
|
2547
|
+
node_list.get(node_key) if node_list and node_key else None
|
|
2548
|
+
)
|
|
2549
|
+
|
|
2550
|
+
has_loop_carried_def = any(d.line == node for d in matching_defs)
|
|
2551
|
+
|
|
2552
|
+
if (
|
|
2553
|
+
has_loop_carried_def
|
|
2554
|
+
and ast_node
|
|
2555
|
+
and is_node_inside_loop(ast_node)
|
|
2556
|
+
):
|
|
2557
|
+
add_edge(
|
|
2558
|
+
final_graph,
|
|
2559
|
+
node,
|
|
2560
|
+
node,
|
|
2561
|
+
{
|
|
2562
|
+
"dataflow_type": "loop_carried",
|
|
2563
|
+
"edge_type": "DFG_edge",
|
|
2564
|
+
"color": "#FFA500",
|
|
2565
|
+
"used_def": used.name,
|
|
2566
|
+
},
|
|
2567
|
+
)
|
|
2568
|
+
|
|
2569
|
+
for available_def in matching_defs:
|
|
2570
|
+
if getattr(
|
|
2571
|
+
available_def, "is_pointer_modification_at_call_site", False
|
|
2572
|
+
):
|
|
2573
|
+
continue
|
|
2574
|
+
if available_def.line != node:
|
|
2575
|
+
add_edge(
|
|
2576
|
+
final_graph,
|
|
2577
|
+
available_def.line,
|
|
2578
|
+
node,
|
|
2579
|
+
{
|
|
2580
|
+
"dataflow_type": "comesFrom",
|
|
2581
|
+
"edge_type": "DFG_edge",
|
|
2582
|
+
"color": "#00A3FF",
|
|
2583
|
+
"used_def": used.name,
|
|
2584
|
+
},
|
|
2585
|
+
)
|
|
2586
|
+
used.satisfied = True
|
|
2587
|
+
elif matching_defs:
|
|
2588
|
+
for available_def in matching_defs:
|
|
2589
|
+
if getattr(
|
|
2590
|
+
available_def, "is_pointer_modification_at_call_site", False
|
|
2591
|
+
):
|
|
2592
|
+
continue
|
|
2593
|
+
if available_def.line != node:
|
|
2594
|
+
add_edge(
|
|
2595
|
+
final_graph,
|
|
2596
|
+
available_def.line,
|
|
2597
|
+
node,
|
|
2598
|
+
{
|
|
2599
|
+
"dataflow_type": "comesFrom",
|
|
2600
|
+
"edge_type": "DFG_edge",
|
|
2601
|
+
"color": "#00A3FF",
|
|
2602
|
+
"used_def": used.name,
|
|
2603
|
+
},
|
|
2604
|
+
)
|
|
2605
|
+
used.satisfied = True
|
|
2606
|
+
if matching_defs:
|
|
2607
|
+
used.satisfied = True
|
|
2608
|
+
elif matching_field_defs:
|
|
2609
|
+
for available_def in matching_field_defs:
|
|
2610
|
+
if name_match_with_fields(used.name, available_def.name):
|
|
2611
|
+
if scope_check(available_def.scope, used.variable_scope):
|
|
2612
|
+
if available_def.line != node:
|
|
2613
|
+
add_edge(
|
|
2614
|
+
final_graph,
|
|
2615
|
+
available_def.line,
|
|
2616
|
+
node,
|
|
2617
|
+
{
|
|
2618
|
+
"dataflow_type": "comesFrom",
|
|
2619
|
+
"edge_type": "DFG_edge",
|
|
2620
|
+
"color": "#00A3FF",
|
|
2621
|
+
"used_def": used.name,
|
|
2622
|
+
},
|
|
2623
|
+
)
|
|
2624
|
+
used.satisfied = True
|
|
2625
|
+
|
|
2626
|
+
if not used.satisfied:
|
|
2627
|
+
for def_node in graph_nodes:
|
|
2628
|
+
if def_node not in rda_table:
|
|
2629
|
+
continue
|
|
2630
|
+
for definition in rda_table[def_node]["def"]:
|
|
2631
|
+
names_match = False
|
|
2632
|
+
|
|
2633
|
+
if definition.name == used.name:
|
|
2634
|
+
names_match = True
|
|
2635
|
+
else:
|
|
2636
|
+
def_base = (
|
|
2637
|
+
definition.name.split("::")[-1]
|
|
2638
|
+
if "::" in definition.name
|
|
2639
|
+
else definition.name
|
|
2640
|
+
)
|
|
2641
|
+
used_base = (
|
|
2642
|
+
used.name.split("::")[-1]
|
|
2643
|
+
if "::" in used.name
|
|
2644
|
+
else used.name
|
|
2645
|
+
)
|
|
2646
|
+
|
|
2647
|
+
if def_base == used_base:
|
|
2648
|
+
if "::" in used.name:
|
|
2649
|
+
names_match = definition.name == used.name
|
|
2650
|
+
else:
|
|
2651
|
+
names_match = False
|
|
2652
|
+
|
|
2653
|
+
if names_match:
|
|
2654
|
+
node_type = (
|
|
2655
|
+
read_index(index, def_node)[-1]
|
|
2656
|
+
if def_node in index.values()
|
|
2657
|
+
else None
|
|
2658
|
+
)
|
|
2659
|
+
if node_type == "function_definition":
|
|
2660
|
+
func_scope = definition.scope
|
|
2661
|
+
func_line = definition.line
|
|
2662
|
+
namespace_scope = (
|
|
2663
|
+
func_scope[:-1]
|
|
2664
|
+
if len(func_scope) > 1
|
|
2665
|
+
else func_scope
|
|
2666
|
+
)
|
|
2667
|
+
|
|
2668
|
+
return_nodes = []
|
|
2669
|
+
|
|
2670
|
+
for rnode in graph_nodes:
|
|
2671
|
+
rnode_type = (
|
|
2672
|
+
read_index(index, rnode)[-1]
|
|
2673
|
+
if rnode in index.values()
|
|
2674
|
+
else None
|
|
2675
|
+
)
|
|
2676
|
+
if rnode_type == "return_statement":
|
|
2677
|
+
has_return_value = False
|
|
2678
|
+
return_scope = None
|
|
2679
|
+
return_line = None
|
|
2680
|
+
|
|
2681
|
+
if rnode in rda_table and rda_table[rnode].get(
|
|
2682
|
+
"use"
|
|
2683
|
+
):
|
|
2684
|
+
for ret_use in rda_table[rnode]["use"]:
|
|
2685
|
+
return_scope = ret_use.scope
|
|
2686
|
+
return_line = ret_use.line
|
|
2687
|
+
has_return_value = True
|
|
2688
|
+
break
|
|
2689
|
+
|
|
2690
|
+
if (
|
|
2691
|
+
has_return_value
|
|
2692
|
+
and return_scope
|
|
2693
|
+
and return_line
|
|
2694
|
+
):
|
|
2695
|
+
namespace_matches = len(
|
|
2696
|
+
return_scope
|
|
2697
|
+
) == len(namespace_scope) and all(
|
|
2698
|
+
return_scope[i] == namespace_scope[i]
|
|
2699
|
+
for i in range(len(namespace_scope))
|
|
2700
|
+
)
|
|
2701
|
+
|
|
2702
|
+
if (
|
|
2703
|
+
namespace_matches
|
|
2704
|
+
and return_line > func_line
|
|
2705
|
+
):
|
|
2706
|
+
is_in_this_function = True
|
|
2707
|
+
|
|
2708
|
+
next_func_line = float("inf")
|
|
2709
|
+
for other_node in graph_nodes:
|
|
2710
|
+
other_type = (
|
|
2711
|
+
read_index(index, other_node)[
|
|
2712
|
+
-1
|
|
2713
|
+
]
|
|
2714
|
+
if other_node in index.values()
|
|
2715
|
+
else None
|
|
2716
|
+
)
|
|
2717
|
+
if (
|
|
2718
|
+
other_type
|
|
2719
|
+
== "function_definition"
|
|
2720
|
+
and other_node != def_node
|
|
2721
|
+
):
|
|
2722
|
+
if other_node in rda_table:
|
|
2723
|
+
for other_def in rda_table[
|
|
2724
|
+
other_node
|
|
2725
|
+
].get("def", []):
|
|
2726
|
+
other_scope = (
|
|
2727
|
+
other_def.scope
|
|
2728
|
+
)
|
|
2729
|
+
other_line = (
|
|
2730
|
+
other_def.line
|
|
2731
|
+
)
|
|
2732
|
+
other_namespace = (
|
|
2733
|
+
other_scope[:-1]
|
|
2734
|
+
if len(other_scope)
|
|
2735
|
+
> 1
|
|
2736
|
+
else other_scope
|
|
2737
|
+
)
|
|
2738
|
+
if (
|
|
2739
|
+
other_namespace
|
|
2740
|
+
== namespace_scope
|
|
2741
|
+
and other_line
|
|
2742
|
+
> func_line
|
|
2743
|
+
and other_line
|
|
2744
|
+
< next_func_line
|
|
2745
|
+
):
|
|
2746
|
+
next_func_line = (
|
|
2747
|
+
other_line
|
|
2748
|
+
)
|
|
2749
|
+
|
|
2750
|
+
if return_line < next_func_line:
|
|
2751
|
+
return_nodes.append(rnode)
|
|
2752
|
+
|
|
2753
|
+
if return_nodes:
|
|
2754
|
+
for ret_node in return_nodes:
|
|
2755
|
+
if ret_node != node:
|
|
2756
|
+
add_edge(
|
|
2757
|
+
final_graph,
|
|
2758
|
+
ret_node,
|
|
2759
|
+
node,
|
|
2760
|
+
{
|
|
2761
|
+
"dataflow_type": "comesFrom",
|
|
2762
|
+
"edge_type": "DFG_edge",
|
|
2763
|
+
"color": "#00A3FF",
|
|
2764
|
+
"used_def": used.name,
|
|
2765
|
+
},
|
|
2766
|
+
)
|
|
2767
|
+
used.satisfied = True
|
|
2768
|
+
break
|
|
2769
|
+
|
|
2770
|
+
if not used.satisfied:
|
|
2771
|
+
for def_node in graph_nodes:
|
|
2772
|
+
if def_node not in rda_table:
|
|
2773
|
+
continue
|
|
2774
|
+
for definition in rda_table[def_node]["def"]:
|
|
2775
|
+
if definition.name == used.name:
|
|
2776
|
+
if definition.scope == [0] and scope_check(
|
|
2777
|
+
definition.scope, used.scope
|
|
2778
|
+
):
|
|
2779
|
+
if definition.line != node:
|
|
2780
|
+
add_edge(
|
|
2781
|
+
final_graph,
|
|
2782
|
+
definition.line,
|
|
2783
|
+
node,
|
|
2784
|
+
{
|
|
2785
|
+
"dataflow_type": "comesFrom",
|
|
2786
|
+
"edge_type": "DFG_edge",
|
|
2787
|
+
"color": "#00A3FF",
|
|
2788
|
+
"used_def": used.name,
|
|
2789
|
+
},
|
|
2790
|
+
)
|
|
2791
|
+
used.satisfied = True
|
|
2792
|
+
break
|
|
2793
|
+
if used.satisfied:
|
|
2794
|
+
break
|
|
2795
|
+
|
|
2796
|
+
if not used.satisfied and "::" in used.name:
|
|
2797
|
+
qualified_parts = used.name.split("::")
|
|
2798
|
+
var_name = qualified_parts[-1]
|
|
2799
|
+
|
|
2800
|
+
for def_node in graph_nodes:
|
|
2801
|
+
if def_node not in rda_table:
|
|
2802
|
+
continue
|
|
2803
|
+
for definition in rda_table[def_node]["def"]:
|
|
2804
|
+
if definition.name == var_name:
|
|
2805
|
+
if len(definition.scope) >= 2:
|
|
2806
|
+
if definition.line != node:
|
|
2807
|
+
add_edge(
|
|
2808
|
+
final_graph,
|
|
2809
|
+
definition.line,
|
|
2810
|
+
node,
|
|
2811
|
+
{
|
|
2812
|
+
"dataflow_type": "comesFrom",
|
|
2813
|
+
"edge_type": "DFG_edge",
|
|
2814
|
+
"color": "#00A3FF",
|
|
2815
|
+
"used_def": used.name,
|
|
2816
|
+
},
|
|
2817
|
+
)
|
|
2818
|
+
used.satisfied = True
|
|
2819
|
+
break
|
|
2820
|
+
if used.satisfied:
|
|
2821
|
+
break
|
|
2822
|
+
|
|
2823
|
+
if not used.satisfied:
|
|
2824
|
+
for def_node in graph_nodes:
|
|
2825
|
+
if def_node not in rda_table:
|
|
2826
|
+
continue
|
|
2827
|
+
for definition in rda_table[def_node]["def"]:
|
|
2828
|
+
if definition.name == used.name:
|
|
2829
|
+
if len(definition.scope) >= 2 and len(used.scope) >= 2:
|
|
2830
|
+
if (
|
|
2831
|
+
definition.scope[0] == used.scope[0]
|
|
2832
|
+
and definition.scope[1] == used.scope[1]
|
|
2833
|
+
):
|
|
2834
|
+
if definition.line != node:
|
|
2835
|
+
add_edge(
|
|
2836
|
+
final_graph,
|
|
2837
|
+
definition.line,
|
|
2838
|
+
node,
|
|
2839
|
+
{
|
|
2840
|
+
"dataflow_type": "comesFrom",
|
|
2841
|
+
"edge_type": "DFG_edge",
|
|
2842
|
+
"color": "#00A3FF",
|
|
2843
|
+
"used_def": used.name,
|
|
2844
|
+
},
|
|
2845
|
+
)
|
|
2846
|
+
used.satisfied = True
|
|
2847
|
+
break
|
|
2848
|
+
if used.satisfied:
|
|
2849
|
+
break
|
|
2850
|
+
|
|
2851
|
+
if properties.get("last_def", False):
|
|
2852
|
+
killed_defs = rda_solution[node]["IN"] - rda_solution[node]["OUT"]
|
|
2853
|
+
for killed_def in killed_defs:
|
|
2854
|
+
node_type = read_index(index, node)[-1]
|
|
2855
|
+
def_node_type = read_index(index, killed_def.line)[-1]
|
|
2856
|
+
ignore_types = [
|
|
2857
|
+
"for_statement",
|
|
2858
|
+
"for_range_loop",
|
|
2859
|
+
"while_statement",
|
|
2860
|
+
"if_statement",
|
|
2861
|
+
"switch_statement",
|
|
2862
|
+
]
|
|
2863
|
+
if node_type not in ignore_types and def_node_type not in ignore_types:
|
|
2864
|
+
add_edge(
|
|
2865
|
+
final_graph,
|
|
2866
|
+
killed_def.line,
|
|
2867
|
+
node,
|
|
2868
|
+
{"color": "orange", "dataflow_type": "lastDef"},
|
|
2869
|
+
)
|
|
2870
|
+
|
|
2871
|
+
for edge in processed_edges:
|
|
2872
|
+
edge_data = cfg.get_edge_data(*edge)
|
|
2873
|
+
if edge_data and len(edge_data) > 0:
|
|
2874
|
+
edge_data = edge_data[0]
|
|
2875
|
+
label = edge_data.get("label", "")
|
|
2876
|
+
|
|
2877
|
+
if label == "constructor_call":
|
|
2878
|
+
source_node = node_list.get(read_index(index, edge[0]))
|
|
2879
|
+
obj_name = "this"
|
|
2880
|
+
if source_node and source_node.type == "declaration":
|
|
2881
|
+
for child in source_node.named_children:
|
|
2882
|
+
if child.type in [
|
|
2883
|
+
"init_declarator",
|
|
2884
|
+
"identifier",
|
|
2885
|
+
"type_identifier",
|
|
2886
|
+
]:
|
|
2887
|
+
if child.type == "init_declarator":
|
|
2888
|
+
decl = child.child_by_field_name("declarator")
|
|
2889
|
+
if decl and decl.type == "identifier":
|
|
2890
|
+
obj_name = st(decl)
|
|
2891
|
+
elif child.type == "identifier":
|
|
2892
|
+
obj_name = st(child)
|
|
2893
|
+
|
|
2894
|
+
add_edge(
|
|
2895
|
+
final_graph,
|
|
2896
|
+
edge[0],
|
|
2897
|
+
edge[1],
|
|
2898
|
+
{
|
|
2899
|
+
"dataflow_type": "constructor_call",
|
|
2900
|
+
"edge_type": "DFG_edge",
|
|
2901
|
+
"color": "#FF6B6B",
|
|
2902
|
+
"object_name": obj_name,
|
|
2903
|
+
},
|
|
2904
|
+
)
|
|
2905
|
+
|
|
2906
|
+
elif label == "base_constructor_call":
|
|
2907
|
+
add_edge(
|
|
2908
|
+
final_graph,
|
|
2909
|
+
edge[0],
|
|
2910
|
+
edge[1],
|
|
2911
|
+
{
|
|
2912
|
+
"dataflow_type": "base_constructor_call",
|
|
2913
|
+
"edge_type": "DFG_edge",
|
|
2914
|
+
"color": "#FF6B6B",
|
|
2915
|
+
"object_name": "this",
|
|
2916
|
+
},
|
|
2917
|
+
)
|
|
2918
|
+
|
|
2919
|
+
elif label == "scope_exit_destructor":
|
|
2920
|
+
add_edge(
|
|
2921
|
+
final_graph,
|
|
2922
|
+
edge[0],
|
|
2923
|
+
edge[1],
|
|
2924
|
+
{
|
|
2925
|
+
"dataflow_type": "destructor_call",
|
|
2926
|
+
"edge_type": "DFG_edge",
|
|
2927
|
+
"color": "#C44569",
|
|
2928
|
+
"object_name": "this",
|
|
2929
|
+
},
|
|
2930
|
+
)
|
|
2931
|
+
|
|
2932
|
+
elif label == "base_destructor_call":
|
|
2933
|
+
add_edge(
|
|
2934
|
+
final_graph,
|
|
2935
|
+
edge[0],
|
|
2936
|
+
edge[1],
|
|
2937
|
+
{
|
|
2938
|
+
"dataflow_type": "base_destructor_call",
|
|
2939
|
+
"edge_type": "DFG_edge",
|
|
2940
|
+
"color": "#C44569",
|
|
2941
|
+
"object_name": "this",
|
|
2942
|
+
},
|
|
2943
|
+
)
|
|
2944
|
+
|
|
2945
|
+
elif label == "virtual_call":
|
|
2946
|
+
source_node = node_list.get(read_index(index, edge[0]))
|
|
2947
|
+
obj_name = "this"
|
|
2948
|
+
|
|
2949
|
+
if source_node and source_node.type == "expression_statement":
|
|
2950
|
+
call_expr = (
|
|
2951
|
+
source_node.named_children[0]
|
|
2952
|
+
if source_node.named_children
|
|
2953
|
+
else None
|
|
2954
|
+
)
|
|
2955
|
+
if call_expr and call_expr.type == "call_expression":
|
|
2956
|
+
func_node = call_expr.child_by_field_name("function")
|
|
2957
|
+
if func_node and func_node.type == "field_expression":
|
|
2958
|
+
arg_node = func_node.child_by_field_name("argument")
|
|
2959
|
+
if arg_node:
|
|
2960
|
+
obj_name = st(arg_node)
|
|
2961
|
+
|
|
2962
|
+
add_edge(
|
|
2963
|
+
final_graph,
|
|
2964
|
+
edge[0],
|
|
2965
|
+
edge[1],
|
|
2966
|
+
{
|
|
2967
|
+
"dataflow_type": "virtual_dispatch",
|
|
2968
|
+
"edge_type": "DFG_edge",
|
|
2969
|
+
"color": "#4834DF",
|
|
2970
|
+
"object_name": obj_name,
|
|
2971
|
+
},
|
|
2972
|
+
)
|
|
2973
|
+
|
|
2974
|
+
elif label == "method_call":
|
|
2975
|
+
pass
|
|
2976
|
+
|
|
2977
|
+
else:
|
|
2978
|
+
if label in ["method_return", "function_return"]:
|
|
2979
|
+
add_edge(
|
|
2980
|
+
final_graph,
|
|
2981
|
+
edge[0],
|
|
2982
|
+
edge[1],
|
|
2983
|
+
{"dataflow_type": "parameter", "edge_type": "DFG_edge"},
|
|
2984
|
+
)
|
|
2985
|
+
|
|
2986
|
+
if lambda_map:
|
|
2987
|
+
param_to_lambda = {}
|
|
2988
|
+
|
|
2989
|
+
for call_node, func_def_node in processed_edges:
|
|
2990
|
+
if call_node not in rda_table:
|
|
2991
|
+
continue
|
|
2992
|
+
|
|
2993
|
+
uses = rda_table[call_node].get("use", [])
|
|
2994
|
+
|
|
2995
|
+
if func_def_node not in rda_table:
|
|
2996
|
+
continue
|
|
2997
|
+
params = rda_table[func_def_node].get("def", [])
|
|
2998
|
+
|
|
2999
|
+
node_type = (
|
|
3000
|
+
read_index(index, func_def_node)[-1]
|
|
3001
|
+
if func_def_node in index.values()
|
|
3002
|
+
else None
|
|
3003
|
+
)
|
|
3004
|
+
actual_params = (
|
|
3005
|
+
params[1:] if node_type == "function_definition" and params else params
|
|
3006
|
+
)
|
|
3007
|
+
|
|
3008
|
+
for used_var in uses:
|
|
3009
|
+
if not isinstance(used_var, Identifier):
|
|
3010
|
+
continue
|
|
3011
|
+
if used_var.method_call:
|
|
3012
|
+
continue
|
|
3013
|
+
|
|
3014
|
+
if used_var.name in lambda_map:
|
|
3015
|
+
for param in actual_params:
|
|
3016
|
+
if isinstance(param, Identifier) and not param.method_call:
|
|
3017
|
+
param_to_lambda[(param.name, func_def_node)] = used_var.name
|
|
3018
|
+
if debug:
|
|
3019
|
+
logger.info(
|
|
3020
|
+
f"Mapped parameter {param.name} in func {func_def_node} "
|
|
3021
|
+
f"to lambda {used_var.name}"
|
|
3022
|
+
)
|
|
3023
|
+
|
|
3024
|
+
for node in graph_nodes:
|
|
3025
|
+
if node not in rda_table:
|
|
3026
|
+
continue
|
|
3027
|
+
|
|
3028
|
+
uses = rda_table[node].get("use", [])
|
|
3029
|
+
|
|
3030
|
+
for used_var in uses:
|
|
3031
|
+
if not isinstance(used_var, Identifier):
|
|
3032
|
+
continue
|
|
3033
|
+
if not used_var.method_call:
|
|
3034
|
+
continue
|
|
3035
|
+
|
|
3036
|
+
node_type = (
|
|
3037
|
+
read_index(index, node)[-1] if node in index.values() else None
|
|
3038
|
+
)
|
|
3039
|
+
|
|
3040
|
+
reaching_defs = rda_solution[node]["IN"]
|
|
3041
|
+
for def_var in reaching_defs:
|
|
3042
|
+
if not isinstance(def_var, Identifier):
|
|
3043
|
+
continue
|
|
3044
|
+
if def_var.name != used_var.name:
|
|
3045
|
+
continue
|
|
3046
|
+
|
|
3047
|
+
key = (def_var.name, def_var.line)
|
|
3048
|
+
if key in param_to_lambda:
|
|
3049
|
+
lambda_var = param_to_lambda[key]
|
|
3050
|
+
lambda_info = lambda_map[lambda_var]
|
|
3051
|
+
|
|
3052
|
+
for body_node in lambda_info["body_nodes"]:
|
|
3053
|
+
add_edge(
|
|
3054
|
+
final_graph,
|
|
3055
|
+
node,
|
|
3056
|
+
body_node,
|
|
3057
|
+
{
|
|
3058
|
+
"dataflow_type": "lambda_call",
|
|
3059
|
+
"edge_type": "DFG_edge",
|
|
3060
|
+
"color": "#FF6B6B",
|
|
3061
|
+
"lambda_var": lambda_var,
|
|
3062
|
+
},
|
|
3063
|
+
)
|
|
3064
|
+
if debug:
|
|
3065
|
+
logger.info(
|
|
3066
|
+
f"Added lambda call edge: {node} -> {body_node} "
|
|
3067
|
+
f"(calling lambda {lambda_var})"
|
|
3068
|
+
)
|
|
3069
|
+
|
|
3070
|
+
return final_graph
|
|
3071
|
+
|
|
3072
|
+
|
|
3073
|
+
def rda_cfg_map(rda_solution, CFG_results):
|
|
3074
|
+
"""Create debug graph showing RDA info on CFG edges"""
|
|
3075
|
+
graph = copy.deepcopy(CFG_results.graph)
|
|
3076
|
+
|
|
3077
|
+
for edge in list(graph.edges):
|
|
3078
|
+
out_set = rda_solution[edge[0]]["OUT"]
|
|
3079
|
+
in_set = rda_solution[edge[1]]["IN"]
|
|
3080
|
+
|
|
3081
|
+
intersection = [d for d in out_set if d in in_set]
|
|
3082
|
+
|
|
3083
|
+
if intersection:
|
|
3084
|
+
edge_data = graph.get_edge_data(*edge)
|
|
3085
|
+
edge_data["rda_info"] = ",".join([str(d) for d in intersection])
|
|
3086
|
+
else:
|
|
3087
|
+
graph.remove_edge(*edge)
|
|
3088
|
+
|
|
3089
|
+
return graph
|
|
3090
|
+
|
|
3091
|
+
|
|
3092
|
+
def collect_call_site_information(parser, function_metadata, cfg_graph):
|
|
3093
|
+
"""
|
|
3094
|
+
Collect information about function call sites for interprocedural analysis.
|
|
3095
|
+
|
|
3096
|
+
For each call site, track:
|
|
3097
|
+
- Which function is called
|
|
3098
|
+
- Which arguments are passed by reference (&var)
|
|
3099
|
+
- The mapping of actual arguments to formal parameters
|
|
3100
|
+
|
|
3101
|
+
Returns:
|
|
3102
|
+
List of dicts with call site information:
|
|
3103
|
+
{
|
|
3104
|
+
"call_site_node": AST node,
|
|
3105
|
+
"call_site_id": CFG node ID,
|
|
3106
|
+
"function_name": str,
|
|
3107
|
+
"pass_by_ref_args": [(arg_idx, var_name, var_node), ...]
|
|
3108
|
+
}
|
|
3109
|
+
"""
|
|
3110
|
+
call_sites = []
|
|
3111
|
+
index = parser.index
|
|
3112
|
+
|
|
3113
|
+
for node in traverse_tree(parser.tree.root_node):
|
|
3114
|
+
if node.type == "call_expression":
|
|
3115
|
+
function_name = None
|
|
3116
|
+
func_node = node.child_by_field_name("function")
|
|
3117
|
+
if func_node:
|
|
3118
|
+
if func_node.type == "identifier":
|
|
3119
|
+
function_name = st(func_node)
|
|
3120
|
+
elif func_node.type == "qualified_identifier":
|
|
3121
|
+
function_name = st(func_node)
|
|
3122
|
+
elif func_node.type == "field_expression":
|
|
3123
|
+
field_node = func_node.child_by_field_name("field")
|
|
3124
|
+
if field_node and field_node.type == "field_identifier":
|
|
3125
|
+
function_name = st(field_node)
|
|
3126
|
+
|
|
3127
|
+
if not function_name or function_name not in function_metadata:
|
|
3128
|
+
continue
|
|
3129
|
+
|
|
3130
|
+
parent_statement = return_first_parent_of_types(
|
|
3131
|
+
node, statement_types["node_list_type"]
|
|
3132
|
+
)
|
|
3133
|
+
if not parent_statement:
|
|
3134
|
+
continue
|
|
3135
|
+
|
|
3136
|
+
call_site_id = get_index(parent_statement, index)
|
|
3137
|
+
if call_site_id is None or call_site_id not in cfg_graph.nodes:
|
|
3138
|
+
continue
|
|
3139
|
+
|
|
3140
|
+
pass_by_ref_args = []
|
|
3141
|
+
args_node = node.child_by_field_name("arguments")
|
|
3142
|
+
if args_node:
|
|
3143
|
+
func_params = function_metadata[function_name]["params"]
|
|
3144
|
+
|
|
3145
|
+
for arg_idx, arg in enumerate(args_node.named_children):
|
|
3146
|
+
if arg_idx < len(func_params):
|
|
3147
|
+
param_name, is_pointer, is_reference, param_idx = func_params[
|
|
3148
|
+
arg_idx
|
|
3149
|
+
]
|
|
3150
|
+
|
|
3151
|
+
if is_pointer or is_reference:
|
|
3152
|
+
if arg.type == "pointer_expression":
|
|
3153
|
+
has_ampersand = False
|
|
3154
|
+
arg_node = None
|
|
3155
|
+
for arg_child in arg.children:
|
|
3156
|
+
if arg_child.type == "&":
|
|
3157
|
+
has_ampersand = True
|
|
3158
|
+
elif arg_child.is_named:
|
|
3159
|
+
arg_node = arg_child
|
|
3160
|
+
|
|
3161
|
+
if has_ampersand and arg_node:
|
|
3162
|
+
if arg_node.type in ["identifier", "this"]:
|
|
3163
|
+
var_name = st(arg_node)
|
|
3164
|
+
pass_by_ref_args.append(
|
|
3165
|
+
(arg_idx, var_name, arg_node)
|
|
3166
|
+
)
|
|
3167
|
+
elif is_reference and arg.type in ["identifier", "this"]:
|
|
3168
|
+
var_name = st(arg)
|
|
3169
|
+
pass_by_ref_args.append((arg_idx, var_name, arg))
|
|
3170
|
+
elif is_pointer and arg.type in ["identifier", "this"]:
|
|
3171
|
+
var_name = st(arg)
|
|
3172
|
+
arg_index = get_index(arg, index)
|
|
3173
|
+
if (
|
|
3174
|
+
arg_index
|
|
3175
|
+
and arg_index in parser.symbol_table["scope_map"]
|
|
3176
|
+
):
|
|
3177
|
+
pass_by_ref_args.append((arg_idx, var_name, arg))
|
|
3178
|
+
|
|
3179
|
+
if pass_by_ref_args:
|
|
3180
|
+
call_sites.append(
|
|
3181
|
+
{
|
|
3182
|
+
"call_site_node": node,
|
|
3183
|
+
"call_site_id": call_site_id,
|
|
3184
|
+
"function_name": function_name,
|
|
3185
|
+
"pass_by_ref_args": pass_by_ref_args,
|
|
3186
|
+
}
|
|
3187
|
+
)
|
|
3188
|
+
|
|
3189
|
+
return call_sites
|
|
3190
|
+
|
|
3191
|
+
|
|
3192
|
+
def find_modification_sites(parser, function_metadata_by_id, pointer_modifications):
|
|
3193
|
+
"""
|
|
3194
|
+
Find all modification sites for pointer/reference parameters inside functions.
|
|
3195
|
+
|
|
3196
|
+
For each function, find all statements where a pointer/reference parameter is modified.
|
|
3197
|
+
|
|
3198
|
+
Args:
|
|
3199
|
+
parser: C++ parser
|
|
3200
|
+
function_metadata_by_id: Dict mapping func_def_id -> metadata (from collect_function_metadata)
|
|
3201
|
+
pointer_modifications: Dict mapping func_name -> set of modified param indices
|
|
3202
|
+
|
|
3203
|
+
Returns:
|
|
3204
|
+
Tuple of:
|
|
3205
|
+
- modification_sites_by_name: Dict mapping function_name -> list of (param_idx, modification_node, statement_id)
|
|
3206
|
+
- modification_sites_by_id: Dict mapping func_def_id -> list of (param_idx, modification_node, statement_id)
|
|
3207
|
+
"""
|
|
3208
|
+
modification_sites_by_name = {}
|
|
3209
|
+
modification_sites_by_id = {}
|
|
3210
|
+
index = parser.index
|
|
3211
|
+
|
|
3212
|
+
for func_def_id, meta in function_metadata_by_id.items():
|
|
3213
|
+
modifications = []
|
|
3214
|
+
func_node = meta["node"]
|
|
3215
|
+
func_name = meta.get("func_name", "")
|
|
3216
|
+
modified_params = pointer_modifications.get(func_name, set())
|
|
3217
|
+
|
|
3218
|
+
param_name_to_idx = {}
|
|
3219
|
+
for param_name, is_pointer, is_reference, param_idx in meta["params"]:
|
|
3220
|
+
if (is_pointer or is_reference) and param_idx in modified_params:
|
|
3221
|
+
param_name_to_idx[param_name] = param_idx
|
|
3222
|
+
|
|
3223
|
+
if not param_name_to_idx:
|
|
3224
|
+
if func_name:
|
|
3225
|
+
modification_sites_by_name[func_name] = modifications
|
|
3226
|
+
modification_sites_by_id[func_def_id] = modifications
|
|
3227
|
+
continue
|
|
3228
|
+
|
|
3229
|
+
for node in traverse_tree(func_node):
|
|
3230
|
+
modification_param_idx = None
|
|
3231
|
+
mod_node = None
|
|
3232
|
+
|
|
3233
|
+
if node.type == "assignment_expression":
|
|
3234
|
+
left = node.child_by_field_name("left")
|
|
3235
|
+
if left:
|
|
3236
|
+
if left.type == "pointer_expression":
|
|
3237
|
+
arg = left.child_by_field_name("argument")
|
|
3238
|
+
if arg and arg.type in ["identifier", "this"]:
|
|
3239
|
+
var_name = st(arg)
|
|
3240
|
+
if var_name in param_name_to_idx:
|
|
3241
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3242
|
+
mod_node = node
|
|
3243
|
+
|
|
3244
|
+
elif left.type == "subscript_expression":
|
|
3245
|
+
array_arg = left.child_by_field_name("argument")
|
|
3246
|
+
if array_arg and array_arg.type in ["identifier", "this"]:
|
|
3247
|
+
var_name = st(array_arg)
|
|
3248
|
+
if var_name in param_name_to_idx:
|
|
3249
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3250
|
+
mod_node = node
|
|
3251
|
+
|
|
3252
|
+
elif left.type in ["identifier", "this"]:
|
|
3253
|
+
var_name = st(left)
|
|
3254
|
+
if var_name in param_name_to_idx:
|
|
3255
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3256
|
+
mod_node = node
|
|
3257
|
+
|
|
3258
|
+
elif node.type == "update_expression":
|
|
3259
|
+
arg = node.child_by_field_name("argument")
|
|
3260
|
+
if arg:
|
|
3261
|
+
if arg.type == "parenthesized_expression":
|
|
3262
|
+
inner_children = [c for c in arg.named_children if c.is_named]
|
|
3263
|
+
if inner_children:
|
|
3264
|
+
arg = inner_children[0]
|
|
3265
|
+
|
|
3266
|
+
if arg.type == "pointer_expression":
|
|
3267
|
+
inner_arg = arg.child_by_field_name("argument")
|
|
3268
|
+
if inner_arg and inner_arg.type in ["identifier", "this"]:
|
|
3269
|
+
var_name = st(inner_arg)
|
|
3270
|
+
if var_name in param_name_to_idx:
|
|
3271
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3272
|
+
mod_node = node
|
|
3273
|
+
elif arg.type == "subscript_expression":
|
|
3274
|
+
array_arg = arg.child_by_field_name("argument")
|
|
3275
|
+
if array_arg and array_arg.type in ["identifier", "this"]:
|
|
3276
|
+
var_name = st(array_arg)
|
|
3277
|
+
if var_name in param_name_to_idx:
|
|
3278
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3279
|
+
mod_node = node
|
|
3280
|
+
elif arg.type in ["identifier", "this"]:
|
|
3281
|
+
var_name = st(arg)
|
|
3282
|
+
if var_name in param_name_to_idx:
|
|
3283
|
+
modification_param_idx = param_name_to_idx[var_name]
|
|
3284
|
+
mod_node = node
|
|
3285
|
+
|
|
3286
|
+
if modification_param_idx is not None and mod_node is not None:
|
|
3287
|
+
parent_statement = return_first_parent_of_types(
|
|
3288
|
+
mod_node, statement_types["node_list_type"]
|
|
3289
|
+
)
|
|
3290
|
+
if parent_statement:
|
|
3291
|
+
statement_id = get_index(parent_statement, index)
|
|
3292
|
+
if statement_id is not None:
|
|
3293
|
+
modifications.append(
|
|
3294
|
+
(modification_param_idx, mod_node, statement_id)
|
|
3295
|
+
)
|
|
3296
|
+
|
|
3297
|
+
if func_name:
|
|
3298
|
+
modification_sites_by_name[func_name] = modifications
|
|
3299
|
+
modification_sites_by_id[func_def_id] = modifications
|
|
3300
|
+
|
|
3301
|
+
return modification_sites_by_name, modification_sites_by_id
|
|
3302
|
+
|
|
3303
|
+
|
|
3304
|
+
def get_cfg_call_targets(cfg_graph, call_site_id):
|
|
3305
|
+
"""
|
|
3306
|
+
Get the function definition IDs that are called from a given call site,
|
|
3307
|
+
based on CFG edges (method_call, virtual_call, function_call).
|
|
3308
|
+
|
|
3309
|
+
This uses the CFG's resolution of virtual dispatch, which correctly handles
|
|
3310
|
+
pointer_targets to determine the actual concrete type being called.
|
|
3311
|
+
|
|
3312
|
+
Args:
|
|
3313
|
+
cfg_graph: The CFG graph
|
|
3314
|
+
call_site_id: The call site node ID
|
|
3315
|
+
|
|
3316
|
+
Returns:
|
|
3317
|
+
Set of function definition IDs that are actually called from this call site
|
|
3318
|
+
"""
|
|
3319
|
+
target_func_ids = set()
|
|
3320
|
+
|
|
3321
|
+
for edge in cfg_graph.out_edges(call_site_id):
|
|
3322
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3323
|
+
if edge_data and len(edge_data) > 0:
|
|
3324
|
+
edge_data = edge_data[0]
|
|
3325
|
+
label = edge_data.get("label", "")
|
|
3326
|
+
|
|
3327
|
+
if (
|
|
3328
|
+
label.startswith("method_call")
|
|
3329
|
+
or label.startswith("virtual_call")
|
|
3330
|
+
or label.startswith("function_call")
|
|
3331
|
+
):
|
|
3332
|
+
target_func_ids.add(edge[1])
|
|
3333
|
+
|
|
3334
|
+
return target_func_ids
|
|
3335
|
+
|
|
3336
|
+
|
|
3337
|
+
def add_interprocedural_edges(
|
|
3338
|
+
final_graph,
|
|
3339
|
+
parser,
|
|
3340
|
+
call_sites,
|
|
3341
|
+
modification_sites_by_id,
|
|
3342
|
+
function_metadata,
|
|
3343
|
+
cfg_graph,
|
|
3344
|
+
rda_table,
|
|
3345
|
+
):
|
|
3346
|
+
"""
|
|
3347
|
+
Add interprocedural DFG edges for pass-by-reference.
|
|
3348
|
+
|
|
3349
|
+
For each call site where &var or reference is passed to a pointer/reference parameter:
|
|
3350
|
+
1. Use CFG edges to determine which function(s) are actually called (handles virtual dispatch)
|
|
3351
|
+
2. Add edges from modification sites inside the ACTUALLY CALLED function to uses after the call
|
|
3352
|
+
|
|
3353
|
+
This function uses CFG edge information to correctly resolve virtual dispatch,
|
|
3354
|
+
ensuring that only modifications from the concrete type's implementation are connected.
|
|
3355
|
+
|
|
3356
|
+
Args:
|
|
3357
|
+
final_graph: The DFG graph to add edges to
|
|
3358
|
+
parser: C++ parser
|
|
3359
|
+
call_sites: List of call site information from collect_call_site_information()
|
|
3360
|
+
modification_sites_by_id: Dict mapping func_def_id -> list of modifications
|
|
3361
|
+
function_metadata: Dict from collect_function_metadata()
|
|
3362
|
+
cfg_graph: Control flow graph (contains virtual dispatch resolution)
|
|
3363
|
+
rda_table: RDA table with def/use information
|
|
3364
|
+
"""
|
|
3365
|
+
index = parser.index
|
|
3366
|
+
|
|
3367
|
+
for call_site_info in call_sites:
|
|
3368
|
+
call_site_id = call_site_info["call_site_id"]
|
|
3369
|
+
function_name = call_site_info["function_name"]
|
|
3370
|
+
pass_by_ref_args = call_site_info["pass_by_ref_args"]
|
|
3371
|
+
|
|
3372
|
+
target_func_ids = get_cfg_call_targets(cfg_graph, call_site_id)
|
|
3373
|
+
|
|
3374
|
+
if not target_func_ids:
|
|
3375
|
+
continue
|
|
3376
|
+
|
|
3377
|
+
for arg_idx, var_name, var_node in pass_by_ref_args:
|
|
3378
|
+
all_param_mods = []
|
|
3379
|
+
|
|
3380
|
+
for func_def_id in target_func_ids:
|
|
3381
|
+
mods = modification_sites_by_id.get(func_def_id, [])
|
|
3382
|
+
for mod_param_idx, mod_node, mod_statement_id in mods:
|
|
3383
|
+
if mod_param_idx == arg_idx:
|
|
3384
|
+
all_param_mods.append(
|
|
3385
|
+
(mod_param_idx, mod_node, mod_statement_id, func_def_id)
|
|
3386
|
+
)
|
|
3387
|
+
|
|
3388
|
+
if not all_param_mods:
|
|
3389
|
+
continue
|
|
3390
|
+
|
|
3391
|
+
reaching_mods = []
|
|
3392
|
+
|
|
3393
|
+
for (
|
|
3394
|
+
mod_param_idx,
|
|
3395
|
+
mod_node,
|
|
3396
|
+
mod_statement_id,
|
|
3397
|
+
func_def_id,
|
|
3398
|
+
) in all_param_mods:
|
|
3399
|
+
is_killed = False
|
|
3400
|
+
|
|
3401
|
+
func_mods = [
|
|
3402
|
+
(m_idx, m_node, m_id)
|
|
3403
|
+
for m_idx, m_node, m_id, f_id in all_param_mods
|
|
3404
|
+
if f_id == func_def_id and m_idx == mod_param_idx
|
|
3405
|
+
]
|
|
3406
|
+
|
|
3407
|
+
visited_in_func = set()
|
|
3408
|
+
queue_in_func = [mod_statement_id]
|
|
3409
|
+
|
|
3410
|
+
while queue_in_func:
|
|
3411
|
+
current = queue_in_func.pop(0)
|
|
3412
|
+
if current in visited_in_func:
|
|
3413
|
+
continue
|
|
3414
|
+
visited_in_func.add(current)
|
|
3415
|
+
|
|
3416
|
+
for edge in cfg_graph.out_edges(current):
|
|
3417
|
+
successor = edge[1]
|
|
3418
|
+
|
|
3419
|
+
if successor in visited_in_func:
|
|
3420
|
+
continue
|
|
3421
|
+
|
|
3422
|
+
for other_mod_idx, other_mod_node, other_mod_id in func_mods:
|
|
3423
|
+
if (
|
|
3424
|
+
other_mod_id == successor
|
|
3425
|
+
and other_mod_id != mod_statement_id
|
|
3426
|
+
):
|
|
3427
|
+
is_killed = True
|
|
3428
|
+
break
|
|
3429
|
+
|
|
3430
|
+
if is_killed:
|
|
3431
|
+
break
|
|
3432
|
+
|
|
3433
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3434
|
+
if edge_data:
|
|
3435
|
+
edge_label = edge_data.get(0, {}).get("label", "")
|
|
3436
|
+
if "return" not in edge_label:
|
|
3437
|
+
queue_in_func.append(successor)
|
|
3438
|
+
|
|
3439
|
+
if is_killed:
|
|
3440
|
+
break
|
|
3441
|
+
|
|
3442
|
+
if not is_killed:
|
|
3443
|
+
reaching_mods.append((mod_param_idx, mod_node, mod_statement_id))
|
|
3444
|
+
|
|
3445
|
+
for mod_param_idx, mod_node, mod_statement_id in reaching_mods:
|
|
3446
|
+
successors = []
|
|
3447
|
+
visited = set()
|
|
3448
|
+
queue = [call_site_id]
|
|
3449
|
+
|
|
3450
|
+
while queue:
|
|
3451
|
+
current = queue.pop(0)
|
|
3452
|
+
if current in visited:
|
|
3453
|
+
continue
|
|
3454
|
+
visited.add(current)
|
|
3455
|
+
|
|
3456
|
+
uses_var = False
|
|
3457
|
+
defines_var = False
|
|
3458
|
+
if current != call_site_id and current in rda_table:
|
|
3459
|
+
for used in rda_table[current]["use"]:
|
|
3460
|
+
if used.name == var_name:
|
|
3461
|
+
uses_var = True
|
|
3462
|
+
successors.append(current)
|
|
3463
|
+
break
|
|
3464
|
+
|
|
3465
|
+
for defined in rda_table[current]["def"]:
|
|
3466
|
+
if defined.name == var_name:
|
|
3467
|
+
defines_var = True
|
|
3468
|
+
break
|
|
3469
|
+
|
|
3470
|
+
if (
|
|
3471
|
+
current == call_site_id
|
|
3472
|
+
or not uses_var
|
|
3473
|
+
or (uses_var and defines_var)
|
|
3474
|
+
):
|
|
3475
|
+
for edge in cfg_graph.out_edges(current):
|
|
3476
|
+
if edge[1] not in visited:
|
|
3477
|
+
queue.append(edge[1])
|
|
3478
|
+
|
|
3479
|
+
for use_site in successors:
|
|
3480
|
+
add_edge(
|
|
3481
|
+
final_graph,
|
|
3482
|
+
mod_statement_id,
|
|
3483
|
+
use_site,
|
|
3484
|
+
{
|
|
3485
|
+
"dataflow_type": "comesFrom",
|
|
3486
|
+
"edge_type": "DFG_edge",
|
|
3487
|
+
"color": "#00A3FF",
|
|
3488
|
+
"used_def": var_name,
|
|
3489
|
+
"interprocedural": "modification_to_use",
|
|
3490
|
+
},
|
|
3491
|
+
)
|
|
3492
|
+
|
|
3493
|
+
|
|
3494
|
+
def add_argument_parameter_edges(final_graph, parser, cfg_graph, rda_table):
|
|
3495
|
+
"""
|
|
3496
|
+
Add interprocedural DFG edges for argument-to-parameter data flow.
|
|
3497
|
+
|
|
3498
|
+
For each function call:
|
|
3499
|
+
1. Extract arguments from call site
|
|
3500
|
+
2. Extract parameters from function definition
|
|
3501
|
+
3. Create edges from arguments to parameters
|
|
3502
|
+
|
|
3503
|
+
Args:
|
|
3504
|
+
final_graph: The DFG graph to add edges to
|
|
3505
|
+
parser: C++ parser
|
|
3506
|
+
cfg_graph: Control flow graph with function_call edges
|
|
3507
|
+
rda_table: RDA table with def/use information
|
|
3508
|
+
"""
|
|
3509
|
+
index = parser.index
|
|
3510
|
+
node_list = {
|
|
3511
|
+
(node.start_point, node.end_point, node.type): node
|
|
3512
|
+
for node in traverse_tree(parser.tree, [])
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
for edge in list(cfg_graph.edges()):
|
|
3516
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3517
|
+
if edge_data and len(edge_data) > 0:
|
|
3518
|
+
edge_data = edge_data[0]
|
|
3519
|
+
label = edge_data.get("label", "")
|
|
3520
|
+
controlflow_type = edge_data.get("controlflow_type", "")
|
|
3521
|
+
|
|
3522
|
+
is_function_call = label.startswith(
|
|
3523
|
+
"function_call"
|
|
3524
|
+
) or controlflow_type.startswith("function_call")
|
|
3525
|
+
is_method_call = label.startswith(
|
|
3526
|
+
"method_call"
|
|
3527
|
+
) or controlflow_type.startswith("method_call")
|
|
3528
|
+
|
|
3529
|
+
if is_function_call or is_method_call:
|
|
3530
|
+
call_site_id = edge[0]
|
|
3531
|
+
func_def_id = edge[1]
|
|
3532
|
+
|
|
3533
|
+
call_site_node = node_list.get(read_index(index, call_site_id))
|
|
3534
|
+
func_def_node = node_list.get(read_index(index, func_def_id))
|
|
3535
|
+
|
|
3536
|
+
if not (call_site_node and func_def_node):
|
|
3537
|
+
continue
|
|
3538
|
+
|
|
3539
|
+
if func_def_node.type != "function_definition":
|
|
3540
|
+
continue
|
|
3541
|
+
|
|
3542
|
+
call_expr = None
|
|
3543
|
+
for child in traverse_tree(call_site_node, []):
|
|
3544
|
+
if child.type == "call_expression":
|
|
3545
|
+
call_expr = child
|
|
3546
|
+
break
|
|
3547
|
+
|
|
3548
|
+
if not call_expr:
|
|
3549
|
+
continue
|
|
3550
|
+
|
|
3551
|
+
args_node = call_expr.child_by_field_name("arguments")
|
|
3552
|
+
if not args_node or not args_node.named_children:
|
|
3553
|
+
continue
|
|
3554
|
+
|
|
3555
|
+
arguments = args_node.named_children
|
|
3556
|
+
|
|
3557
|
+
declarator = func_def_node.child_by_field_name("declarator")
|
|
3558
|
+
if not declarator:
|
|
3559
|
+
continue
|
|
3560
|
+
|
|
3561
|
+
func_declarator = declarator
|
|
3562
|
+
while func_declarator and func_declarator.type in [
|
|
3563
|
+
"pointer_declarator",
|
|
3564
|
+
"reference_declarator",
|
|
3565
|
+
]:
|
|
3566
|
+
for child in func_declarator.children:
|
|
3567
|
+
if child.type == "function_declarator":
|
|
3568
|
+
func_declarator = child
|
|
3569
|
+
break
|
|
3570
|
+
else:
|
|
3571
|
+
break
|
|
3572
|
+
|
|
3573
|
+
if not func_declarator or func_declarator.type != "function_declarator":
|
|
3574
|
+
continue
|
|
3575
|
+
|
|
3576
|
+
params_node = func_declarator.child_by_field_name("parameters")
|
|
3577
|
+
if not params_node or not params_node.named_children:
|
|
3578
|
+
continue
|
|
3579
|
+
|
|
3580
|
+
parameters = [
|
|
3581
|
+
p
|
|
3582
|
+
for p in params_node.named_children
|
|
3583
|
+
if p.type == "parameter_declaration"
|
|
3584
|
+
]
|
|
3585
|
+
|
|
3586
|
+
for idx, (arg, param) in enumerate(zip(arguments, parameters)):
|
|
3587
|
+
param_declarator = param.child_by_field_name("declarator")
|
|
3588
|
+
if not param_declarator:
|
|
3589
|
+
continue
|
|
3590
|
+
|
|
3591
|
+
is_pass_by_ref_or_ptr = False
|
|
3592
|
+
if param_declarator.type in [
|
|
3593
|
+
"pointer_declarator",
|
|
3594
|
+
"reference_declarator",
|
|
3595
|
+
"array_declarator",
|
|
3596
|
+
]:
|
|
3597
|
+
is_pass_by_ref_or_ptr = True
|
|
3598
|
+
|
|
3599
|
+
if not is_pass_by_ref_or_ptr:
|
|
3600
|
+
continue
|
|
3601
|
+
|
|
3602
|
+
param_id = param_declarator
|
|
3603
|
+
while param_id and param_id.type not in ["identifier"]:
|
|
3604
|
+
if param_id.type in [
|
|
3605
|
+
"pointer_declarator",
|
|
3606
|
+
"reference_declarator",
|
|
3607
|
+
"array_declarator",
|
|
3608
|
+
]:
|
|
3609
|
+
for child in param_id.named_children:
|
|
3610
|
+
if child.type == "identifier":
|
|
3611
|
+
param_id = child
|
|
3612
|
+
break
|
|
3613
|
+
elif child.type in [
|
|
3614
|
+
"pointer_declarator",
|
|
3615
|
+
"reference_declarator",
|
|
3616
|
+
"function_declarator",
|
|
3617
|
+
"array_declarator",
|
|
3618
|
+
]:
|
|
3619
|
+
param_id = child
|
|
3620
|
+
break
|
|
3621
|
+
else:
|
|
3622
|
+
break
|
|
3623
|
+
else:
|
|
3624
|
+
break
|
|
3625
|
+
|
|
3626
|
+
if not param_id or param_id.type != "identifier":
|
|
3627
|
+
continue
|
|
3628
|
+
|
|
3629
|
+
param_name = param_id.text.decode("utf-8")
|
|
3630
|
+
|
|
3631
|
+
add_edge(
|
|
3632
|
+
final_graph,
|
|
3633
|
+
call_site_id,
|
|
3634
|
+
func_def_id,
|
|
3635
|
+
{
|
|
3636
|
+
"dataflow_type": "comesFrom",
|
|
3637
|
+
"edge_type": "DFG_edge",
|
|
3638
|
+
"color": "#00A3FF",
|
|
3639
|
+
"used_def": param_name,
|
|
3640
|
+
"interprocedural": "argument_to_parameter",
|
|
3641
|
+
"argument_index": idx,
|
|
3642
|
+
},
|
|
3643
|
+
)
|
|
3644
|
+
|
|
3645
|
+
|
|
3646
|
+
def add_method_member_access_edges(final_graph, parser, cfg_graph, rda_table):
|
|
3647
|
+
"""
|
|
3648
|
+
Add interprocedural DFG edges for method member access.
|
|
3649
|
+
|
|
3650
|
+
When an object's method is called (obj.method()), create edges showing:
|
|
3651
|
+
1. The object flows to the method (as implicit 'this' parameter)
|
|
3652
|
+
2. Member accesses within the method (this->field) use the object's data
|
|
3653
|
+
|
|
3654
|
+
Args:
|
|
3655
|
+
final_graph: The DFG graph to add edges to
|
|
3656
|
+
parser: C++ parser
|
|
3657
|
+
cfg_graph: Control flow graph with method_call edges
|
|
3658
|
+
rda_table: RDA table with def/use information
|
|
3659
|
+
"""
|
|
3660
|
+
index = parser.index
|
|
3661
|
+
node_list = {
|
|
3662
|
+
(node.start_point, node.end_point, node.type): node
|
|
3663
|
+
for node in traverse_tree(parser.tree, [])
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
for edge in list(cfg_graph.edges()):
|
|
3667
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3668
|
+
if edge_data and len(edge_data) > 0:
|
|
3669
|
+
edge_data = edge_data[0]
|
|
3670
|
+
label = edge_data.get("label", "")
|
|
3671
|
+
object_name = edge_data.get("object_name", "")
|
|
3672
|
+
|
|
3673
|
+
if label in ["method_call", "virtual_call"]:
|
|
3674
|
+
call_site_id = edge[0]
|
|
3675
|
+
method_def_id = edge[1]
|
|
3676
|
+
|
|
3677
|
+
call_site_node = node_list.get(read_index(index, call_site_id))
|
|
3678
|
+
method_def_node = node_list.get(read_index(index, method_def_id))
|
|
3679
|
+
|
|
3680
|
+
if not (call_site_node and method_def_node):
|
|
3681
|
+
continue
|
|
3682
|
+
|
|
3683
|
+
if method_def_node.type != "function_definition":
|
|
3684
|
+
continue
|
|
3685
|
+
|
|
3686
|
+
method_body = method_def_node.child_by_field_name("body")
|
|
3687
|
+
if not method_body:
|
|
3688
|
+
continue
|
|
3689
|
+
|
|
3690
|
+
field_accesses = []
|
|
3691
|
+
for node in traverse_tree(method_body, []):
|
|
3692
|
+
if node.type == "field_expression":
|
|
3693
|
+
argument = node.child_by_field_name("argument")
|
|
3694
|
+
field = node.child_by_field_name("field")
|
|
3695
|
+
|
|
3696
|
+
if argument and field:
|
|
3697
|
+
arg_text = argument.text.decode("utf-8")
|
|
3698
|
+
if arg_text == "this" or arg_text == object_name:
|
|
3699
|
+
parent_stmt = node
|
|
3700
|
+
while (
|
|
3701
|
+
parent_stmt
|
|
3702
|
+
and parent_stmt.type
|
|
3703
|
+
not in statement_types["node_list_type"]
|
|
3704
|
+
):
|
|
3705
|
+
parent_stmt = parent_stmt.parent
|
|
3706
|
+
|
|
3707
|
+
if parent_stmt:
|
|
3708
|
+
stmt_id = get_index(parent_stmt, index)
|
|
3709
|
+
if stmt_id and stmt_id in cfg_graph.nodes:
|
|
3710
|
+
field_name = field.text.decode("utf-8")
|
|
3711
|
+
field_accesses.append((stmt_id, field_name))
|
|
3712
|
+
|
|
3713
|
+
class_members = set()
|
|
3714
|
+
parent = method_def_node.parent
|
|
3715
|
+
while parent:
|
|
3716
|
+
if parent.type in ["class_specifier", "struct_specifier"]:
|
|
3717
|
+
for node in traverse_tree(parent, []):
|
|
3718
|
+
if node.type == "field_declaration":
|
|
3719
|
+
declarator = node.child_by_field_name("declarator")
|
|
3720
|
+
if declarator:
|
|
3721
|
+
if declarator.type == "identifier":
|
|
3722
|
+
class_members.add(
|
|
3723
|
+
declarator.text.decode("utf-8")
|
|
3724
|
+
)
|
|
3725
|
+
elif declarator.type == "field_identifier":
|
|
3726
|
+
class_members.add(
|
|
3727
|
+
declarator.text.decode("utf-8")
|
|
3728
|
+
)
|
|
3729
|
+
for child in declarator.children:
|
|
3730
|
+
if child.type == "identifier":
|
|
3731
|
+
class_members.add(
|
|
3732
|
+
child.text.decode("utf-8")
|
|
3733
|
+
)
|
|
3734
|
+
break
|
|
3735
|
+
parent = parent.parent
|
|
3736
|
+
|
|
3737
|
+
for node_id in cfg_graph.nodes:
|
|
3738
|
+
node_key = (
|
|
3739
|
+
read_index(index, node_id)
|
|
3740
|
+
if node_id in index.values()
|
|
3741
|
+
else None
|
|
3742
|
+
)
|
|
3743
|
+
if not node_key:
|
|
3744
|
+
continue
|
|
3745
|
+
ast_node = node_list.get(node_key)
|
|
3746
|
+
if not ast_node:
|
|
3747
|
+
continue
|
|
3748
|
+
|
|
3749
|
+
is_in_method = False
|
|
3750
|
+
temp = ast_node
|
|
3751
|
+
while temp:
|
|
3752
|
+
if temp == method_body:
|
|
3753
|
+
is_in_method = True
|
|
3754
|
+
break
|
|
3755
|
+
temp = temp.parent
|
|
3756
|
+
|
|
3757
|
+
if not is_in_method:
|
|
3758
|
+
continue
|
|
3759
|
+
|
|
3760
|
+
if node_id in rda_table:
|
|
3761
|
+
for used in rda_table[node_id].get("use", []):
|
|
3762
|
+
if isinstance(used, Identifier):
|
|
3763
|
+
if used.core in class_members:
|
|
3764
|
+
field_accesses.append((node_id, used.core))
|
|
3765
|
+
|
|
3766
|
+
|
|
3767
|
+
def add_function_return_edges(final_graph, parser, cfg_graph, rda_table):
|
|
3768
|
+
"""
|
|
3769
|
+
Add interprocedural DFG edges for function return values.
|
|
3770
|
+
|
|
3771
|
+
For each function call where the return value is used:
|
|
3772
|
+
1. Find the return statement(s) in the called function
|
|
3773
|
+
2. Extract the returned expression/variable
|
|
3774
|
+
3. Find the variable being initialized at the call site
|
|
3775
|
+
4. Create edge from returned expression to initialized variable
|
|
3776
|
+
|
|
3777
|
+
Args:
|
|
3778
|
+
final_graph: The DFG graph to add edges to
|
|
3779
|
+
parser: C++ parser
|
|
3780
|
+
cfg_graph: Control flow graph with function_return/method_return edges
|
|
3781
|
+
rda_table: RDA table with def/use information
|
|
3782
|
+
"""
|
|
3783
|
+
index = parser.index
|
|
3784
|
+
node_list = {
|
|
3785
|
+
(node.start_point, node.end_point, node.type): node
|
|
3786
|
+
for node in traverse_tree(parser.tree, [])
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
for edge in list(cfg_graph.edges()):
|
|
3790
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3791
|
+
if edge_data and len(edge_data) > 0:
|
|
3792
|
+
edge_data = edge_data[0]
|
|
3793
|
+
label = edge_data.get("label", "")
|
|
3794
|
+
|
|
3795
|
+
if label in ["function_return", "method_return"]:
|
|
3796
|
+
return_node_id = edge[0]
|
|
3797
|
+
call_site_id = edge[1]
|
|
3798
|
+
|
|
3799
|
+
return_statement = node_list.get(read_index(index, return_node_id))
|
|
3800
|
+
call_site_node = node_list.get(read_index(index, call_site_id))
|
|
3801
|
+
|
|
3802
|
+
if not (return_statement and call_site_node):
|
|
3803
|
+
continue
|
|
3804
|
+
|
|
3805
|
+
if (
|
|
3806
|
+
return_statement.type != "return_statement"
|
|
3807
|
+
or not return_statement.named_children
|
|
3808
|
+
):
|
|
3809
|
+
continue
|
|
3810
|
+
|
|
3811
|
+
if not is_return_value_used(call_site_node):
|
|
3812
|
+
continue
|
|
3813
|
+
|
|
3814
|
+
returned_vars = []
|
|
3815
|
+
if return_node_id in rda_table:
|
|
3816
|
+
for used in rda_table[return_node_id].get("use", []):
|
|
3817
|
+
if isinstance(used, Identifier):
|
|
3818
|
+
returned_vars.append(used.name)
|
|
3819
|
+
|
|
3820
|
+
if not returned_vars:
|
|
3821
|
+
continue
|
|
3822
|
+
|
|
3823
|
+
initialized_vars = []
|
|
3824
|
+
if call_site_id in rda_table:
|
|
3825
|
+
for defined in rda_table[call_site_id].get("def", []):
|
|
3826
|
+
if isinstance(defined, Identifier):
|
|
3827
|
+
initialized_vars.append(defined.name)
|
|
3828
|
+
|
|
3829
|
+
for ret_var in returned_vars:
|
|
3830
|
+
for init_var in initialized_vars:
|
|
3831
|
+
add_edge(
|
|
3832
|
+
final_graph,
|
|
3833
|
+
return_node_id,
|
|
3834
|
+
call_site_id,
|
|
3835
|
+
{
|
|
3836
|
+
"dataflow_type": "comesFrom",
|
|
3837
|
+
"edge_type": "DFG_edge",
|
|
3838
|
+
"color": "#00A3FF",
|
|
3839
|
+
"used_def": init_var,
|
|
3840
|
+
"interprocedural": "return_to_caller",
|
|
3841
|
+
"returned_value": ret_var,
|
|
3842
|
+
},
|
|
3843
|
+
)
|
|
3844
|
+
|
|
3845
|
+
|
|
3846
|
+
def dfg_cpp(properties, CFG_results):
|
|
3847
|
+
"""
|
|
3848
|
+
Main driver for generating DFG for C++ programs.
|
|
3849
|
+
|
|
3850
|
+
Combines C procedural features with Java OOP features.
|
|
3851
|
+
|
|
3852
|
+
Args:
|
|
3853
|
+
properties: Configuration dict with DFG options
|
|
3854
|
+
CFG_results: CFG driver results with graph, parser, etc.
|
|
3855
|
+
|
|
3856
|
+
Returns:
|
|
3857
|
+
(final_graph, debug_graph, rda_table, rda_solution)
|
|
3858
|
+
"""
|
|
3859
|
+
parser = CFG_results.parser
|
|
3860
|
+
index = parser.index
|
|
3861
|
+
tree = parser.tree
|
|
3862
|
+
|
|
3863
|
+
cfg_graph = copy.deepcopy(CFG_results.graph)
|
|
3864
|
+
node_list = CFG_results.node_list
|
|
3865
|
+
|
|
3866
|
+
cfg_records = (
|
|
3867
|
+
CFG_results.CFG.records
|
|
3868
|
+
if hasattr(CFG_results, "CFG") and hasattr(CFG_results.CFG, "records")
|
|
3869
|
+
else {}
|
|
3870
|
+
)
|
|
3871
|
+
implicit_return_map = cfg_records.get("implicit_return_map", {})
|
|
3872
|
+
|
|
3873
|
+
implicit_return_to_destructor = {
|
|
3874
|
+
ir_id: fn_id for fn_id, ir_id in implicit_return_map.items()
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
processed_edges = []
|
|
3878
|
+
|
|
3879
|
+
called_destructors = set()
|
|
3880
|
+
destructor_chain_edges = []
|
|
3881
|
+
base_destructor_edges = []
|
|
3882
|
+
|
|
3883
|
+
for edge in list(cfg_graph.edges()):
|
|
3884
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3885
|
+
if edge_data and len(edge_data) > 0:
|
|
3886
|
+
edge_data = edge_data[0]
|
|
3887
|
+
label = edge_data.get("label", "")
|
|
3888
|
+
|
|
3889
|
+
if label == "scope_exit_destructor":
|
|
3890
|
+
called_destructors.add(edge[1])
|
|
3891
|
+
elif label.startswith("destructor_chain|"):
|
|
3892
|
+
destructor_chain_edges.append(edge)
|
|
3893
|
+
elif label == "base_destructor_call":
|
|
3894
|
+
base_destructor_edges.append(edge)
|
|
3895
|
+
|
|
3896
|
+
changed = True
|
|
3897
|
+
while changed:
|
|
3898
|
+
changed = False
|
|
3899
|
+
for edge in destructor_chain_edges:
|
|
3900
|
+
source_ir = edge[0]
|
|
3901
|
+
target_destructor = edge[1]
|
|
3902
|
+
source_destructor = implicit_return_to_destructor.get(source_ir)
|
|
3903
|
+
if source_destructor and source_destructor in called_destructors:
|
|
3904
|
+
if target_destructor not in called_destructors:
|
|
3905
|
+
called_destructors.add(target_destructor)
|
|
3906
|
+
changed = True
|
|
3907
|
+
|
|
3908
|
+
valid_implicit_returns = set()
|
|
3909
|
+
for destructor_id in called_destructors:
|
|
3910
|
+
ir_id = implicit_return_map.get(destructor_id)
|
|
3911
|
+
if ir_id:
|
|
3912
|
+
valid_implicit_returns.add(ir_id)
|
|
3913
|
+
|
|
3914
|
+
for edge in list(cfg_graph.edges()):
|
|
3915
|
+
edge_data = cfg_graph.get_edge_data(*edge)
|
|
3916
|
+
if edge_data and len(edge_data) > 0:
|
|
3917
|
+
edge_data = edge_data[0]
|
|
3918
|
+
label = edge_data.get("label", "")
|
|
3919
|
+
|
|
3920
|
+
if label.startswith("function_call|"):
|
|
3921
|
+
call_statement = node_list.get(read_index(index, edge[0]))
|
|
3922
|
+
function_def = node_list.get(read_index(index, edge[1]))
|
|
3923
|
+
|
|
3924
|
+
if call_statement and function_def:
|
|
3925
|
+
if function_def.type == "function_definition":
|
|
3926
|
+
declarator = function_def.child_by_field_name("declarator")
|
|
3927
|
+
if declarator:
|
|
3928
|
+
params_node = declarator.child_by_field_name("parameters")
|
|
3929
|
+
if params_node and params_node.named_children:
|
|
3930
|
+
processed_edges.append(edge)
|
|
3931
|
+
|
|
3932
|
+
elif label in ["method_return", "function_return"]:
|
|
3933
|
+
return_statement = node_list.get(read_index(index, edge[0]))
|
|
3934
|
+
call_site_node = node_list.get(read_index(index, edge[1]))
|
|
3935
|
+
|
|
3936
|
+
if return_statement and return_statement.type == "return_statement":
|
|
3937
|
+
if return_statement.named_children:
|
|
3938
|
+
if call_site_node and is_return_value_used(call_site_node):
|
|
3939
|
+
processed_edges.append(edge)
|
|
3940
|
+
|
|
3941
|
+
elif label == "constructor_call":
|
|
3942
|
+
processed_edges.append(edge)
|
|
3943
|
+
|
|
3944
|
+
elif label == "base_constructor_call":
|
|
3945
|
+
processed_edges.append(edge)
|
|
3946
|
+
|
|
3947
|
+
elif label == "scope_exit_destructor":
|
|
3948
|
+
processed_edges.append(edge)
|
|
3949
|
+
|
|
3950
|
+
elif label == "base_destructor_call":
|
|
3951
|
+
source_ir = edge[0]
|
|
3952
|
+
if source_ir in valid_implicit_returns:
|
|
3953
|
+
processed_edges.append(edge)
|
|
3954
|
+
|
|
3955
|
+
elif label == "virtual_call":
|
|
3956
|
+
processed_edges.append(edge)
|
|
3957
|
+
|
|
3958
|
+
elif label == "method_call":
|
|
3959
|
+
processed_edges.append(edge)
|
|
3960
|
+
|
|
3961
|
+
start_lambda_time = time.time()
|
|
3962
|
+
lambda_map = discover_lambdas(parser, CFG_results)
|
|
3963
|
+
end_lambda_time = time.time()
|
|
3964
|
+
|
|
3965
|
+
function_metadata_by_name, function_metadata_by_id = collect_function_metadata(
|
|
3966
|
+
parser
|
|
3967
|
+
)
|
|
3968
|
+
pointer_modifications = analyze_pointer_modifications(
|
|
3969
|
+
parser, function_metadata_by_name
|
|
3970
|
+
)
|
|
3971
|
+
|
|
3972
|
+
start_rda_init_time = time.time()
|
|
3973
|
+
rda_table = build_rda_table(
|
|
3974
|
+
parser,
|
|
3975
|
+
CFG_results,
|
|
3976
|
+
lambda_map,
|
|
3977
|
+
function_metadata_by_name,
|
|
3978
|
+
pointer_modifications,
|
|
3979
|
+
)
|
|
3980
|
+
end_rda_init_time = time.time()
|
|
3981
|
+
|
|
3982
|
+
start_rda_time = time.time()
|
|
3983
|
+
rda_solution = start_rda(index, rda_table, cfg_graph)
|
|
3984
|
+
end_rda_time = time.time()
|
|
3985
|
+
|
|
3986
|
+
final_graph = get_required_edges_from_def_to_use(
|
|
3987
|
+
index,
|
|
3988
|
+
cfg_graph,
|
|
3989
|
+
rda_solution,
|
|
3990
|
+
rda_table,
|
|
3991
|
+
cfg_graph.nodes,
|
|
3992
|
+
processed_edges,
|
|
3993
|
+
properties,
|
|
3994
|
+
lambda_map,
|
|
3995
|
+
node_list,
|
|
3996
|
+
parser,
|
|
3997
|
+
)
|
|
3998
|
+
|
|
3999
|
+
call_sites = collect_call_site_information(
|
|
4000
|
+
parser, function_metadata_by_name, cfg_graph
|
|
4001
|
+
)
|
|
4002
|
+
modification_sites_by_name, modification_sites_by_id = find_modification_sites(
|
|
4003
|
+
parser, function_metadata_by_id, pointer_modifications
|
|
4004
|
+
)
|
|
4005
|
+
add_interprocedural_edges(
|
|
4006
|
+
final_graph,
|
|
4007
|
+
parser,
|
|
4008
|
+
call_sites,
|
|
4009
|
+
modification_sites_by_id,
|
|
4010
|
+
function_metadata_by_name,
|
|
4011
|
+
cfg_graph,
|
|
4012
|
+
rda_table,
|
|
4013
|
+
)
|
|
4014
|
+
|
|
4015
|
+
add_argument_parameter_edges(final_graph, parser, cfg_graph, rda_table)
|
|
4016
|
+
|
|
4017
|
+
add_function_return_edges(final_graph, parser, cfg_graph, rda_table)
|
|
4018
|
+
|
|
4019
|
+
add_method_member_access_edges(final_graph, parser, cfg_graph, rda_table)
|
|
4020
|
+
|
|
4021
|
+
if debug:
|
|
4022
|
+
logger.info(
|
|
4023
|
+
"RDA init: {:.3f}s, RDA: {:.3f}s",
|
|
4024
|
+
end_rda_init_time - start_rda_init_time,
|
|
4025
|
+
end_rda_time - start_rda_time,
|
|
4026
|
+
)
|
|
4027
|
+
|
|
4028
|
+
debug_graph = rda_cfg_map(rda_solution, CFG_results)
|
|
4029
|
+
|
|
4030
|
+
return final_graph, debug_graph, rda_table, rda_solution
|