[pulse] Adding null case to malloc's model

Summary:
Malloc returns either an allocated object or a null pointer if there is no memory available. Modelling that.
This has always been a bit contentious because this leads to NPEs that people often ignores because they don't care. But if we don't model this, then we have FPs when people do take this into account when freeing the memory.

Reviewed By: jvillard

Differential Revision: D20791692

fbshipit-source-id: 6fd259f12
master
Dulma Churchill 5 years ago committed by Facebook GitHub Bot
parent 1cb973b44f
commit dba4140a7b

@ -31,6 +31,9 @@ module ItvPure : sig
val nat : t val nat : t
val pos : t
(** [1, +oo] *)
val of_int : int -> t val of_int : int -> t
val lb : t -> Bound.t val lb : t -> Bound.t

@ -121,6 +121,8 @@ module Unsafe : sig
val equal_to : IntLit.t -> t val equal_to : IntLit.t -> t
val not_equal_to : IntLit.t -> t val not_equal_to : IntLit.t -> t
val ge_to : IntLit.t -> t
end = struct end = struct
type t = Between of Bound.t * Bound.t | Outside of IntLit.t * IntLit.t [@@deriving compare] type t = Between of Bound.t * Bound.t | Outside of IntLit.t * IntLit.t [@@deriving compare]
@ -140,6 +142,10 @@ end = struct
let not_equal_to i = Outside (i, i) let not_equal_to i = Outside (i, i)
let ge_to i =
let b = Bound.Int i in
Between (b, Bound.PlusInfinity)
end end
include Unsafe include Unsafe

@ -39,3 +39,5 @@ val binop : Binop.t -> t -> t -> t option
val unop : Unop.t -> t -> t option val unop : Unop.t -> t -> t option
val zero_inf : t val zero_inf : t
val ge_to : IntLit.t -> t

@ -88,10 +88,25 @@ module C = struct
[astate] [astate]
let malloc access : model = let malloc _ : model =
fun ~caller_summary:_ ~callee_procname location ~ret:(ret_id, _) astate -> fun ~caller_summary:_ ~callee_procname location ~ret:(ret_id, _) astate ->
let astate = PulseOperations.allocate callee_procname location access astate in let ret_addr = AbstractValue.mk_fresh () in
Ok [PulseOperations.write_id ret_id access astate] let astate_alloc =
PulseOperations.allocate callee_procname location (ret_addr, []) astate
|> PulseOperations.write_id ret_id (ret_addr, [])
|> AddressAttributes.add_one ret_addr (BoItv Itv.ItvPure.pos)
|> AddressAttributes.add_one ret_addr
(CItv (CItv.ge_to IntLit.one, Immediate {location; history= []}))
in
let+ astate_null =
AddressAttributes.add_one ret_addr (BoItv (Itv.ItvPure.of_int_lit IntLit.zero)) astate
|> AddressAttributes.add_one ret_addr
(CItv (CItv.equal_to IntLit.zero, Immediate {location; history= []}))
|> PulseOperations.write_id ret_id (ret_addr, [])
|> PulseOperations.invalidate location (Invalidation.ConstantDereference IntLit.zero)
(ret_addr, [])
in
[astate_alloc; astate_null]
end end
module Cplusplus = struct module Cplusplus = struct

@ -15,8 +15,10 @@ int* malloc_returned_ok() {
void malloc_then_free_ok() { void malloc_then_free_ok() {
int* p = malloc(sizeof(p)); int* p = malloc(sizeof(p));
*p = 5; if (p) {
free(p); *p = 5;
free(p);
}
} }
int* create_p() { int* create_p() {

Loading…
Cancel
Save