Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect renamed functions and global variables. #774

Merged
merged 102 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from 97 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
4256428
Added basic test cases for changed variable names.
TimOrtel Mar 17, 2022
27dd10f
Rename detection works for simple cases
TimOrtel Mar 18, 2022
6bc0fca
Rename detection for method parameters, too
TimOrtel Apr 3, 2022
ca6670b
Renaming of method params should work now.
TimOrtel Apr 5, 2022
c1e165c
Renaming of results does work for the log files.
TimOrtel Apr 18, 2022
d589278
Added multiple incremental runs test
TimOrtel Apr 19, 2022
9eb3f87
Renamed local vars are now also shown in g2html.
TimOrtel Apr 20, 2022
d652715
Added incremental aware print statements and replaced traditional pri…
TimOrtel May 3, 2022
08da3fb
Renamed variable names are now displayed with their new name in g2html
TimOrtel May 4, 2022
3a11fb9
Cleanup print statements and added some docu.
TimOrtel May 9, 2022
26d0702
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel May 9, 2022
b7fac89
Renamed context to rename_mapping
TimOrtel May 9, 2022
abf871b
Replaced rename mapping lists with Hashtbls for increased performance
TimOrtel May 9, 2022
4745a3f
cleanup print statements and code.
TimOrtel May 14, 2022
7d702f7
Merge upstream master
TimOrtel May 14, 2022
c645c68
cherry picked context -> rename mapping
TimOrtel May 14, 2022
aed7a3a
Replaced rename mapping lists with Hashtbls for increased performance
TimOrtel May 9, 2022
9e95ddb
Old locals are now renamed to the new local names.
TimOrtel May 14, 2022
7e89ec2
Fixed duplicate id tests
TimOrtel May 16, 2022
e4df2ca
Added some test cases
TimOrtel May 16, 2022
2c86411
Added first functions for rename detection.
TimOrtel May 17, 2022
182db42
Replaced Hashtbl in compare functions with Map
TimOrtel May 17, 2022
11de365
CompareAST functions now propagate updated rename_mappings in their r…
TimOrtel May 17, 2022
d900e7e
eqF now returns the method rename dependencies
TimOrtel May 17, 2022
49caf8c
Implemented rename detection of method. Not tested.
TimOrtel May 18, 2022
abef116
Removed obsolete method and smaller changes
TimOrtel May 25, 2022
b9ad6db
Implemented simple rename detection for methods
TimOrtel May 25, 2022
1855a5a
Added more docu
TimOrtel May 25, 2022
c71e29c
Added more test cases for method rename
TimOrtel May 25, 2022
874519c
Added json and patch files for method rename tests.
TimOrtel Jun 6, 2022
b75a19f
Global var renames are now also detected in compareAST
TimOrtel Jun 6, 2022
9e80fc1
Cleaned up and improved detectRenamedFunctions.
TimOrtel Jun 7, 2022
fae1e5e
Moved multiple incremental run tests to subdirectory.
TimOrtel Jun 8, 2022
0c6b9c4
Moved multiple incremental run tests to subdirectory.
TimOrtel Jun 8, 2022
d5979f1
Merge Branch Without Rename Mapping
TimOrtel Jun 10, 2022
37e5703
Merged upstream master
TimOrtel Jun 10, 2022
a9a2e65
Now also uses VarinfoMap for method rename assumptions
TimOrtel Jun 14, 2022
ed605ff
Now uses varinfo#vGlob to check if a variable is global
TimOrtel Jun 14, 2022
3b60fb7
Removed unused currentFunctionName global state.
TimOrtel Jun 15, 2022
e9494eb
Removed useless global state cherry pick
TimOrtel Jun 15, 2022
1eae9c3
Removed nothing test case
TimOrtel Jun 15, 2022
1921299
Fixed analysis.ml
TimOrtel Jun 15, 2022
fd691c5
Removed nothing test case
TimOrtel Jun 15, 2022
686a3da
Added include assert to tests. Removed useless test.c
TimOrtel Jun 15, 2022
0a0ee34
Replaced tupletostring with fancy syntax.
TimOrtel Jun 15, 2022
8b28e89
Hashtbl.add is now replaced by Hashtbl.replace in many places.
TimOrtel Jun 15, 2022
77bd926
List optimization.
TimOrtel Jun 15, 2022
938fcb0
Removed compinfo and enum rename hack from compareAST and replaced it…
TimOrtel Jun 17, 2022
2cf1a03
Merge remote-tracking branch 'refs/remotes/origin/dev-method-rename-s…
TimOrtel Jun 17, 2022
7371dc9
method_rename_assumptions now uses varinfo map instead of string hash…
TimOrtel Jun 20, 2022
7b320c9
Removed RenameMapping.
TimOrtel Jun 20, 2022
18938a3
Fixed crash in forward_list_equal on lists with altering list lengths.
TimOrtel Jun 21, 2022
40281fe
Added documentation to tests in 04-var-rename
TimOrtel Jun 21, 2022
60468d4
Add comment to test-incremental-multiple.sh
TimOrtel Jun 15, 2022
9c8e226
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel Jun 22, 2022
a9d297c
Removed syntactic noise introduced by addition and removal of RenameM…
TimOrtel Jun 22, 2022
31283c9
Removed diffs directory in tests/incremental/04-var-rename
TimOrtel Jun 22, 2022
f04651b
Removed diffs directory in tests/incremental/04-var-rename
TimOrtel Jun 22, 2022
4d8098e
Add comment to test-incremental-multiple.sh
TimOrtel Jun 15, 2022
4535039
Added documentation to tests in 04-var-rename
TimOrtel Jun 21, 2022
55133d2
Replaced printf with tracing in compareCIL
TimOrtel Jun 22, 2022
51590ee
Removed parameter renames and instead disabled the name checking for …
TimOrtel Jul 1, 2022
c2a807e
Merged upstream/master
TimOrtel Jul 4, 2022
b3487ba
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel Jul 4, 2022
c4f6d66
Merged with dev-local-var-rename
TimOrtel Jul 4, 2022
1caaa79
Removed diffs.
TimOrtel Jul 4, 2022
b9785ab
Applied changes requested in PR #731. compareCFG now propagates renam…
TimOrtel Jul 12, 2022
1f7b7bb
detecting renames can now be disabled using the option incremental.de…
TimOrtel Jul 12, 2022
ad0103f
merge upstream/master
TimOrtel Jul 12, 2022
ae506cb
Added test script. function rename detection now supports renamed rec…
TimOrtel Jul 13, 2022
f8dba3e
Added doc on how to support library headers.
TimOrtel Jul 16, 2022
d9a7c93
Fixed a couple of bugs
TimOrtel Jul 26, 2022
abe372b
Merge branch 'master' into dev-method-rename-simple-impl
stilscher Mar 6, 2023
fa9747b
remove GlobalElemMap
stilscher Mar 6, 2023
8884a9b
fix merge mistake
stilscher Mar 7, 2023
ef2a721
cleanup compareCilFiles
stilscher Mar 7, 2023
68ed7e0
remove redundant global in output map
stilscher Mar 7, 2023
b959c3c
fix updating of compinfo names and ckeys for comparison without renam…
stilscher Mar 7, 2023
abdfe66
remove extra output type and avoid another mapping between types
stilscher Mar 7, 2023
c0aaa81
cleanup eqF: same handling for cfg and ast comparison
stilscher Mar 7, 2023
55da723
make detection of renamed globals more concise
stilscher Mar 8, 2023
009f457
refactor
stilscher Mar 8, 2023
5d90ad0
fixes in rename detection
stilscher Mar 13, 2023
f736366
add cram tests for rename detection
stilscher Mar 13, 2023
5e1963f
remove superflous tests and those without clear expected result
stilscher Mar 13, 2023
b90d0bc
fix patches
stilscher Mar 13, 2023
7c365ba
re-establish consecutive test ids
stilscher Mar 13, 2023
4bb775a
move rename detection and CompareGlobals back to CompareCIL
stilscher Mar 13, 2023
2620cfc
remove debugging functions
stilscher Mar 13, 2023
442b6d9
merge comparison with and without rename detection
stilscher Mar 13, 2023
6ba71fc
make semgrep happy
stilscher Mar 13, 2023
aeaf301
add incremental cram tests to CI
stilscher Mar 23, 2023
033555a
refine implementation based on review comments
stilscher Mar 23, 2023
e293a7f
missing propagation of change_info and final_matches
stilscher Mar 23, 2023
e8ce672
remove test script because of restricted parser and few working cases
stilscher Mar 23, 2023
af79fb2
no structural comparison when looking through collected final_matches
stilscher Mar 23, 2023
7d68cf2
fix check whether already matched as unchanged
stilscher Mar 23, 2023
79873fe
fix: already matched check needs to consider change_info
stilscher Mar 23, 2023
06502b5
remove polymorphic comparison of global_col
stilscher Apr 17, 2023
61d15d1
fix new and old global mix-up
stilscher May 2, 2023
72065a5
handle functions without definitions in exact comparison
stilscher May 3, 2023
2a8bce5
Merge branch 'master' into dev-method-rename-simple-impl
stilscher May 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/locked.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ jobs:
- name: Test regression cram
run: opam exec -- dune runtest tests/regression

- name: Test incremental cram
run: opam exec -- dune runtest tests/incremental

- name: Test unit
run: opam exec -- dune runtest unittest

Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/unlocked.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ jobs:
- name: Test regression cram
run: opam exec -- dune runtest tests/regression

- name: Test incremental cram
run: opam exec -- dune runtest tests/incremental

- name: Test unit
run: opam exec -- dune runtest unittest

Expand Down Expand Up @@ -179,6 +182,9 @@ jobs:
- name: Test regression cram
run: opam exec -- dune runtest tests/regression

- name: Test incremental cram
run: opam exec -- dune runtest tests/incremental

- name: Test unit
run: opam exec -- dune runtest unittest

Expand Down
2 changes: 1 addition & 1 deletion src/framework/constraints.ml
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ struct
| Some {changes; _} -> changes
| None -> empty_change_info ()
in
List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed));
List.(Printf.printf "change_info = { unchanged = %d; changed = %d (with unchangedHeader = %d); added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (BatList.count_matching (fun c -> c.unchangedHeader) c.changed) (length c.added) (length c.removed));

let changed_funs = List.filter_map (function
| {old = {def = Some (Fun f); _}; diff = None; _} ->
Expand Down
384 changes: 235 additions & 149 deletions src/incremental/compareAST.ml

Large diffs are not rendered by default.

98 changes: 57 additions & 41 deletions src/incremental/compareCFG.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,47 @@ open GoblintCil
open CilMaps
include CompareAST

let eq_node (x, fun1) (y, fun2) =
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
(* don't allow pseudo return node to be equal to normal return node, could make function unchanged, but have different sallstmts *)
(*Non propagating version of &&>>. Discards the new rename_mapping and alwas propagates the one in prev_result. However propagates the renames_on_success*)
let (&&<>) (prev_result: bool * rename_mapping) f : bool * rename_mapping =
let (prev_equal, prev_rm) = prev_result in
let (a, b, c, _) = prev_rm in

if prev_equal then
let (r, ((_, _, _, updated_renames_on_success) : rename_mapping)) = f ~rename_mapping:prev_rm in
(r, (a, b, c, updated_renames_on_success))
else false, prev_rm

let eq_node (x, fun1) (y, fun2) ~rename_mapping =
let isPseudoReturn f sid =
let pid = CfgTools.get_pseudo_return_id f in
sid == pid in
match x,y with
| Statement s1, Statement s2 ->
let p1 = isPseudoReturn fun1 s1.sid in
let p2 = isPseudoReturn fun2 s2.sid in
((p1 && p2) || not (p1 || p2)) && eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2) ~rename_mapping:empty_rename_mapping
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
| _ -> false
((p1 && p2) || not (p1 || p2), rename_mapping) &&>> eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2)
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
| _ -> false, rename_mapping

(* TODO: compare ASMs properly instead of simply always assuming that they are not the same *)
let eq_edge x y =
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
let eq_edge x y ~rename_mapping =
match x, y with
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 ~rename_mapping:empty_rename_mapping && eq_exp rv1 rv2 ~rename_mapping:empty_rename_mapping
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 ~rename_mapping:empty_rename_mapping && GobList.equal (eq_exp ~rename_mapping:empty_rename_mapping) ars1 ars2
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 ~rename_mapping &&<> eq_exp rv1 rv2
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 ~rename_mapping &&<> forward_list_equal eq_exp ars1 ars2
| Proc (Some r1,f1,ars1), Proc (Some r2,f2,ars2) ->
eq_lval r1 r2 ~rename_mapping:empty_rename_mapping && eq_exp f1 f2 ~rename_mapping:empty_rename_mapping && GobList.equal (eq_exp ~rename_mapping:empty_rename_mapping) ars1 ars2
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar ~rename_mapping:empty_rename_mapping
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 ~rename_mapping:empty_rename_mapping && eq_varinfo fd1.svar fd2.svar ~rename_mapping:empty_rename_mapping
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 ~rename_mapping:empty_rename_mapping && b1 = b2
| ASM _, ASM _ -> false
| Skip, Skip -> true
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2 ~rename_mapping:empty_rename_mapping
| _ -> false
eq_lval r1 r2 ~rename_mapping &&<> eq_exp f1 f2 &&<> forward_list_equal eq_exp ars1 ars2
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar ~rename_mapping
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 ~rename_mapping &&<> eq_varinfo fd1.svar fd2.svar
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 ~rename_mapping &&> (b1 = b2)
| ASM _, ASM _ -> false, rename_mapping
| Skip, Skip -> true, rename_mapping
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2 ~rename_mapping
| _ -> false, rename_mapping

(* The order of the edges in the list is relevant. Therefore compare them one to one without sorting first *)
let eq_edge_list xs ys = GobList.equal eq_edge xs ys
let eq_edge_list xs ys = forward_list_equal ~propF:(&&<>) eq_edge xs ys

let to_edge_list ls = List.map (fun (loc, edge) -> edge) ls

Expand All @@ -50,37 +57,40 @@ type biDirectionNodeMap = {node1to2: node NH.t; node2to1: node NH.t}
* in the succesors of fromNode2 in the new CFG. Matching node tuples are added to the waitingList to repeat the matching
* process on their successors. If a node from the old CFG can not be matched, it is added to diff and no further
* comparison is done for its successors. The two function entry nodes make up the tuple to start the comparison from. *)
let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 fun2 =

let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 fun2 rename_mapping : biDirectionNodeMap * unit NH.t * rename_mapping =
let diff = NH.create 113 in
let same = {node1to2=NH.create 113; node2to1=NH.create 113} in
let waitingList : (node * node) t = Queue.create () in

let rec compareNext () =
if Queue.is_empty waitingList then ()
let rec compareNext rename_mapping : rename_mapping =
if Queue.is_empty waitingList then rename_mapping
else
let fromNode1, fromNode2 = Queue.take waitingList in
let outList1 = CfgOld.next fromNode1 in
let outList2 = CfgNew.next fromNode2 in

(* Find a matching edge and successor node for (edgeList1, toNode1) in the list of successors of fromNode2.
* If successful, add the matching node tuple to same, else add toNode1 to the differing nodes. *)
let findMatch (edgeList1, toNode1) =
let rec aux remSuc = match remSuc with
| [] -> NH.replace diff toNode1 ()
let findMatch (edgeList1, toNode1) rename_mapping : rename_mapping =
let rec aux remSuc rename_mapping : rename_mapping = match remSuc with
| [] -> NH.replace diff toNode1 (); rename_mapping
| (locEdgeList2, toNode2)::remSuc' ->
let edgeList2 = to_edge_list locEdgeList2 in
if eq_node (toNode1, fun1) (toNode2, fun2) && eq_edge_list edgeList1 edgeList2 then
let (isEq, updatedRenameMapping) = (true, rename_mapping) &&>> eq_node (toNode1, fun1) (toNode2, fun2) &&>> eq_edge_list edgeList1 edgeList2 in
if isEq then
begin
match NH.find_opt same.node1to2 toNode1 with
| Some n2 -> if not (Node.equal n2 toNode2) then NH.replace diff toNode1 ()
| None -> NH.replace same.node1to2 toNode1 toNode2; NH.replace same.node2to1 toNode2 toNode1; Queue.add (toNode1, toNode2) waitingList
| Some n2 -> if not (Node.equal n2 toNode2) then NH.replace diff toNode1 (); updatedRenameMapping
| None -> NH.replace same.node1to2 toNode1 toNode2; NH.replace same.node2to1 toNode2 toNode1; Queue.add (toNode1, toNode2) waitingList;
updatedRenameMapping
end
else aux remSuc' in
aux outList2 in
else aux remSuc' updatedRenameMapping in
aux outList2 rename_mapping in
(* For a toNode1 from the list of successors of fromNode1, check whether it might have duplicate matches.
* In that case declare toNode1 as differing node. Else, try finding a match in the list of successors
* of fromNode2 in the new CFG using findMatch. *)
let iterOuts (locEdgeList1, toNode1) =
let iterOuts (locEdgeList1, toNode1) rename_mapping : rename_mapping =
let edgeList1 = to_edge_list locEdgeList1 in
(* Differentiate between a possibly duplicate Test(1,false) edge and a single occurence. In the first
* case the edge is directly added to the diff set to avoid undetected ambiguities during the recursive
Expand All @@ -91,13 +101,18 @@ let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 f
let posAmbigEdge edgeList = let findTestFalseEdge (ll,_) = testFalseEdge (snd (List.hd ll)) in
let numDuplicates l = List.length (List.find_all findTestFalseEdge l) in
testFalseEdge (List.hd edgeList) && (numDuplicates outList1 > 1 || numDuplicates outList2 > 1) in
if posAmbigEdge edgeList1 then NH.replace diff toNode1 ()
else findMatch (edgeList1, toNode1) in
List.iter iterOuts outList1; compareNext () in
if posAmbigEdge edgeList1 then (NH.replace diff toNode1 (); rename_mapping)
else findMatch (edgeList1, toNode1) rename_mapping in
let updatedRenameMapping = List.fold_left (fun rm e -> iterOuts e rm) rename_mapping outList1 in
compareNext updatedRenameMapping
in

let entryNode1, entryNode2 = (FunctionEntry fun1, FunctionEntry fun2) in
NH.replace same.node1to2 entryNode1 entryNode2; NH.replace same.node2to1 entryNode2 entryNode1;
Queue.push (entryNode1,entryNode2) waitingList; compareNext (); (same, diff)
NH.replace same.node1to2 entryNode1 entryNode2;
NH.replace same.node2to1 entryNode2 entryNode1;
Queue.push (entryNode1,entryNode2) waitingList;
let updatedRenameMapping = compareNext rename_mapping in
same, diff, updatedRenameMapping

(* This is the second phase of the CFG comparison of functions. It removes the nodes from the matching node set 'same'
* that have an incoming backedge in the new CFG that can be reached from a differing new node. This is important to
Expand All @@ -120,7 +135,8 @@ let reexamine f1 f2 (same : biDirectionNodeMap) (diffNodes1 : unit NH.t) (module
repeat ();
NH.to_seq same.node1to2, NH.to_seq_keys diffNodes1

let compareFun (module CfgOld : CfgForward) (module CfgNew : CfgBidir) fun1 fun2 =
let same, diff = Timing.wrap "compare-phase1" (fun () -> compareCfgs (module CfgOld) (module CfgNew) fun1 fun2) () in

let compareFun (module CfgOld : CfgForward) (module CfgNew : CfgBidir) fun1 fun2 rename_mapping : (node * node) list * node list * rename_mapping =
let same, diff, rename_mapping = Timing.wrap "compare-phase1" (fun () -> compareCfgs (module CfgOld) (module CfgNew) fun1 fun2 rename_mapping) () in
let unchanged, diffNodes1 = Timing.wrap "compare-phase2" (fun () -> reexamine fun1 fun2 same diff (module CfgOld) (module CfgNew)) () in
List.of_seq unchanged, List.of_seq diffNodes1
List.of_seq unchanged, List.of_seq diffNodes1, rename_mapping
Loading