[pulse] model `std::function::operator=`

Summary:
`function::operator=` is called whenever we assign a literal lambda to a
variable, so it's pretty useful to be able to report anything on
lambdas.

Reviewed By: mbouaziz

Differential Revision: D16008163

fbshipit-source-id: a9d07668d
master
Jules Villard 6 years ago committed by Facebook Github Bot
parent 0ab1223d3d
commit 2bf6852b95

@ -166,6 +166,7 @@ module PulseTransferFunctions = struct
in in
match model with match model with
| Some model -> | Some model ->
L.d_printfln "Found model for call@\n" ;
model call_loc ~ret ~actuals:actuals_evaled astate model call_loc ~ret ~actuals:actuals_evaled astate
| None -> ( | None -> (
(* do interprocedural call then destroy objects going out of scope *) (* do interprocedural call then destroy objects going out of scope *)

@ -17,6 +17,24 @@ type exec_fun =
type model = exec_fun type model = exec_fun
module Misc = struct module Misc = struct
let shallow_copy model_desc : model =
fun location ~ret:(ret_id, _) ~actuals astate ->
let event = PulseDomain.ValueHistory.Call {f= `Model model_desc; location} in
( match actuals with
| [(dest_pointer_hist, _); (src_pointer_hist, _)] ->
PulseOperations.eval_access location src_pointer_hist Dereference astate
>>= fun (astate, obj) ->
PulseOperations.shallow_copy location obj astate
>>= fun (astate, obj_copy) ->
let obj_hist = snd obj in
PulseOperations.write_deref location ~ref:dest_pointer_hist
~obj:(obj_copy, event :: obj_hist)
astate
| _ ->
Ok astate )
>>| fun astate -> [PulseOperations.havoc_id ret_id [event] astate]
let early_exit : model = fun _ ~ret:_ ~actuals:_ _ -> Ok [] let early_exit : model = fun _ ~ret:_ ~actuals:_ _ -> Ok []
let skip : model = fun _ ~ret:_ ~actuals:_ astate -> Ok [astate] let skip : model = fun _ ~ret:_ ~actuals:_ astate -> Ok [astate]
@ -48,28 +66,31 @@ module Cplusplus = struct
Ok [astate] Ok [astate]
let placement_new : model =
fun location ~ret:(ret_id, _) ~actuals astate ->
let event = PulseDomain.ValueHistory.Call {f= `Model "<placement new>"; location} in
match List.rev actuals with
| ((address, _), _) :: _ ->
Ok [PulseOperations.write_id ret_id (address, [event]) astate]
| _ ->
Ok [PulseOperations.havoc_id ret_id [event] astate]
end
module StdFunction = struct
let operator_call : model = let operator_call : model =
fun location ~ret:(ret_id, _) ~actuals astate -> fun location ~ret:(ret_id, _) ~actuals astate ->
( match actuals with ( match actuals with
| (lambda, _) :: _ -> | (lambda_ptr_hist, _) :: _ ->
PulseOperations.eval_access location lambda_ptr_hist Dereference astate
>>= fun (astate, (lambda, _)) ->
PulseOperations.Closures.check_captured_addresses PulseOperations.Closures.check_captured_addresses
(PulseDomain.InterprocAction.Immediate {imm= (); location}) (PulseDomain.InterprocAction.Immediate {imm= (); location})
(fst lambda) astate lambda astate
| _ -> | _ ->
Ok astate ) Ok astate )
>>| fun astate -> >>| fun astate ->
let event = PulseDomain.ValueHistory.Call {f= `Model "<lambda>"; location} in let event = PulseDomain.ValueHistory.Call {f= `Model "<lambda>"; location} in
[PulseOperations.havoc_id ret_id [event] astate] [PulseOperations.havoc_id ret_id [event] astate]
let placement_new : model =
fun location ~ret:(ret_id, _) ~actuals astate ->
let event = PulseDomain.ValueHistory.Call {f= `Model "<placement new>"; location} in
match List.rev actuals with
| ((address, _), _) :: _ ->
Ok [PulseOperations.write_id ret_id (address, [event]) astate]
| _ ->
Ok [PulseOperations.havoc_id ret_id [event] astate]
end end
module StdVector = struct module StdVector = struct
@ -164,7 +185,8 @@ module ProcNameDispatcher = struct
make_dispatcher make_dispatcher
[ -"folly" &:: "DelayedDestruction" &:: "destroy" &--> Misc.skip [ -"folly" &:: "DelayedDestruction" &:: "destroy" &--> Misc.skip
; -"folly" &:: "SocketAddress" &:: "~SocketAddress" &--> Misc.skip ; -"folly" &:: "SocketAddress" &:: "~SocketAddress" &--> Misc.skip
; -"std" &:: "function" &:: "operator()" &--> Cplusplus.operator_call ; -"std" &:: "function" &:: "operator()" &--> StdFunction.operator_call
; -"std" &:: "function" &:: "operator=" &--> Misc.shallow_copy "std::function::operator="
; -"std" &:: "vector" &:: "assign" &--> StdVector.invalidate_references Assign ; -"std" &:: "vector" &:: "assign" &--> StdVector.invalidate_references Assign
; -"std" &:: "vector" &:: "clear" &--> StdVector.invalidate_references Clear ; -"std" &:: "vector" &:: "clear" &--> StdVector.invalidate_references Clear
; -"std" &:: "vector" &:: "emplace" &--> StdVector.invalidate_references Emplace ; -"std" &:: "vector" &:: "emplace" &--> StdVector.invalidate_references Emplace

@ -215,6 +215,21 @@ let invalidate_array_elements location cause addr_trace astate =
edges astate edges astate
let shallow_copy location addr_hist astate =
let action = action_of_address location in
check_addr_access action addr_hist astate
>>| fun astate ->
let cell =
match Memory.find_opt (fst addr_hist) astate with
| None ->
(Memory.Edges.empty, Attributes.empty)
| Some cell ->
cell
in
let copy = AbstractAddress.mk_fresh () in
(Memory.set_cell copy cell astate, copy)
let check_address_escape escape_location proc_desc address history astate = let check_address_escape escape_location proc_desc address history astate =
let is_assigned_to_global address astate = let is_assigned_to_global address astate =
let points_to_address pointer address astate = let points_to_address pointer address astate =

@ -86,6 +86,10 @@ val invalidate_array_elements :
-> t access_result -> t access_result
(** record that all the array elements that address points to is invalid *) (** record that all the array elements that address points to is invalid *)
val shallow_copy :
Location.t -> PulseDomain.AddrTracePair.t -> t -> (t * AbstractAddress.t) access_result
(** returns the address of a new cell with the same edges as the original *)
val remove_vars : Var.t list -> t -> t val remove_vars : Var.t list -> t -> t
val check_address_escape : val check_address_escape :

@ -13,7 +13,7 @@ struct S {
~S() {} ~S() {}
}; };
int FN_ref_capture_destroy_invoke_bad() { int ref_capture_destroy_invoke_bad() {
std::function<int()> f; std::function<int()> f;
{ {
S s; S s;
@ -22,7 +22,7 @@ int FN_ref_capture_destroy_invoke_bad() {
return f(); // s used here return f(); // s used here
} }
int FN_implicit_ref_capture_destroy_invoke_bad() { int implicit_ref_capture_destroy_invoke_bad() {
std::function<int()> f; std::function<int()> f;
{ {
auto s = S(); auto s = S();
@ -44,7 +44,7 @@ int FN_reassign_lambda_capture_destroy_invoke_bad() {
// frontend doesn't understand difference between capture-by-value and // frontend doesn't understand difference between capture-by-value and
// capture-by-ref, need to fix // capture-by-ref, need to fix
int value_capture_destroy_invoke_ok() { int FP_value_capture_destroy_invoke_ok() {
std::function<int()> f; std::function<int()> f;
{ {
S s; S s;
@ -54,7 +54,7 @@ int value_capture_destroy_invoke_ok() {
} }
// same thing here // same thing here
int implicit_value_capture_destroy_invoke_ok() { int FP_implicit_value_capture_destroy_invoke_ok() {
std::function<int()> f; std::function<int()> f;
{ {
S s; S s;

@ -1,5 +1,9 @@
codetoanalyze/cpp/pulse/basics.cpp, multiple_invalidations_branch_bad, 6, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,invalid access occurs here here] codetoanalyze/cpp/pulse/basics.cpp, multiple_invalidations_branch_bad, 6, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,invalid access occurs here here]
codetoanalyze/cpp/pulse/basics.cpp, multiple_invalidations_loop_bad, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,invalid access occurs here here] codetoanalyze/cpp/pulse/basics.cpp, multiple_invalidations_loop_bad, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,invalid access occurs here here]
codetoanalyze/cpp/pulse/closures.cpp, FP_implicit_value_capture_destroy_invoke_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidation part of the trace starts here,variable declared,memory is the address of a stack variable `s` whose lifetime has ended here,use-after-lifetime part of the trace starts here,value captured as `&s`,invalid access occurs here here]
codetoanalyze/cpp/pulse/closures.cpp, FP_value_capture_destroy_invoke_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidation part of the trace starts here,variable declared,memory is the address of a stack variable `s` whose lifetime has ended here,use-after-lifetime part of the trace starts here,value captured as `&s`,invalid access occurs here here]
codetoanalyze/cpp/pulse/closures.cpp, implicit_ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidation part of the trace starts here,variable declared,memory is the address of a stack variable `s` whose lifetime has ended here,use-after-lifetime part of the trace starts here,variable declared,value captured as `&s`,invalid access occurs here here]
codetoanalyze/cpp/pulse/closures.cpp, ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidation part of the trace starts here,variable declared,memory is the address of a stack variable `s` whose lifetime has ended here,use-after-lifetime part of the trace starts here,variable declared,value captured as `&s`,invalid access occurs here here]
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int*>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `templated_wrapper_delete_ok` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,when calling `templated_wrapper_access_ok` here,invalid access occurs here here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int*>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `templated_wrapper_delete_ok` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,when calling `templated_wrapper_access_ok` here,invalid access occurs here here]
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `templated_wrapper_delete_ok` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,when calling `templated_wrapper_access_ok` here,invalid access occurs here here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `templated_wrapper_delete_ok` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,when calling `templated_wrapper_access_ok` here,invalid access occurs here here]
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<_Bool>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `deduplication::templated_delete_function` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function` here,invalid access occurs here here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<_Bool>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `deduplication::templated_delete_function` here,memory was invalidated by `delete` here,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function` here,invalid access occurs here here]

Loading…
Cancel
Save