Represent attributes with atoms, not disequalities

Summary:
Replace disequalities to Attribute expressions with predicate symbol
application pure atomic formulas.

This diff should preserve existing behavior, up to the comparison order
of attribute disequalities versus predicate applications.

Reviewed By: sblackshear

Differential Revision: D3647049

fbshipit-source-id: c39a901
master
Josh Berdine 9 years ago committed by Facebook Github Bot 8
parent e3132152cb
commit 71a15b2388

@ -962,6 +962,7 @@ let remove_abducted_retvars p =>
fun fun
| Sil.Aeq lhs rhs | Sil.Aeq lhs rhs
| Sil.Aneq lhs rhs => exp_contains lhs || exp_contains rhs | Sil.Aneq lhs rhs => exp_contains lhs || exp_contains rhs
| Sil.Apred _ _ e => exp_contains e
) )
pi pi
}; };

@ -137,9 +137,7 @@ and exp =
The [dynamic_length], tracked by symbolic execution, may differ from the [static_length] The [dynamic_length], tracked by symbolic execution, may differ from the [static_length]
obtained from the type definition, e.g. when an array is over-allocated. For struct types, obtained from the type definition, e.g. when an array is over-allocated. For struct types,
the [dynamic_length] is that of the final extensible array, if any. */ the [dynamic_length] is that of the final extensible array, if any. */
| Sizeof of Typ.t dynamic_length Subtype.t | Sizeof of Typ.t dynamic_length Subtype.t;
/** attribute used in disequalities to annotate a value */
| Attribute of attribute;
/** Kind of prune instruction */ /** Kind of prune instruction */
@ -204,7 +202,8 @@ type offset = | Off_fld of Ident.fieldname Typ.t | Off_index of exp;
/** an atom is a pure atomic formula */ /** an atom is a pure atomic formula */
type atom = type atom =
| Aeq of exp exp /** equality */ | Aeq of exp exp /** equality */
| Aneq of exp exp /** disequality*/; | Aneq of exp exp /** disequality */
| Apred of bool attribute exp /** possibly negated predicate symbol applied to an exp */;
/** kind of lseg or dllseg predicates */ /** kind of lseg or dllseg predicates */
@ -660,9 +659,6 @@ let rec exp_compare (e1: exp) (e2: exp) :int =>
Subtype.compare s1 s2 Subtype.compare s1 s2
} }
} }
| (Attribute att1, Attribute att2) => attribute_compare att1 att2
| (Attribute _, _) => (-1)
| (_, Attribute _) => 1
}; };
let exp_equal e1 e2 => exp_compare e1 e2 == 0; let exp_equal e1 e2 => exp_compare e1 e2 == 0;
@ -697,8 +693,8 @@ let atom_compare a b =>
} else { } else {
exp_compare e2 f2 exp_compare e2 f2
} }
| (Aeq _, Aneq _) => (-1) | (Aeq _, _) => (-1)
| (Aneq _, Aeq _) => 1 | (_, Aeq _) => 1
| (Aneq e1 e2, Aneq f1 f2) => | (Aneq e1 e2, Aneq f1 f2) =>
let n = exp_compare e1 f1; let n = exp_compare e1 f1;
if (n != 0) { if (n != 0) {
@ -706,6 +702,20 @@ let atom_compare a b =>
} else { } else {
exp_compare e2 f2 exp_compare e2 f2
} }
| (Aneq _, _) => (-1)
| (_, Aneq _) => 1
| (Apred b1 a1 e1, Apred b2 a2 e2) =>
let n = bool_compare b1 b2;
if (n != 0) {
n
} else {
let n = attribute_compare a1 a2;
if (n != 0) {
n
} else {
exp_compare e1 e2
}
}
} }
}; };
@ -1086,7 +1096,6 @@ let rec _pp_exp pe0 pp_t f e0 => {
| Sizeof t l s => | Sizeof t l s =>
let pp_len f l => Option.map_default (F.fprintf f "[%a]" pp_exp) () l; let pp_len f l => Option.map_default (F.fprintf f "[%a]" pp_exp) () l;
F.fprintf f "sizeof(%a%a%a)" pp_t t pp_len l Subtype.pp s F.fprintf f "sizeof(%a%a%a)" pp_t t pp_len l Subtype.pp s
| Attribute att => F.fprintf f "%s" (attribute_to_string pe att)
} }
}; };
color_post_wrapper changed pe0 f color_post_wrapper changed pe0 f
@ -1266,19 +1275,22 @@ let pp_atom pe0 f a => {
| PP_HTML => F.fprintf f "%a = %a" (pp_exp pe) e1 (pp_exp pe) e2 | PP_HTML => F.fprintf f "%a = %a" (pp_exp pe) e1 (pp_exp pe) e2
| PP_LATEX => F.fprintf f "%a{=}%a" (pp_exp pe) e1 (pp_exp pe) e2 | PP_LATEX => F.fprintf f "%a{=}%a" (pp_exp pe) e1 (pp_exp pe) e2
} }
| Aneq (Attribute _ as ea) e
| Aneq e (Attribute _ as ea) => F.fprintf f "%a(%a)" (pp_exp pe) ea (pp_exp pe) e
| Aneq e1 e2 => | Aneq e1 e2 =>
switch pe.pe_kind { switch pe.pe_kind {
| PP_TEXT | PP_TEXT
| PP_HTML => F.fprintf f "%a != %a" (pp_exp pe) e1 (pp_exp pe) e2 | PP_HTML => F.fprintf f "%a != %a" (pp_exp pe) e1 (pp_exp pe) e2
| PP_LATEX => F.fprintf f "%a{\\neq}%a" (pp_exp pe) e1 (pp_exp pe) e2 | PP_LATEX => F.fprintf f "%a{\\neq}%a" (pp_exp pe) e1 (pp_exp pe) e2
} }
| Apred b a e => F.fprintf f "%s%s(%a)" (b ? "" : "!") (attribute_to_string pe a) (pp_exp pe) e
}; };
color_post_wrapper changed pe0 f color_post_wrapper changed pe0 f
}; };
/** dump an attribute */
let d_attribute (a: attribute) => L.add_print_action (L.PTattribute, Obj.repr a);
/** dump an atom */ /** dump an atom */
let d_atom (a: atom) => L.add_print_action (L.PTatom, Obj.repr a); let d_atom (a: atom) => L.add_print_action (L.PTatom, Obj.repr a);
@ -1923,7 +1935,8 @@ let hpred_list_expmap (f: (exp, option inst) => (exp, option inst)) (hlist: list
let atom_expmap (f: exp => exp) => let atom_expmap (f: exp => exp) =>
fun fun
| Aeq e1 e2 => Aeq (f e1) (f e2) | Aeq e1 e2 => Aeq (f e1) (f e2)
| Aneq e1 e2 => Aneq (f e1) (f e2); | Aneq e1 e2 => Aneq (f e1) (f e2)
| Apred b a e => Apred b a (f e);
let atom_list_expmap (f: exp => exp) (alist: list atom) => IList.map (atom_expmap f) alist; let atom_list_expmap (f: exp => exp) (alist: list atom) => IList.map (atom_expmap f) alist;
@ -1964,7 +1977,6 @@ let rec root_of_lexp lexp =>
| Lfield e _ _ => root_of_lexp e | Lfield e _ _ => root_of_lexp e
| Lindex e _ => root_of_lexp e | Lindex e _ => root_of_lexp e
| Sizeof _ => lexp | Sizeof _ => lexp
| Attribute _ => lexp
}; };
@ -2053,15 +2065,15 @@ let rec exp_fpv =
/* TODO: Sizeof length expressions may contain variables, do not ignore them. */ /* TODO: Sizeof length expressions may contain variables, do not ignore them. */
/* | Sizeof _ None _ => [] */ /* | Sizeof _ None _ => [] */
/* | Sizeof _ (Some l) _ => exp_fpv l */ /* | Sizeof _ (Some l) _ => exp_fpv l */
| Sizeof _ _ _ => [] | Sizeof _ _ _ => [];
| Attribute _ => [];
let exp_list_fpv el => IList.flatten (IList.map exp_fpv el); let exp_list_fpv el => IList.flatten (IList.map exp_fpv el);
let atom_fpv = let atom_fpv =
fun fun
| Aeq e1 e2 => exp_fpv e1 @ exp_fpv e2 | Aeq e1 e2 => exp_fpv e1 @ exp_fpv e2
| Aneq e1 e2 => exp_fpv e1 @ exp_fpv e2; | Aneq e1 e2 => exp_fpv e1 @ exp_fpv e2
| Apred _ _ e => exp_fpv e;
let rec strexp_fpv = let rec strexp_fpv =
fun fun
@ -2253,8 +2265,7 @@ let rec exp_fav_add fav =>
/* TODO: Sizeof length expressions may contain variables, do not ignore them. */ /* TODO: Sizeof length expressions may contain variables, do not ignore them. */
/* | Sizeof _ None _ => () */ /* | Sizeof _ None _ => () */
/* | Sizeof _ (Some l) _ => exp_fav_add fav l; */ /* | Sizeof _ (Some l) _ => exp_fav_add fav l; */
| Sizeof _ _ _ => () | Sizeof _ _ _ => ();
| Attribute _ => ();
let exp_fav = fav_imperative_to_functional exp_fav_add; let exp_fav = fav_imperative_to_functional exp_fav_add;
@ -2272,7 +2283,8 @@ let atom_fav_add fav =>
| Aneq e1 e2 => { | Aneq e1 e2 => {
exp_fav_add fav e1; exp_fav_add fav e1;
exp_fav_add fav e2 exp_fav_add fav e2
}; }
| Apred _ _ e => exp_fav_add fav e;
let atom_fav = fav_imperative_to_functional atom_fav_add; let atom_fav = fav_imperative_to_functional atom_fav_add;
@ -2710,7 +2722,6 @@ let rec exp_sub_ids (f: Ident.t => exp) exp =>
} }
| None => exp | None => exp
} }
| Attribute _ => exp
}; };
let rec apply_sub subst id => let rec apply_sub subst id =>
@ -3204,7 +3215,8 @@ let atom_replace_exp epairs =>
let e1' = exp_replace_exp epairs e1; let e1' = exp_replace_exp epairs e1;
let e2' = exp_replace_exp epairs e2; let e2' = exp_replace_exp epairs e2;
Aneq e1' e2' Aneq e1' e2'
}; }
| Apred b a e => Apred b a (exp_replace_exp epairs e);
let rec strexp_replace_exp epairs => let rec strexp_replace_exp epairs =>
fun fun
@ -3326,7 +3338,6 @@ let exp_get_vars exp => {
/* | Sizeof _ None _ => vars */ /* | Sizeof _ None _ => vars */
/* | Sizeof _ (Some l) _ => exp_get_vars_ l vars */ /* | Sizeof _ (Some l) _ => exp_get_vars_ l vars */
| Sizeof _ _ _ => vars | Sizeof _ _ _ => vars
| Attribute _ => vars
}; };
exp_get_vars_ exp ([], []) exp_get_vars_ exp ([], [])
}; };
@ -3343,7 +3354,6 @@ let exp_get_offsets exp => {
| Exn _ | Exn _
| Closure _ | Closure _
| Lvar _ | Lvar _
| Attribute _
| Sizeof _ None _ => offlist_past | Sizeof _ None _ => offlist_past
| Sizeof _ (Some l) _ => f offlist_past l | Sizeof _ (Some l) _ => f offlist_past l
| Cast _ sub_exp => f offlist_past sub_exp | Cast _ sub_exp => f offlist_past sub_exp

@ -125,9 +125,7 @@ and exp =
The [dynamic_length], tracked by symbolic execution, may differ from the [static_length] The [dynamic_length], tracked by symbolic execution, may differ from the [static_length]
obtained from the type definition, e.g. when an array is over-allocated. For struct types, obtained from the type definition, e.g. when an array is over-allocated. For struct types,
the [dynamic_length] is that of the final extensible array, if any. */ the [dynamic_length] is that of the final extensible array, if any. */
| Sizeof of Typ.t dynamic_length Subtype.t | Sizeof of Typ.t dynamic_length Subtype.t;
/** attribute used in disequalities to annotate a value */
| Attribute of attribute;
/** Sets of expressions. */ /** Sets of expressions. */
@ -198,7 +196,8 @@ type offset = | Off_fld of Ident.fieldname Typ.t | Off_index of exp;
/** an atom is a pure atomic formula */ /** an atom is a pure atomic formula */
type atom = type atom =
| Aeq of exp exp /** equality */ | Aeq of exp exp /** equality */
| Aneq of exp exp /** disequality*/; | Aneq of exp exp /** disequality */
| Apred of bool attribute exp /** possibly negated predicate symbol applied to an exp */;
/** kind of lseg or dllseg predicates */ /** kind of lseg or dllseg predicates */
@ -591,6 +590,10 @@ let d_instr_list: list instr => unit;
let pp_atom: printenv => F.formatter => atom => unit; let pp_atom: printenv => F.formatter => atom => unit;
/** Dump an attribute. */
let d_attribute: attribute => unit;
/** Dump an atom. */ /** Dump an atom. */
let d_atom: atom => unit; let d_atom: atom => unit;

@ -776,7 +776,6 @@ let abstract_pure_part p ~(from_abstract_footprint: bool) =
IList.fold_left IList.fold_left
(fun pi a -> (fun pi a ->
match a with match a with
| Sil.Aneq (Sil.Var _, _) -> a:: pi
(* we only use Lt and Le because Gt and Ge are inserted in terms of Lt and Le. *) (* we only use Lt and Le because Gt and Ge are inserted in terms of Lt and Le. *)
| Sil.Aeq (Sil.Const (Const.Cint i), Sil.BinOp (Binop.Lt, _, _)) | Sil.Aeq (Sil.Const (Const.Cint i), Sil.BinOp (Binop.Lt, _, _))
| Sil.Aeq (Sil.BinOp (Binop.Lt, _, _), Sil.Const (Const.Cint i)) | Sil.Aeq (Sil.BinOp (Binop.Lt, _, _), Sil.Const (Const.Cint i))
@ -788,7 +787,10 @@ let abstract_pure_part p ~(from_abstract_footprint: bool) =
| Sil.Var _ | Sil.Var _
| Sil.Const _ -> a :: pi | Sil.Const _ -> a :: pi
| _ -> pi) | _ -> pi)
| _ -> pi) | Sil.Aneq (Var _, _)
| Sil.Apred (_, _, Var _) -> a :: pi
| Sil.Aeq _ | Aneq _ | Apred _ -> pi
)
[] pi_filtered in [] pi_filtered in
IList.rev new_pure in IList.rev new_pure in
@ -817,7 +819,12 @@ let abstract_gc p =
let intersect_e2 _ = IList.intersect Ident.compare (Sil.fav_to_list fav_e2) (Sil.fav_to_list fav_p_without_pi) in let intersect_e2 _ = IList.intersect Ident.compare (Sil.fav_to_list fav_e2) (Sil.fav_to_list fav_p_without_pi) in
let no_fav_e1 = Sil.fav_is_empty fav_e1 in let no_fav_e1 = Sil.fav_is_empty fav_e1 in
let no_fav_e2 = Sil.fav_is_empty fav_e2 in let no_fav_e2 = Sil.fav_is_empty fav_e2 in
(no_fav_e1 || intersect_e1 ()) && (no_fav_e2 || intersect_e2 ()) in (no_fav_e1 || intersect_e1 ()) && (no_fav_e2 || intersect_e2 ())
| Sil.Apred (_, _, e) ->
let fav_e = Sil.exp_fav e in
Sil.fav_is_empty fav_e
||
IList.intersect Ident.compare (Sil.fav_to_list fav_e) (Sil.fav_to_list fav_p_without_pi) in
let new_pi = IList.filter strong_filter pi in let new_pi = IList.filter strong_filter pi in
let prop = Prop.normalize (Prop.replace_pi new_pi p) in let prop = Prop.normalize (Prop.replace_pi new_pi p) in
match Prop.prop_iter_create prop with match Prop.prop_iter_create prop with
@ -1094,7 +1101,7 @@ let check_junk ?original_prop pname tenv prop =
check_observer_is_unsubscribed_deallocation prop e; check_observer_is_unsubscribed_deallocation prop e;
match Prop.get_resource_attribute prop e with match Prop.get_resource_attribute prop e with
| Some (Sil.Aresource ({ Sil.ra_kind = Sil.Racquire }) as a) -> | Some (Sil.Aresource ({ Sil.ra_kind = Sil.Racquire }) as a) ->
L.d_str "ATTRIBUTE: "; Sil.d_exp (Sil.Attribute a); L.d_ln (); L.d_str "ATTRIBUTE: "; Sil.d_attribute a; L.d_ln ();
res := Some a res := Some a
| _ -> | _ ->
(match Prop.get_undef_attribute prop e with (match Prop.get_undef_attribute prop e with

@ -718,6 +718,10 @@ end = struct
when (exp_contains_only_normal_ids e' && not (Ident.is_normal id)) -> when (exp_contains_only_normal_ids e' && not (Ident.is_normal id)) ->
build_other_atoms (fun e0 -> Prop.mk_neq e0 e') side e build_other_atoms (fun e0 -> Prop.mk_neq e0 e') side e
| Sil.Apred (b, a, (Var id as e))
when not (Ident.is_normal id) ->
build_other_atoms (fun e0 -> Prop.mk_pred b a e0) side e
| Sil.Aeq((Sil.Var id as e), e') | Sil.Aeq(e', (Sil.Var id as e)) | Sil.Aeq((Sil.Var id as e), e') | Sil.Aeq(e', (Sil.Var id as e))
when (exp_contains_only_normal_ids e' && not (Ident.is_normal id)) -> when (exp_contains_only_normal_ids e' && not (Ident.is_normal id)) ->
build_other_atoms (fun e0 -> Prop.mk_eq e0 e') side e build_other_atoms (fun e0 -> Prop.mk_eq e0 e') side e
@ -734,7 +738,7 @@ end = struct
let construct e0 = Prop.mk_inequality (Sil.BinOp(Binop.Lt, e', e0)) in let construct e0 = Prop.mk_inequality (Sil.BinOp(Binop.Lt, e', e0)) in
build_other_atoms construct side e build_other_atoms construct side e
| _ -> None | Sil.Aeq _ | Aneq _ | Apred _ -> None
end end
type data_opt = ExtFresh | ExtDefault of Sil.exp type data_opt = ExtFresh | ExtDefault of Sil.exp
@ -828,8 +832,6 @@ let rec exp_construct_fresh side e =
e e
| Sil.Sizeof (typ, Some len, st) -> | Sil.Sizeof (typ, Some len, st) ->
Sil.Sizeof (typ, Some (exp_construct_fresh side len), st) Sil.Sizeof (typ, Some (exp_construct_fresh side len), st)
| Sil.Attribute _ ->
e
let strexp_construct_fresh side = let strexp_construct_fresh side =
let f (e, inst_opt) = (exp_construct_fresh side e, inst_opt) in let f (e, inst_opt) = (exp_construct_fresh side e, inst_opt) in
@ -1667,7 +1669,9 @@ let pi_partial_join mode
when (exp_is_const e') -> when (exp_is_const e') ->
true true
| Sil.Aneq _ -> false | Sil.Aneq _ -> false
| e -> Prop.atom_is_inequality e in | Sil.Aeq _ as e -> Prop.atom_is_inequality e
| Sil.Apred (_, _, e) ->
exp_is_const e in
begin begin
if Config.trace_join then begin if Config.trace_join then begin
L.d_str "pi1: "; Prop.d_pi pi1; L.d_ln (); L.d_str "pi1: "; Prop.d_pi pi1; L.d_ln ();

@ -1307,7 +1307,9 @@ let atom_to_xml_light (a: Sil.atom) : Io_infer.Xml.node =
| Sil.Aeq _ -> | Sil.Aeq _ ->
"equality" "equality"
| Sil.Aneq _ -> | Sil.Aneq _ ->
"disequality" in "disequality"
| Sil.Apred _ ->
"pred" in
Io_infer.Xml.create_tree "stack-variable" [("type", kind_info); ("instance", atom_to_xml_string a)] [] Io_infer.Xml.create_tree "stack-variable" [("type", kind_info); ("instance", atom_to_xml_string a)] []
let xml_pure_info prop = let xml_pure_info prop =

@ -17,6 +17,7 @@ module F = Format
(** type of printable elements *) (** type of printable elements *)
type print_type = type print_type =
| PTatom | PTatom
| PTattribute
| PTdecrease_indent | PTdecrease_indent
| PTexp | PTexp
| PTexp_list | PTexp_list

@ -15,6 +15,7 @@ open! Utils
(** type of printable elements *) (** type of printable elements *)
type print_type = type print_type =
| PTatom | PTatom
| PTattribute
| PTdecrease_indent | PTdecrease_indent
| PTexp | PTexp
| PTexp_list | PTexp_list

@ -82,8 +82,6 @@ let rec exp_match e1 sub vars e2 : (Sil.subst * Ident.t list) option =
(match exp_match base1 sub vars base2 with (match exp_match base1 sub vars base2 with
| None -> None | None -> None
| Some (sub', vars') -> exp_match idx1 sub' vars' idx2) | Some (sub', vars') -> exp_match idx1 sub' vars' idx2)
| Sil.Attribute _, _ | _, Sil.Attribute _ ->
check_equal sub vars e1 e2
let exp_list_match es1 sub vars es2 = let exp_list_match es1 sub vars es2 =
let f res_acc (e1, e2) = match res_acc with let f res_acc (e1, e2) = match res_acc with

@ -763,8 +763,7 @@ let execute_alloc mk can_return_null
evaluate_char_sizeof len evaluate_char_sizeof len
| Sil.Sizeof (Typ.Tarray (Typ.Tint ik, Some len), None, _) when Typ.ikind_is_char ik -> | Sil.Sizeof (Typ.Tarray (Typ.Tint ik, Some len), None, _) when Typ.ikind_is_char ik ->
evaluate_char_sizeof (Sil.Const (Const.Cint len)) evaluate_char_sizeof (Sil.Const (Const.Cint len))
| Sil.Sizeof _ -> e | Sil.Sizeof _ -> e in
| Sil.Attribute _ -> e in
let size_exp, procname = match args with let size_exp, procname = match args with
| [(Sil.Sizeof | [(Sil.Sizeof
(Typ.Tstruct (Typ.Tstruct

@ -172,6 +172,9 @@ let force_delayed_print fmt =
| (L.PTatom, a) -> | (L.PTatom, a) ->
let (a: Sil.atom) = Obj.obj a in let (a: Sil.atom) = Obj.obj a in
Sil.pp_atom pe_default fmt a Sil.pp_atom pe_default fmt a
| (L.PTattribute, a) ->
let (a: Sil.attribute) = Obj.obj a in
F.pp_print_string fmt (Sil.attribute_to_string pe_default a)
| (L.PTdecrease_indent, n) -> | (L.PTdecrease_indent, n) ->
let (n: int) = Obj.obj n in let (n: int) = Obj.obj n in
for _ = 1 to n do F.fprintf fmt "@]" done for _ = 1 to n do F.fprintf fmt "@]" done

@ -830,9 +830,7 @@ let sym_eval abs e =
| Sil.Lindex (e1, e2) -> | Sil.Lindex (e1, e2) ->
let e1' = eval e1 in let e1' = eval e1 in
let e2' = eval e2 in let e2' = eval e2 in
Sil.Lindex(e1', e2') Sil.Lindex(e1', e2') in
| Sil.Attribute _ ->
e in
let e' = eval e in let e' = eval e in
(* L.d_str "sym_eval "; Sil.d_exp e; L.d_str" --> "; Sil.d_exp e'; L.d_ln (); *) (* L.d_str "sym_eval "; Sil.d_exp e; L.d_str" --> "; Sil.d_exp e'; L.d_ln (); *)
e' e'
@ -1035,7 +1033,9 @@ let atom_normalize sub a0 =
| Sil.Aeq (e1, e2) -> | Sil.Aeq (e1, e2) ->
handle_boolean_operation true e1 e2 handle_boolean_operation true e1 e2
| Sil.Aneq (e1, e2) -> | Sil.Aneq (e1, e2) ->
handle_boolean_operation false e1 e2 in handle_boolean_operation false e1 e2
| Sil.Apred (b, a, e) ->
Sil.Apred (b, a, exp_normalize sub e) in
if atom_is_inequality a' then inequality_normalize a' else a' if atom_is_inequality a' then inequality_normalize a' else a'
(** Negate an atom *) (** Negate an atom *)
@ -1046,6 +1046,7 @@ let atom_negate = function
mk_inequality (Sil.exp_le e2 e1) mk_inequality (Sil.exp_le e2 e1)
| Sil.Aeq (e1, e2) -> Sil.Aneq (e1, e2) | Sil.Aeq (e1, e2) -> Sil.Aneq (e1, e2)
| Sil.Aneq (e1, e2) -> Sil.Aeq (e1, e2) | Sil.Aneq (e1, e2) -> Sil.Aeq (e1, e2)
| Sil.Apred (b, a, e) -> Sil.Apred (not b, a, e)
let rec strexp_normalize sub se = let rec strexp_normalize sub se =
match se with match se with
@ -1476,6 +1477,13 @@ let mk_eq e1 e2 =
let ne2 = exp_normalize Sil.sub_empty e2 in let ne2 = exp_normalize Sil.sub_empty e2 in
atom_normalize Sil.sub_empty (Sil.Aeq (ne1, ne2))) () atom_normalize Sil.sub_empty (Sil.Aeq (ne1, ne2))) ()
(** Construct a pred. *)
let mk_pred b a e =
Config.run_with_abs_val_equal_zero
(fun () ->
let ne = exp_normalize Sil.sub_empty e in
atom_normalize Sil.sub_empty (Apred (b, a, ne))) ()
(** Construct a points-to predicate for a single program variable. (** Construct a points-to predicate for a single program variable.
If [expand_structs] is true, initialize the fields of structs with fresh variables. *) If [expand_structs] is true, initialize the fields of structs with fresh variables. *)
let mk_ptsto_lvar tenv expand_structs inst ((pvar: Pvar.t), texp, expo) : Sil.hpred = let mk_ptsto_lvar tenv expand_structs inst ((pvar: Pvar.t), texp, expo) : Sil.hpred =
@ -1608,7 +1616,8 @@ let compute_reachable_atoms pi exps =
| _ -> false in | _ -> false in
IList.filter IList.filter
(function (function
| Sil.Aeq (lhs, rhs) | Sil.Aneq (lhs, rhs) -> exp_contains lhs || exp_contains rhs) | Sil.Aeq (lhs, rhs) | Sil.Aneq (lhs, rhs) -> exp_contains lhs || exp_contains rhs
| Sil.Apred (_, _, e) -> exp_contains e)
pi pi
(** Eliminates all empty lsegs from sigma, and collect equalities (** Eliminates all empty lsegs from sigma, and collect equalities
@ -1772,8 +1781,7 @@ let prop_reset_inst inst_map prop =
(** Return the exp and attribute marked in the atom if any, and return None otherwise *) (** Return the exp and attribute marked in the atom if any, and return None otherwise *)
let atom_get_exp_attribute = function let atom_get_exp_attribute = function
| Sil.Aneq (Sil.Attribute att, e) | Sil.Apred (true, att, e) -> Some (e, att)
| Sil.Aneq (e, Sil.Attribute att) -> Some (e, att)
| _ -> None | _ -> None
(** Check whether an atom is used to mark an attribute *) (** Check whether an atom is used to mark an attribute *)
@ -1785,8 +1793,7 @@ let get_exp_attributes prop exp =
let nexp = exp_normalize_prop prop exp in let nexp = exp_normalize_prop prop exp in
let atom_get_attr attributes atom = let atom_get_attr attributes atom =
match atom with match atom with
| Sil.Aneq (e, Sil.Attribute att) | Sil.Apred (true, att, e) when Sil.exp_equal e nexp -> att :: attributes
| Sil.Aneq (Sil.Attribute att, e) when Sil.exp_equal e nexp -> att:: attributes
| _ -> attributes in | _ -> attributes in
IList.fold_left atom_get_attr [] prop.pi IList.fold_left atom_get_attr [] prop.pi
@ -1842,29 +1849,26 @@ let get_all_attributes prop =
IList.rev !res IList.rev !res
(** Set an attribute associated to the expression *) (** Set an attribute associated to the expression *)
let set_exp_attribute prop exp att = let set_exp_attribute ?(footprint = false) ?(polarity = true) prop attr exp =
let exp_att = Sil.Attribute att in prop_atom_and ~footprint prop (Sil.Apred (polarity, attr, exp))
conjoin_neq exp exp_att prop
(** Replace an attribute associated to the expression *) (** Replace an attribute associated to the expression *)
let add_or_replace_exp_attribute_check_changed check_attribute_change prop exp att = let add_or_replace_exp_attribute_check_changed check_attribute_change prop exp att =
let nexp = exp_normalize_prop prop exp in let nexp = exp_normalize_prop prop exp in
let found = ref false in let found = ref false in
let atom_map a = match a with let atom_map a = match a with
| Sil.Aneq (e, Sil.Attribute att_old) | Sil.Apred (true, att_old, e) ->
| Sil.Aneq (Sil.Attribute att_old, e) ->
if Sil.exp_equal nexp e && (attributes_in_same_category att_old att) then if Sil.exp_equal nexp e && (attributes_in_same_category att_old att) then
begin begin
found := true; found := true;
check_attribute_change att_old att; check_attribute_change att_old att;
let e1, e2 = exp_reorder e (Sil.Attribute att) in Sil.Apred (true, att, e)
Sil.Aneq (e1, e2)
end end
else a else a
| _ -> a in | _ -> a in
let pi' = IList.map atom_map (get_pi prop) in let pi' = IList.map atom_map (get_pi prop) in
if !found then replace_pi pi' prop if !found then replace_pi pi' prop
else set_exp_attribute prop nexp att else set_exp_attribute prop att nexp
let add_or_replace_exp_attribute prop exp att = let add_or_replace_exp_attribute prop exp att =
(* wrapper for the most common case: do nothing *) (* wrapper for the most common case: do nothing *)
@ -1882,9 +1886,8 @@ let mark_vars_as_undefined prop vars_to_mark callee_pname ret_annots loc path_po
let remove_attribute_by_filter ~f prop = let remove_attribute_by_filter ~f prop =
let atom_remove atom pi = match atom with let atom_remove atom pi = match atom with
| Sil.Aneq (e, Sil.Attribute att_old) | Sil.Apred (true, att_old, exp) ->
| Sil.Aneq (Sil.Attribute att_old, e) -> if f att_old exp then
if f att_old e then
pi pi
else atom:: pi else atom:: pi
| _ -> atom:: pi in | _ -> atom:: pi in
@ -1936,8 +1939,7 @@ let rec nullify_exp_with_objc_null prop exp =
(** Get all the attributes of the prop *) (** Get all the attributes of the prop *)
let get_atoms_with_attribute att prop = let get_atoms_with_attribute att prop =
let atom_remove atom autoreleased_atoms = match atom with let atom_remove atom autoreleased_atoms = match atom with
| Sil.Aneq (e, Sil.Attribute att_old) | Sil.Apred (true, att_old, e) ->
| Sil.Aneq (Sil.Attribute att_old, e) ->
if Sil.attribute_equal att_old att then if Sil.attribute_equal att_old att then
e:: autoreleased_atoms e:: autoreleased_atoms
else autoreleased_atoms else autoreleased_atoms
@ -1948,16 +1950,11 @@ let get_atoms_with_attribute att prop =
let attribute_map_resource prop f = let attribute_map_resource prop f =
let pi = get_pi prop in let pi = get_pi prop in
let attribute_map e = function let attribute_map e = function
| Sil.Aresource ra -> | Sil.Aresource ra -> Sil.Aresource (f e ra)
Sil.Aresource (f e ra)
| att -> att in | att -> att in
let atom_map a = match a with let atom_map = function
| Sil.Aneq (e, Sil.Attribute att) | Sil.Apred (b, att, e) -> Sil.Apred (b, attribute_map e att, e)
| Sil.Aneq (Sil.Attribute att, e) -> | atom -> atom in
let att' = attribute_map e att in
let e1, e2 = exp_reorder e (Sil.Attribute att') in
Sil.Aneq (e1, e2)
| _ -> a in
let pi' = IList.map atom_map pi in let pi' = IList.map atom_map pi in
replace_pi pi' prop replace_pi pi' prop
@ -1998,8 +1995,7 @@ let find_arithmetic_problem proc_node_session prop exp =
| Sil.Lfield (e, _, _) -> walk e | Sil.Lfield (e, _, _) -> walk e
| Sil.Lindex (e1, e2) -> walk e1; walk e2 | Sil.Lindex (e1, e2) -> walk e1; walk e2
| Sil.Sizeof (_, None, _) -> () | Sil.Sizeof (_, None, _) -> ()
| Sil.Sizeof (_, Some len, _) -> walk len | Sil.Sizeof (_, Some len, _) -> walk len in
| Sil.Attribute _ -> () in
walk exp; walk exp;
try Some (Div0 (IList.find check_zero !exps_divided)), !res try Some (Div0 (IList.find check_zero !exps_divided)), !res
with Not_found -> with Not_found ->
@ -2294,13 +2290,14 @@ let rec exp_captured_ren ren = function
let e1' = exp_captured_ren ren e1 in let e1' = exp_captured_ren ren e1 in
let e2' = exp_captured_ren ren e2 in let e2' = exp_captured_ren ren e2 in
Sil.Lindex(e1', e2') Sil.Lindex(e1', e2')
| Sil.Attribute _ as e -> e
let atom_captured_ren ren = function let atom_captured_ren ren = function
| Sil.Aeq (e1, e2) -> | Sil.Aeq (e1, e2) ->
Sil.Aeq (exp_captured_ren ren e1, exp_captured_ren ren e2) Sil.Aeq (exp_captured_ren ren e1, exp_captured_ren ren e2)
| Sil.Aneq (e1, e2) -> | Sil.Aneq (e1, e2) ->
Sil.Aneq (exp_captured_ren ren e1, exp_captured_ren ren e2) Sil.Aneq (exp_captured_ren ren e1, exp_captured_ren ren e2)
| Sil.Apred (b, a, e) ->
Sil.Apred (b, a, exp_captured_ren ren e)
let rec strexp_captured_ren ren = function let rec strexp_captured_ren ren = function
| Sil.Eexp (e, inst) -> | Sil.Eexp (e, inst) ->

@ -222,6 +222,9 @@ val mk_neq : exp -> exp -> atom
(** Construct an equality. *) (** Construct an equality. *)
val mk_eq : exp -> exp -> atom val mk_eq : exp -> exp -> atom
(** Construct a pred. *)
val mk_pred : bool -> attribute -> exp -> atom
(** create a strexp of the given type, populating the structures if [expand_structs] is true *) (** create a strexp of the given type, populating the structures if [expand_structs] is true *)
val create_strexp_of_type : val create_strexp_of_type :
Tenv.t option -> struct_init_mode -> Typ.t -> Sil.exp option -> Sil.inst -> Sil.strexp Tenv.t option -> struct_init_mode -> Typ.t -> Sil.exp option -> Sil.inst -> Sil.strexp
@ -313,7 +316,9 @@ val get_all_attributes : 'a t -> (exp * attribute) list
val has_dangling_uninit_attribute : 'a t -> exp -> bool val has_dangling_uninit_attribute : 'a t -> exp -> bool
val set_exp_attribute : normal t -> exp -> attribute -> normal t (** Set an attribute associated to the expression *)
val set_exp_attribute : ?footprint: bool -> ?polarity: bool ->
normal t -> attribute -> exp -> normal t
val add_or_replace_exp_attribute_check_changed : (Sil.attribute -> Sil.attribute -> unit) -> val add_or_replace_exp_attribute_check_changed : (Sil.attribute -> Sil.attribute -> unit) ->
normal t -> exp -> attribute -> normal t normal t -> exp -> attribute -> normal t

@ -28,7 +28,7 @@ let from_prop p = p
(** Return [true] if root node *) (** Return [true] if root node *)
let rec is_root = function let rec is_root = function
| Sil.Var id -> Ident.is_normal id | Sil.Var id -> Ident.is_normal id
| Sil.Exn _ | Sil.Closure _ | Sil.Const _ | Sil.Lvar _ | Sil.Attribute _ -> true | Sil.Exn _ | Sil.Closure _ | Sil.Const _ | Sil.Lvar _ -> true
| Sil.Cast (_, e) -> is_root e | Sil.Cast (_, e) -> is_root e
| Sil.UnOp _ | Sil.BinOp _ | Sil.Lfield _ | Sil.Lindex _ | Sil.Sizeof _ -> false | Sil.UnOp _ | Sil.BinOp _ | Sil.Lfield _ | Sil.Lindex _ | Sil.Sizeof _ -> false
@ -49,6 +49,7 @@ let edge_get_source = function
| Ehpred (Sil.Hdllseg(_, _, e1, _, _, _, _)) -> e1 (* only one direction supported for now *) | Ehpred (Sil.Hdllseg(_, _, e1, _, _, _, _)) -> e1 (* only one direction supported for now *)
| Eatom (Sil.Aeq (e1, _)) -> e1 | Eatom (Sil.Aeq (e1, _)) -> e1
| Eatom (Sil.Aneq (e1, _)) -> e1 | Eatom (Sil.Aneq (e1, _)) -> e1
| Eatom (Sil.Apred (_, _, e)) -> e
| Esub_entry (x, _) -> Sil.Var x | Esub_entry (x, _) -> Sil.Var x
(** Return the successor nodes of the edge *) (** Return the successor nodes of the edge *)
@ -56,6 +57,7 @@ let edge_get_succs = function
| Ehpred hpred -> Sil.ExpSet.elements (Prop.hpred_get_targets hpred) | Ehpred hpred -> Sil.ExpSet.elements (Prop.hpred_get_targets hpred)
| Eatom (Sil.Aeq (_, e2)) -> [e2] | Eatom (Sil.Aeq (_, e2)) -> [e2]
| Eatom (Sil.Aneq (_, e2)) -> [e2] | Eatom (Sil.Aneq (_, e2)) -> [e2]
| Eatom (Sil.Apred _) -> []
| Esub_entry (_, e) -> [e] | Esub_entry (_, e) -> [e]
let get_sigma footprint_part g = let get_sigma footprint_part g =
@ -157,6 +159,8 @@ let compute_edge_diff (oldedge: edge) (newedge: edge) : Obj.t list = match olded
compute_exp_diff e1 e2 compute_exp_diff e1 e2
| Eatom (Sil.Aneq (_, e1)), Eatom (Sil.Aneq (_, e2)) -> | Eatom (Sil.Aneq (_, e1)), Eatom (Sil.Aneq (_, e2)) ->
compute_exp_diff e1 e2 compute_exp_diff e1 e2
| Eatom (Sil.Apred (_, _, e1)), Eatom (Sil.Apred (_, _, e2)) ->
compute_exp_diff e1 e2
| Esub_entry (_, e1), Esub_entry (_, e2) -> | Esub_entry (_, e1), Esub_entry (_, e2) ->
compute_exp_diff e1 e2 compute_exp_diff e1 e2
| _ -> [Obj.repr newedge] | _ -> [Obj.repr newedge]

@ -363,7 +363,8 @@ end = struct
leqs := (e1, e2) :: !leqs (* <= *) leqs := (e1, e2) :: !leqs (* <= *)
| Sil.Aeq (Sil.BinOp (Binop.Lt, e1, e2), Sil.Const (Const.Cint i)) when IntLit.isone i -> | Sil.Aeq (Sil.BinOp (Binop.Lt, e1, e2), Sil.Const (Const.Cint i)) when IntLit.isone i ->
lts := (e1, e2) :: !lts (* < *) lts := (e1, e2) :: !lts (* < *)
| Sil.Aeq _ -> () in | Sil.Aeq _
| Sil.Apred _ -> () in
IList.iter process_atom pi; IList.iter process_atom pi;
saturate { leqs = !leqs; lts = !lts; neqs = !neqs } saturate { leqs = !leqs; lts = !lts; neqs = !neqs }
@ -554,7 +555,7 @@ let check_zero e =
let is_root prop base_exp exp = let is_root prop base_exp exp =
let rec f offlist_past e = match e with let rec f offlist_past e = match e with
| Sil.Var _ | Sil.Const _ | Sil.UnOp _ | Sil.BinOp _ | Sil.Exn _ | Sil.Closure _ | Sil.Lvar _ | Sil.Var _ | Sil.Const _ | Sil.UnOp _ | Sil.BinOp _ | Sil.Exn _ | Sil.Closure _ | Sil.Lvar _
| Sil.Sizeof _ | Sil.Attribute _ -> | Sil.Sizeof _ ->
if check_equal prop base_exp e if check_equal prop base_exp e
then Some offlist_past then Some offlist_past
else None else None
@ -740,6 +741,7 @@ let check_atom prop a0 =
when IntLit.isone i -> check_lt_normalized prop e1 e2 when IntLit.isone i -> check_lt_normalized prop e1 e2
| Sil.Aeq (e1, e2) -> check_equal prop e1 e2 | Sil.Aeq (e1, e2) -> check_equal prop e1 e2
| Sil.Aneq (e1, e2) -> check_disequal prop e1 e2 | Sil.Aneq (e1, e2) -> check_disequal prop e1 e2
| Sil.Apred _ -> IList.exists (Sil.atom_equal a) (Prop.get_pi prop)
(** Check [prop |- e1<=e2]. Result [false] means "don't know". *) (** Check [prop |- e1<=e2]. Result [false] means "don't know". *)
let check_le prop e1 e2 = let check_le prop e1 e2 =
@ -856,7 +858,8 @@ let check_inconsistency_base prop =
| Sil.Aneq (e1, e2) -> | Sil.Aneq (e1, e2) ->
(match e1, e2 with (match e1, e2 with
| Sil.Const c1, Sil.Const c2 -> Const.equal c1 c2 | Sil.Const c1, Sil.Const c2 -> Const.equal c1 c2
| _ -> (Sil.exp_compare e1 e2 = 0)) in | _ -> (Sil.exp_compare e1 e2 = 0))
| Sil.Apred _ -> false in
let inconsistent_inequalities () = let inconsistent_inequalities () =
let ineq = Inequalities.from_prop prop in let ineq = Inequalities.from_prop prop in
(* (*
@ -2108,13 +2111,12 @@ let rec pre_check_pure_implication calc_missing subs pi1 pi2 =
) )
| Sil.Aeq _ :: pi2' -> (* must be an inequality *) | Sil.Aeq _ :: pi2' -> (* must be an inequality *)
pre_check_pure_implication calc_missing subs pi1 pi2' pre_check_pure_implication calc_missing subs pi1 pi2'
| Sil.Aneq (Sil.Var v, _):: pi2' -> | (Sil.Aneq (e, _) | Apred (_, _, e)) :: pi2' ->
if not (Ident.is_primed v || calc_missing) if calc_missing || (match e with Var v -> Ident.is_primed v | _ -> false) then
then raise (IMPL_EXC("ineq e2=f2 in rhs with e2 not primed var", (Sil.sub_empty, Sil.sub_empty), EXC_FALSE)) pre_check_pure_implication calc_missing subs pi1 pi2'
else pre_check_pure_implication calc_missing subs pi1 pi2' else
| Sil.Aneq _ :: pi2' -> raise (IMPL_EXC ("ineq e2=f2 in rhs with e2 not primed var",
if calc_missing then pre_check_pure_implication calc_missing subs pi1 pi2' (Sil.sub_empty, Sil.sub_empty), EXC_FALSE))
else raise (IMPL_EXC ("ineq e2=f2 in rhs with e2 not primed var", (Sil.sub_empty, Sil.sub_empty), EXC_FALSE))
(** Perform the array bound checks delayed (to instantiate variables) by the prover. (** Perform the array bound checks delayed (to instantiate variables) by the prover.
If there is a provable violation of the array bounds, set the prover status to Bounds_check If there is a provable violation of the array bounds, set the prover status to Bounds_check

@ -793,8 +793,7 @@ let add_guarded_by_constraints prop lexp pdesc =
end end
else else
(* private method. add locked proof obligation to [pdesc] *) (* private method. add locked proof obligation to [pdesc] *)
let locked_attr = Sil.Attribute Alocked in Prop.set_exp_attribute ~footprint:true prop Alocked guarded_by_exp
Prop.conjoin_neq ~footprint:true guarded_by_exp locked_attr prop
| _ -> | _ ->
if not (proc_has_matching_annot pdesc guarded_by_str if not (proc_has_matching_annot pdesc guarded_by_str
|| is_synchronized_on_class guarded_by_str) && should_warn pdesc || is_synchronized_on_class guarded_by_str) && should_warn pdesc

@ -356,8 +356,6 @@ let rec prune ~positive condition prop =
assert false assert false
| Sil.Closure _ -> | Sil.Closure _ ->
assert false assert false
| Sil.Attribute _ ->
assert false
and prune_inter ~positive condition1 condition2 prop = and prune_inter ~positive condition1 condition2 prop =
let res = ref Propset.empty in let res = ref Propset.empty in
@ -1380,9 +1378,8 @@ and check_untainted exp taint_kind caller_pname callee_pname prop =
| _ -> | _ ->
if !Config.footprint then if !Config.footprint then
let taint_info = { Sil.taint_source = callee_pname; taint_kind; } in let taint_info = { Sil.taint_source = callee_pname; taint_kind; } in
let untaint_attr = Sil.Attribute (Sil.Auntaint taint_info) in
(* add untained(n_lexp) to the footprint *) (* add untained(n_lexp) to the footprint *)
Prop.conjoin_neq ~footprint:true exp untaint_attr prop Prop.set_exp_attribute ~footprint:true prop (Auntaint taint_info) exp
else prop else prop
(** execute a call for an unknown or scan function *) (** execute a call for an unknown or scan function *)

@ -385,14 +385,12 @@ let post_process_post
| Some (Sil.Aresource ({ Sil.ra_kind = Sil.Rrelease })) -> true | Some (Sil.Aresource ({ Sil.ra_kind = Sil.Rrelease })) -> true
| _ -> false in | _ -> false in
let atom_update_alloc_attribute = function let atom_update_alloc_attribute = function
| Sil.Aneq (e , Sil.Attribute (Sil.Aresource ra)) | Sil.Apred (true, Aresource ra, e)
| Sil.Aneq (Sil.Attribute (Sil.Aresource ra), e)
when not (ra.Sil.ra_kind = Sil.Rrelease && actual_pre_has_freed_attribute e) -> when not (ra.Sil.ra_kind = Sil.Rrelease && actual_pre_has_freed_attribute e) ->
(* unless it was already freed before the call *) (* unless it was already freed before the call *)
let vpath, _ = Errdesc.vpath_find post e in let vpath, _ = Errdesc.vpath_find post e in
let ra' = { ra with Sil.ra_pname = callee_pname; Sil.ra_loc = loc; Sil.ra_vpath = vpath } in let ra' = { ra with Sil.ra_pname = callee_pname; Sil.ra_loc = loc; Sil.ra_vpath = vpath } in
let c = Sil.Attribute (Sil.Aresource ra') in Sil.Apred (true, Aresource ra', e)
Sil.Aneq (e, c)
| a -> a in | a -> a in
let prop' = Prop.replace_sigma (post_process_sigma (Prop.get_sigma post) loc) post in let prop' = Prop.replace_sigma (post_process_sigma (Prop.get_sigma post) loc) post in
let pi' = IList.map atom_update_alloc_attribute (Prop.get_pi prop') in let pi' = IList.map atom_update_alloc_attribute (Prop.get_pi prop') in
@ -1263,7 +1261,7 @@ let exe_call_postprocess ret_ids trace_call callee_pname callee_attrs loc result
let ret_var = Sil.Var ret_id in let ret_var = Sil.Var ret_id in
let mark_id_as_retval (p, path) = let mark_id_as_retval (p, path) =
let att_retval = Sil.Aretval (callee_pname, ret_annot) in let att_retval = Sil.Aretval (callee_pname, ret_annot) in
Prop.set_exp_attribute p ret_var att_retval, path in Prop.set_exp_attribute p att_retval ret_var, path in
IList.map mark_id_as_retval res IList.map mark_id_as_retval res
| _ -> res | _ -> res

@ -33,7 +33,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Sil.Exn _ | Sil.Exn _
| Sil.Closure _ | Sil.Closure _
| Sil.Const (Cint _ | Cfun _ | Cstr _ | Cfloat _ | Cclass _ | Cptr_to_fld _) | Sil.Const (Cint _ | Cfun _ | Cstr _ | Cfloat _ | Cclass _ | Cptr_to_fld _)
| Sil.Var _ | Sil.Sizeof _ | Sil.Attribute _ -> | Sil.Var _ | Sil.Sizeof _ ->
astate astate
let exec_instr astate _ _ = function let exec_instr astate _ _ = function

@ -519,8 +519,7 @@ let callback_check_field_access { Callbacks.proc_desc } =
| Sil.Lindex (e1, e2) -> | Sil.Lindex (e1, e2) ->
do_exp is_read e1; do_exp is_read e1;
do_exp is_read e2 do_exp is_read e2
| Sil.Sizeof _ -> () | Sil.Sizeof _ -> () in
| Sil.Attribute _ -> () in
let do_read_exp = do_exp true in let do_read_exp = do_exp true in
let do_write_exp = do_exp false in let do_write_exp = do_exp false in
let do_instr _ = function let do_instr _ = function

Loading…
Cancel
Save