You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
4.9 KiB
223 lines
4.9 KiB
(*
|
|
* Copyright (c) 2015 - present Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*)
|
|
|
|
open! Utils
|
|
|
|
module F = Format
|
|
|
|
(** Test the generic abstract interpreter by using a simple path counting domain. Path counting is
|
|
actually a decent stress test--if you join too much/too little, you'll over/under-count, and
|
|
you'll diverge at loops if you don't widen *)
|
|
|
|
module PathCountDomain = struct
|
|
|
|
type astate =
|
|
| PathCount of int
|
|
| Top
|
|
|
|
let make_path_count c =
|
|
(* guarding against overflow *)
|
|
if c < 0
|
|
then Top
|
|
else PathCount c
|
|
|
|
let initial = make_path_count 1
|
|
|
|
let is_bottom _ = false
|
|
|
|
let (<=) ~lhs ~rhs = match lhs, rhs with
|
|
| PathCount c1, PathCount c2 -> c1 <= c2
|
|
| _, Top -> true
|
|
| Top, PathCount _ -> false
|
|
|
|
let join a1 a2 = match a1, a2 with
|
|
| PathCount c1, PathCount c2 -> make_path_count (c1 + c2)
|
|
| Top, _ | PathCount _, Top -> Top
|
|
|
|
let widen ~prev:_ ~next:_ ~num_iters:_ = Top
|
|
|
|
let pp fmt = function
|
|
| PathCount c -> F.fprintf fmt "%d" c
|
|
| Top -> F.fprintf fmt "T"
|
|
|
|
end
|
|
|
|
module PathCountTransferFunctions = struct
|
|
type astate = PathCountDomain.astate
|
|
|
|
(* just propagate the current path count *)
|
|
let exec_instr astate _ _ = astate
|
|
end
|
|
|
|
|
|
module NormalTestInterpreter = AnalyzerTester.Make
|
|
(ProcCfg.Normal)
|
|
(Scheduler.ReversePostorder)
|
|
(PathCountDomain)
|
|
(PathCountTransferFunctions)
|
|
|
|
module ExceptionalTestInterpreter = AnalyzerTester.Make
|
|
(ProcCfg.Exceptional)
|
|
(Scheduler.ReversePostorder)
|
|
(PathCountDomain)
|
|
(PathCountTransferFunctions)
|
|
|
|
let tests =
|
|
let open OUnit2 in
|
|
let open AnalyzerTester.StructuredSil in
|
|
let normal_test_list = [
|
|
"straightline",
|
|
[
|
|
invariant "1";
|
|
invariant "1"
|
|
];
|
|
"if",
|
|
[
|
|
invariant "1";
|
|
If (unknown_exp, [], []);
|
|
invariant "2";
|
|
];
|
|
"if_then",
|
|
[
|
|
If (unknown_exp,
|
|
[invariant "1"],
|
|
[]
|
|
);
|
|
invariant "2"
|
|
];
|
|
"if_else",
|
|
[
|
|
If (unknown_exp,
|
|
[],
|
|
[invariant "1"]
|
|
);
|
|
invariant "2"
|
|
];
|
|
"if_then_else",
|
|
[
|
|
If (unknown_exp,
|
|
[invariant "1"],
|
|
[invariant "1"];
|
|
);
|
|
invariant "2"
|
|
];
|
|
"nested_if_then",
|
|
[
|
|
If (unknown_exp,
|
|
[If (unknown_exp, [], []);
|
|
invariant "2"],
|
|
[]
|
|
);
|
|
invariant "3"
|
|
];
|
|
"nested_if_else",
|
|
[
|
|
If (unknown_exp,
|
|
[],
|
|
[If (unknown_exp, [], []);
|
|
invariant "2"]
|
|
);
|
|
invariant "3"
|
|
];
|
|
"nested_if_then_else",
|
|
[
|
|
If (unknown_exp,
|
|
[If (unknown_exp, [], []);
|
|
invariant "2"],
|
|
[If (unknown_exp, [], []);
|
|
invariant "2"]
|
|
);
|
|
invariant "4"
|
|
];
|
|
"if_diamond",
|
|
[
|
|
invariant "1";
|
|
If (unknown_exp, [], []);
|
|
invariant "2";
|
|
If (unknown_exp, [], []);
|
|
invariant "4"
|
|
];
|
|
"loop",
|
|
[
|
|
invariant "1";
|
|
While (unknown_exp, [invariant "T"]);
|
|
invariant "T"
|
|
];
|
|
"if_in_loop",
|
|
[
|
|
While (unknown_exp,
|
|
[If (unknown_exp, [], []);
|
|
invariant "T"]
|
|
);
|
|
invariant "T";
|
|
];
|
|
"nested_loop_visit",
|
|
[
|
|
invariant "1";
|
|
While (unknown_exp,
|
|
[invariant "T";
|
|
While (unknown_exp,
|
|
[invariant "T"]);
|
|
invariant "T"]);
|
|
invariant "T";
|
|
];
|
|
"try",
|
|
[
|
|
Try (
|
|
[
|
|
invariant "1"; (* we expect the try block to be visited *)
|
|
],
|
|
[
|
|
invariant "_|_"; (* but not the catch block *)
|
|
],
|
|
[
|
|
invariant "1"; (* we expect the finally block to be visited *)
|
|
]
|
|
);
|
|
invariant "1"
|
|
];
|
|
] |> NormalTestInterpreter.create_tests in
|
|
let exceptional_test_list = [
|
|
"try1",
|
|
[
|
|
Try (
|
|
[
|
|
invariant "1";
|
|
],
|
|
[
|
|
invariant "1"; (* catch block should be visited *)
|
|
],
|
|
[
|
|
invariant "2"; (* could come from try or catch block *)
|
|
]
|
|
);
|
|
invariant "2"
|
|
];
|
|
"try1",
|
|
[
|
|
Try (
|
|
[
|
|
(* note: each instruction in try block is treated as potentially-excepting... *)
|
|
(* point 1 *)
|
|
invariant "1"; (* point 2 *)
|
|
invariant "1"; (* point 3 *)
|
|
],
|
|
[
|
|
(* ... so |paths through catch block| shoud be |number of instructions in try block| *)
|
|
invariant "2"; (* point 4 *)
|
|
],
|
|
[
|
|
invariant "3"; (* could arrive here via (1, 2, 3), (1, 4), or (2, 4) *)
|
|
]
|
|
);
|
|
invariant "3"
|
|
];
|
|
] |> ExceptionalTestInterpreter.create_tests in
|
|
"analyzer_tests_suite">:::(normal_test_list @ exceptional_test_list)
|