[labs] brush up labs

Summary:
- fix compilation errors due to bitrot
- ensure they don't happen again by adding dune files
- make a quick pass through the README

Reviewed By: skcho

Differential Revision: D21684760

fbshipit-source-id: c541f9376
master
Jules Villard 5 years ago committed by Facebook GitHub Bot
parent 64f18f0933
commit 244384f605

@ -118,6 +118,33 @@ module Raw = struct
let append (base, old_accesses) new_accesses = (base, old_accesses @ new_accesses) let append (base, old_accesses) new_accesses = (base, old_accesses @ new_accesses)
let rec chop_prefix_path ~prefix:path1 path2 =
if phys_equal path1 path2 then Some []
else
match (path1, path2) with
| [], remaining ->
Some remaining
| _, [] ->
None
| access1 :: prefix, access2 :: rest when equal_access access1 access2 ->
chop_prefix_path ~prefix rest
| _ ->
None
let chop_prefix ~prefix:((base1, path1) as ap1) ((base2, path2) as ap2) =
if phys_equal ap1 ap2 then Some []
else if equal_base base1 base2 then chop_prefix_path ~prefix:path1 path2
else None
let replace_prefix ~prefix ~replace_with access_path =
match chop_prefix ~prefix access_path with
| Some remaining_accesses ->
Some (append replace_with remaining_accesses)
| None ->
None
end end
module Abs = struct module Abs = struct

@ -40,6 +40,9 @@ val append : t -> access list -> t
(** append new accesses to an existing access path; e.g., `append_access x.f [g, h]` produces (** append new accesses to an existing access path; e.g., `append_access x.f [g, h]` produces
`x.f.g.h` *) `x.f.g.h` *)
(* used in infer/src/labs/ *)
val replace_prefix : prefix:t -> replace_with:t -> t -> t option [@@warning "-32"]
val equal_base : base -> base -> bool val equal_base : base -> base -> bool
val pp : Format.formatter -> t -> unit val pp : Format.formatter -> t -> unit
@ -48,6 +51,9 @@ val pp_base : Format.formatter -> base -> unit
val pp_access : Format.formatter -> access -> unit val pp_access : Format.formatter -> access -> unit
(* used in infer/src/labs/ *)
val pp_access_list : Format.formatter -> access list -> unit [@@warning "-32"]
module Abs : sig module Abs : sig
type raw = t type raw = t

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.t
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,8 +45,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc= _; tenv= _} _ (instr : HilInstr.t) let exec_instr (astate : ResourceLeakDomain.t)
= {InterproceduralAnalysis.proc_desc= _; tenv= _; analyze_dependency= _; _} _
(instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)
@ -67,7 +61,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -82,16 +76,17 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak _post _summary (_proc_data : unit ProcData.t) = () let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} post =
let change_me = false in
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *) if change_me then
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let proc_data = ProcData.make proc_desc tenv () in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
| Some post -> IssueType.lab_resource_leak message
report_if_leak post summary proc_data ;
Payload.update_summary post summary
| None -> (** Main function into the checker--registered in RegisterCheckers *)
L.(die InternalError) let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
"Analyzer failed to compute post for %a" Procname.pp let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
(Procdesc.get_proc_name proc_data.pdesc) Option.iter result ~f:(fun post -> report_if_leak analysis_data post) ;
result

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs00)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.t
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,7 +45,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc= _; tenv} _ (instr : HilInstr.t) = let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t)
=
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)
@ -69,7 +64,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -84,21 +79,16 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak post summary (proc_data : unit ProcData.t) = let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} post =
if ResourceLeakDomain.has_leak post then if ResourceLeakDomain.has_leak post then
let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_data.pdesc) in let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
Reporting.log_error summary ~loc:last_loc IssueType.lab_resource_leak message Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
IssueType.lab_resource_leak message
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *)
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = (** Main function into the checker--registered in RegisterCheckers *)
let proc_data = ProcData.make proc_desc tenv () in let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
| Some post -> Option.iter result ~f:(fun post -> report_if_leak analysis_data post) ;
report_if_leak post summary proc_data ; result
Payload.update_summary post summary
| None ->
L.(die InternalError)
"Analyzer failed to compute post for %a" Procname.pp
(Procdesc.get_proc_name proc_data.pdesc)

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs01)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.t
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,7 +45,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc= _; tenv} _ (instr : HilInstr.t) = let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t)
=
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)
@ -69,7 +64,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -84,21 +79,16 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak post summary (proc_data : unit ProcData.t) = let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} post =
if ResourceLeakDomain.has_leak post then if ResourceLeakDomain.has_leak post then
let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_data.pdesc) in let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
Reporting.log_error summary ~loc:last_loc IssueType.lab_resource_leak message Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
IssueType.lab_resource_leak message
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *)
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = (** Main function into the checker--registered in RegisterCheckers *)
let proc_data = ProcData.make proc_desc tenv () in let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
| Some post -> Option.iter result ~f:(fun post -> report_if_leak analysis_data post) ;
report_if_leak post summary proc_data ; result
Payload.update_summary post summary
| None ->
L.(die InternalError)
"Analyzer failed to compute post for %a" Procname.pp
(Procdesc.get_proc_name proc_data.pdesc)

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs02)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.t
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,7 +45,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc= _; tenv} _ (instr : HilInstr.t) = let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t)
=
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)
@ -69,7 +64,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -84,21 +79,16 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak post summary (proc_data : unit ProcData.t) = let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} post =
if ResourceLeakDomain.has_leak post then if ResourceLeakDomain.has_leak post then
let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_data.pdesc) in let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
Reporting.log_error summary ~loc:last_loc IssueType.lab_resource_leak message Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
IssueType.lab_resource_leak message
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *)
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = (** Main function into the checker--registered in RegisterCheckers *)
let proc_data = ProcData.make proc_desc tenv () in let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
| Some post -> Option.iter result ~f:(fun post -> report_if_leak analysis_data post) ;
report_if_leak post summary proc_data ; result
Payload.update_summary post summary
| None ->
L.(die InternalError)
"Analyzer failed to compute post for %a" Procname.pp
(Procdesc.get_proc_name proc_data.pdesc)

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs03)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.t
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,7 +45,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc; tenv} _ (instr : HilInstr.t) = let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> ( | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> (
if if
@ -62,10 +56,10 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
else if releases_resource tenv callee_procname then else if releases_resource tenv callee_procname then
ResourceLeakDomain.release_resource astate ResourceLeakDomain.release_resource astate
else else
match Payload.read pdesc callee_procname with match analyze_dependency callee_procname with
| Some summary -> | Some (_callee_proc_desc, callee_summary) ->
(* interprocedural analysis produced a summary: use it *) (* interprocedural analysis produced a summary: use it *)
ResourceLeakDomain.apply_summary ~summary astate ResourceLeakDomain.apply_summary ~summary:callee_summary astate
| None -> | None ->
(* No summary for [callee_procname]; it's native code or missing for some reason *) (* No summary for [callee_procname]; it's native code or missing for some reason *)
astate ) astate )
@ -83,7 +77,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -98,21 +92,16 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak post summary (proc_data : unit ProcData.t) = let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} post =
if ResourceLeakDomain.has_leak post then if ResourceLeakDomain.has_leak post then
let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_data.pdesc) in let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
Reporting.log_error summary ~loc:last_loc IssueType.lab_resource_leak message Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
IssueType.lab_resource_leak message
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *)
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = (** Main function into the checker--registered in RegisterCheckers *)
let proc_data = ProcData.make proc_desc tenv () in let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
| Some post -> Option.iter result ~f:(fun post -> report_if_leak analysis_data post) ;
report_if_leak post summary proc_data ; result
Payload.update_summary post summary
| None ->
L.(die InternalError)
"Analyzer failed to compute post for %a" Procname.pp
(Procdesc.get_proc_name proc_data.pdesc)

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs04)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -63,7 +63,9 @@ let release_resource access_path held =
let assign lhs_access_path rhs_access_path held = let assign lhs_access_path rhs_access_path held =
let one_binding access_path count held = let one_binding access_path count held =
match AccessPath.replace_prefix ~prefix:rhs_access_path lhs_access_path access_path with match
AccessPath.replace_prefix ~prefix:rhs_access_path ~replace_with:access_path lhs_access_path
with
| Some base_access_path -> | Some base_access_path ->
ResourcesHeld.add base_access_path count held ResourcesHeld.add base_access_path count held
| None -> | None ->
@ -141,7 +143,7 @@ module Summary = struct
held ResourcesFromFormals.empty held ResourcesFromFormals.empty
let apply ~summary ~return ~actuals held = let apply ~callee:summary ~return ~actuals held =
let apply_one (base, accesses) callee_count held = let apply_one (base, accesses) callee_count held =
let access_path_opt = let access_path_opt =
match (base : InterfaceAccessPath.base) with match (base : InterfaceAccessPath.base) with

@ -22,9 +22,11 @@ val has_leak : FormalMap.t -> t -> bool
type summary type summary
module Summary : sig module Summary : sig
val apply : summary:summary -> return:AccessPath.base -> actuals:HilExp.t list -> t -> t val apply : callee:summary -> return:AccessPath.base -> actuals:HilExp.t list -> t -> t
val make : FormalMap.t -> t -> summary val make : FormalMap.t -> t -> summary
val pp : Format.formatter -> summary -> unit val pp : Format.formatter -> summary -> unit
type t = summary
end end

@ -9,18 +9,11 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* Boilerplate to write/read our summaries alongside the summaries of other analyzers *)
module Payload = SummaryPayload.Make (struct
type t = ResourceLeakDomain.summary
let field = Payloads.Fields.lab_resource_leaks
end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = ResourceLeakDomain module Domain = ResourceLeakDomain
type extras = unit type analysis_data = ResourceLeakDomain.Summary.t InterproceduralAnalysis.t
let is_closeable_typename tenv typename = let is_closeable_typename tenv typename =
let is_closable_interface typename _ = let is_closable_interface typename _ =
@ -52,7 +45,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) {ProcData.pdesc; tenv} _ (instr : HilInstr.t) = let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ (instr : HilInstr.t) =
match instr with match instr with
| Call (_return, Direct callee_procname, HilExp.AccessExpression allocated :: _, _, _loc) | Call (_return, Direct callee_procname, HilExp.AccessExpression allocated :: _, _, _loc)
when acquires_resource tenv callee_procname -> when acquires_resource tenv callee_procname ->
@ -69,10 +63,10 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| _ -> | _ ->
astate ) astate )
| Call (return, Direct callee_procname, actuals, _, _loc) -> ( | Call (return, Direct callee_procname, actuals, _, _loc) -> (
match Payload.read pdesc callee_procname with match analyze_dependency callee_procname with
| Some summary -> | Some (_callee_proc_desc, callee_summary) ->
(* interprocedural analysis produced a summary: use it *) (* interprocedural analysis produced a summary: use it *)
ResourceLeakDomain.Summary.apply ~summary ~return ~actuals astate ResourceLeakDomain.Summary.apply ~callee:callee_summary ~return ~actuals astate
| None -> | None ->
(* No summary for [callee_procname]; it's native code or missing for some reason *) (* No summary for [callee_procname]; it's native code or missing for some reason *)
astate ) astate )
@ -90,7 +84,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
| ExitScope _ -> | Metadata _ ->
astate astate
@ -105,22 +99,18 @@ module CFG = ProcCfg.Normal
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG)) module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (CFG))
(** Report an error when we have acquired more resources than we have released *) (** Report an error when we have acquired more resources than we have released *)
let report_if_leak post summary formal_map (proc_data : unit ProcData.t) = let report_if_leak {InterproceduralAnalysis.proc_desc; err_log; _} formal_map post =
if ResourceLeakDomain.has_leak formal_map post then if ResourceLeakDomain.has_leak formal_map post then
let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_data.pdesc) in let last_loc = Procdesc.Node.get_loc (Procdesc.get_exit_node proc_desc) in
let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in let message = F.asprintf "Leaked %a resource(s)" ResourceLeakDomain.pp post in
Reporting.log_error summary ~loc:last_loc IssueType.lab_resource_leak message Reporting.log_error proc_desc err_log ~loc:last_loc ResourceLeakLabExercise
IssueType.lab_resource_leak message
(* Callback for invoking the checker from the outside--registered in RegisterCheckers *) (** Main function into the checker--registered in RegisterCheckers *)
let checker {Callbacks.summary; proc_desc; tenv} : Summary.t = let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) =
let proc_data = ProcData.make proc_desc tenv () in let result = Analyzer.compute_post analysis_data ~initial:ResourceLeakDomain.initial proc_desc in
match Analyzer.compute_post proc_data ~initial:ResourceLeakDomain.initial with Option.map result ~f:(fun post ->
| Some post ->
let formal_map = FormalMap.make proc_desc in let formal_map = FormalMap.make proc_desc in
report_if_leak post summary formal_map proc_data ; report_if_leak analysis_data formal_map post ;
Payload.update_summary (ResourceLeakDomain.Summary.make formal_map post) summary ResourceLeakDomain.Summary.make formal_map post )
| None ->
L.(die InternalError)
"Analyzer failed to compute post for %a" Procname.pp
(Procdesc.get_proc_name proc_data.pdesc)

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : Callbacks.proc_callback_t val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

@ -0,0 +1,13 @@
; Copyright (c) Facebook, Inc. and its affiliates.
;
; This source code is licensed under the MIT license found in the
; LICENSE file in the root directory of this source tree.
(library
(name Labs05)
(flags
(:standard -open Core -open IR -open IStdlib -open IStd -open ATDGenerated
-open IBase -open Absint))
(libraries core IStdlib ATDGenerated IBase IR Absint)
(preprocess (pps ppx_compare))
)

@ -4,6 +4,8 @@ This is a lab exercise designed to take the participant through the basics of us
The files to work on are [ResourceLeaks.ml](./ResourceLeaks.ml) and [ResourceLeakDomain.ml](./ResourceLeakDomain.ml), and their corresponding .mli files. The files to work on are [ResourceLeaks.ml](./ResourceLeaks.ml) and [ResourceLeakDomain.ml](./ResourceLeakDomain.ml), and their corresponding .mli files.
The solutions to the exercises can also be found in this directory, each in their own directory. For example, the solution for Section 2 of this lab can be found in [02_domain_join/](./02_domain_join/).
## (0) Quick Start ## (0) Quick Start
### (a) With Docker... ### (a) With Docker...

@ -7,4 +7,5 @@
open! IStd open! IStd
val checker : ResourceLeakDomain.t InterproceduralAnalysis.t -> ResourceLeakDomain.t option val checker :
ResourceLeakDomain.summary InterproceduralAnalysis.t -> ResourceLeakDomain.summary option

Loading…
Cancel
Save