|
|
@ -43,7 +43,8 @@ type mem_kind =
|
|
|
|
| Mmalloc /** memory allocated with malloc */
|
|
|
|
| Mmalloc /** memory allocated with malloc */
|
|
|
|
| Mnew /** memory allocated with new */
|
|
|
|
| Mnew /** memory allocated with new */
|
|
|
|
| Mnew_array /** memory allocated with new[] */
|
|
|
|
| Mnew_array /** memory allocated with new[] */
|
|
|
|
| Mobjc /** memory allocated with objective-c alloc */;
|
|
|
|
| Mobjc /** memory allocated with objective-c alloc */
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
let mem_kind_to_num =
|
|
|
|
let mem_kind_to_num =
|
|
|
|
fun
|
|
|
|
fun
|
|
|
@ -52,39 +53,21 @@ let mem_kind_to_num =
|
|
|
|
| Mnew_array => 2
|
|
|
|
| Mnew_array => 2
|
|
|
|
| Mobjc => 3;
|
|
|
|
| Mobjc => 3;
|
|
|
|
|
|
|
|
|
|
|
|
let mem_kind_compare mk1 mk2 => int_compare (mem_kind_to_num mk1) (mem_kind_to_num mk2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** resource that can be allocated */
|
|
|
|
/** resource that can be allocated */
|
|
|
|
type resource =
|
|
|
|
type resource =
|
|
|
|
| Rmemory mem_kind
|
|
|
|
| Rmemory mem_kind
|
|
|
|
| Rfile
|
|
|
|
| Rfile
|
|
|
|
| Rignore
|
|
|
|
| Rignore
|
|
|
|
| Rlock;
|
|
|
|
| Rlock
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let resource_compare r1 r2 => {
|
|
|
|
|
|
|
|
let res_to_num =
|
|
|
|
|
|
|
|
fun
|
|
|
|
|
|
|
|
| Rmemory mk => mem_kind_to_num mk
|
|
|
|
|
|
|
|
| Rfile => 100
|
|
|
|
|
|
|
|
| Rignore => 200
|
|
|
|
|
|
|
|
| Rlock => 300;
|
|
|
|
|
|
|
|
int_compare (res_to_num r1) (res_to_num r2)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** kind of resource action */
|
|
|
|
/** kind of resource action */
|
|
|
|
type res_act_kind =
|
|
|
|
type res_act_kind =
|
|
|
|
| Racquire
|
|
|
|
| Racquire
|
|
|
|
| Rrelease;
|
|
|
|
| Rrelease
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let res_act_kind_compare rak1 rak2 =>
|
|
|
|
|
|
|
|
switch (rak1, rak2) {
|
|
|
|
|
|
|
|
| (Racquire, Racquire) => 0
|
|
|
|
|
|
|
|
| (Racquire, Rrelease) => (-1)
|
|
|
|
|
|
|
|
| (Rrelease, Racquire) => 1
|
|
|
|
|
|
|
|
| (Rrelease, Rrelease) => 0
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** kind of dangling pointers */
|
|
|
|
/** kind of dangling pointers */
|
|
|
@ -95,62 +78,24 @@ type dangling_kind =
|
|
|
|
of a stack variable which went out of scope */
|
|
|
|
of a stack variable which went out of scope */
|
|
|
|
| DAaddr_stack_var
|
|
|
|
| DAaddr_stack_var
|
|
|
|
/** pointer is -1 */
|
|
|
|
/** pointer is -1 */
|
|
|
|
| DAminusone;
|
|
|
|
| DAminusone
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let dangling_kind_compare dk1 dk2 =>
|
|
|
|
|
|
|
|
switch (dk1, dk2) {
|
|
|
|
|
|
|
|
| (DAuninit, DAuninit) => 0
|
|
|
|
|
|
|
|
| (DAuninit, _) => (-1)
|
|
|
|
|
|
|
|
| (_, DAuninit) => 1
|
|
|
|
|
|
|
|
| (DAaddr_stack_var, DAaddr_stack_var) => 0
|
|
|
|
|
|
|
|
| (DAaddr_stack_var, _) => (-1)
|
|
|
|
|
|
|
|
| (_, DAaddr_stack_var) => 1
|
|
|
|
|
|
|
|
| (DAminusone, DAminusone) => 0
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** position in a path: proc name, node id */
|
|
|
|
/** position in a path: proc name, node id */
|
|
|
|
type path_pos = (Procname.t, int);
|
|
|
|
type path_pos = (Procname.t, int) [@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
let path_pos_compare (pn1, nid1) (pn2, nid2) => {
|
|
|
|
|
|
|
|
let n = Procname.compare pn1 pn2;
|
|
|
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
|
|
|
n
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
int_compare nid1 nid2
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let path_pos_equal pp1 pp2 => path_pos_compare pp1 pp2 == 0;
|
|
|
|
let equal_path_pos pp1 pp2 => compare_path_pos pp1 pp2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
type taint_kind =
|
|
|
|
type taint_kind =
|
|
|
|
| Tk_unverified_SSL_socket
|
|
|
|
| Tk_unverified_SSL_socket
|
|
|
|
| Tk_shared_preferences_data
|
|
|
|
| Tk_shared_preferences_data
|
|
|
|
| Tk_privacy_annotation
|
|
|
|
| Tk_privacy_annotation
|
|
|
|
| Tk_integrity_annotation
|
|
|
|
| Tk_integrity_annotation
|
|
|
|
| Tk_unknown;
|
|
|
|
| Tk_unknown
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let taint_kind_compare tk1 tk2 =>
|
|
|
|
|
|
|
|
switch (tk1, tk2) {
|
|
|
|
|
|
|
|
| (Tk_unverified_SSL_socket, Tk_unverified_SSL_socket) => 0
|
|
|
|
|
|
|
|
| (Tk_unverified_SSL_socket, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Tk_unverified_SSL_socket) => 1
|
|
|
|
|
|
|
|
| (Tk_shared_preferences_data, Tk_shared_preferences_data) => 0
|
|
|
|
|
|
|
|
| (Tk_shared_preferences_data, _) => 1
|
|
|
|
|
|
|
|
| (_, Tk_shared_preferences_data) => (-1)
|
|
|
|
|
|
|
|
| (Tk_privacy_annotation, Tk_privacy_annotation) => 0
|
|
|
|
|
|
|
|
| (Tk_privacy_annotation, _) => 1
|
|
|
|
|
|
|
|
| (_, Tk_privacy_annotation) => (-1)
|
|
|
|
|
|
|
|
| (Tk_integrity_annotation, Tk_integrity_annotation) => 0
|
|
|
|
|
|
|
|
| (Tk_integrity_annotation, _) => 1
|
|
|
|
|
|
|
|
| (_, Tk_integrity_annotation) => (-1)
|
|
|
|
|
|
|
|
| (Tk_unknown, Tk_unknown) => 0
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type taint_info = {taint_source: Procname.t, taint_kind: taint_kind};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let taint_info_compare {taint_source: ts1, taint_kind: tk1} {taint_source: ts2, taint_kind: tk2} =>
|
|
|
|
type taint_info = {taint_source: Procname.t, taint_kind: taint_kind} [@@deriving compare];
|
|
|
|
taint_kind_compare tk1 tk2 |> next Procname.compare ts1 ts2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** acquire/release action on a resource */
|
|
|
|
/** acquire/release action on a resource */
|
|
|
@ -162,6 +107,23 @@ type res_action = {
|
|
|
|
ra_vpath: DecompiledExp.vpath /** vpath of the resource value */
|
|
|
|
ra_vpath: DecompiledExp.vpath /** vpath of the resource value */
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ignore other values beside resources: arbitrary merging into one */
|
|
|
|
|
|
|
|
let compare_res_action {ra_kind: k1, ra_res: r1} {ra_kind: k2, ra_res: r2} =>
|
|
|
|
|
|
|
|
[%compare : (res_act_kind, resource)] (k1, r1) (k2, r2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* type aliases for components of t values that compare should ignore */
|
|
|
|
|
|
|
|
type _annot_item = Annot.Item.t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let compare__annot_item _ _ => 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type _location = Location.t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let compare__location _ _ => 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type _path_pos = path_pos;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let compare__path_pos _ _ => 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Attributes are nary function symbols that are applied to expression arguments in Apred and
|
|
|
|
/** Attributes are nary function symbols that are applied to expression arguments in Apred and
|
|
|
|
Anpred atomic formulas. Many operations don't make much sense for nullary predicates, and are
|
|
|
|
Anpred atomic formulas. Many operations don't make much sense for nullary predicates, and are
|
|
|
@ -176,7 +138,7 @@ type t =
|
|
|
|
| Aautorelease
|
|
|
|
| Aautorelease
|
|
|
|
| Adangling dangling_kind /** dangling pointer */
|
|
|
|
| Adangling dangling_kind /** dangling pointer */
|
|
|
|
/** undefined value obtained by calling the given procedure, plus its return value annots */
|
|
|
|
/** undefined value obtained by calling the given procedure, plus its return value annots */
|
|
|
|
| Aundef Procname.t Annot.Item.t Location.t path_pos
|
|
|
|
| Aundef Procname.t _annot_item _location _path_pos
|
|
|
|
| Ataint taint_info
|
|
|
|
| Ataint taint_info
|
|
|
|
| Auntaint taint_info
|
|
|
|
| Auntaint taint_info
|
|
|
|
| Alocked
|
|
|
|
| Alocked
|
|
|
@ -190,62 +152,8 @@ type t =
|
|
|
|
/** denotes an object registered as an observers to a notification center */
|
|
|
|
/** denotes an object registered as an observers to a notification center */
|
|
|
|
| Aobserver
|
|
|
|
| Aobserver
|
|
|
|
/** denotes an object unsubscribed from observers of a notification center */
|
|
|
|
/** denotes an object unsubscribed from observers of a notification center */
|
|
|
|
| Aunsubscribed_observer;
|
|
|
|
| Aunsubscribed_observer
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let compare (att1: t) (att2: t) :int =>
|
|
|
|
|
|
|
|
switch (att1, att2) {
|
|
|
|
|
|
|
|
| (Aresource ra1, Aresource ra2) =>
|
|
|
|
|
|
|
|
let n = res_act_kind_compare ra1.ra_kind ra2.ra_kind;
|
|
|
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
|
|
|
n
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* ignore other values beside resources: arbitrary merging into one */
|
|
|
|
|
|
|
|
resource_compare
|
|
|
|
|
|
|
|
ra1.ra_res ra2.ra_res
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
| (Aresource _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aresource _) => 1
|
|
|
|
|
|
|
|
| (Aautorelease, Aautorelease) => 0
|
|
|
|
|
|
|
|
| (Aautorelease, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aautorelease) => 1
|
|
|
|
|
|
|
|
| (Adangling dk1, Adangling dk2) => dangling_kind_compare dk1 dk2
|
|
|
|
|
|
|
|
| (Adangling _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Adangling _) => 1
|
|
|
|
|
|
|
|
| (Aundef pn1 _ _ _, Aundef pn2 _ _ _) => Procname.compare pn1 pn2
|
|
|
|
|
|
|
|
| (Ataint ti1, Ataint ti2) => taint_info_compare ti1 ti2
|
|
|
|
|
|
|
|
| (Ataint _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Ataint _) => 1
|
|
|
|
|
|
|
|
| (Auntaint ti1, Auntaint ti2) => taint_info_compare ti1 ti2
|
|
|
|
|
|
|
|
| (Auntaint _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Auntaint _) => 1
|
|
|
|
|
|
|
|
| (Alocked, Alocked) => 0
|
|
|
|
|
|
|
|
| (Alocked, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Alocked) => 1
|
|
|
|
|
|
|
|
| (Aunlocked, Aunlocked) => 0
|
|
|
|
|
|
|
|
| (Aunlocked, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aunlocked) => 1
|
|
|
|
|
|
|
|
| (Adiv0 pp1, Adiv0 pp2) => path_pos_compare pp1 pp2
|
|
|
|
|
|
|
|
| (Adiv0 _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Adiv0 _) => 1
|
|
|
|
|
|
|
|
| (Aobjc_null, Aobjc_null) => 0
|
|
|
|
|
|
|
|
| (Aobjc_null, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aobjc_null) => 1
|
|
|
|
|
|
|
|
| (Aretval pn1 annots1, Aretval pn2 annots2) =>
|
|
|
|
|
|
|
|
let n = Procname.compare pn1 pn2;
|
|
|
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
|
|
|
n
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Annot.Item.compare annots1 annots2
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
| (Aretval _, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aretval _) => 1
|
|
|
|
|
|
|
|
| (Aobserver, Aobserver) => 0
|
|
|
|
|
|
|
|
| (Aobserver, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aobserver) => 1
|
|
|
|
|
|
|
|
| (Aunsubscribed_observer, Aunsubscribed_observer) => 0
|
|
|
|
|
|
|
|
| (Aunsubscribed_observer, _) => (-1)
|
|
|
|
|
|
|
|
| (_, Aunsubscribed_observer) => 1
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let equal att1 att2 => compare att1 att2 == 0;
|
|
|
|
let equal att1 att2 => compare att1 att2 == 0;
|
|
|
|
|
|
|
|
|
|
|
@ -278,11 +186,10 @@ type category =
|
|
|
|
| ACobjc_null
|
|
|
|
| ACobjc_null
|
|
|
|
| ACundef
|
|
|
|
| ACundef
|
|
|
|
| ACretval
|
|
|
|
| ACretval
|
|
|
|
| ACobserver;
|
|
|
|
| ACobserver
|
|
|
|
|
|
|
|
[@@deriving compare];
|
|
|
|
let category_compare (ac1: category) (ac2: category) :int => Pervasives.compare ac1 ac2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let category_equal att1 att2 => category_compare att1 att2 == 0;
|
|
|
|
let equal_category att1 att2 => compare_category att1 att2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
let to_category att =>
|
|
|
|
let to_category att =>
|
|
|
|
switch att {
|
|
|
|
switch att {
|
|
|
|