diff --git a/src/kernel_services/abstract_interp/abstract_memory.ml b/src/kernel_services/abstract_interp/abstract_memory.ml index 687d64d5f8fdce1870017ab5e3e0bd03e8fccc3a..3e2538f1a5972be3fca6a4f9dcb8ea5f4fc46864 100644 --- a/src/kernel_services/abstract_interp/abstract_memory.ml +++ b/src/kernel_services/abstract_interp/abstract_memory.ml @@ -41,7 +41,7 @@ let pp_iter ?(pre=format_of_string "{@;<1 2>") ?(sep=format_of_string ",@;<1 2>") ?(suf=format_of_string "@ }") - ?(format=format_of_string"@[<hv>%a@]") + ?(format=format_of_string "@[<hv>%a@]") iter pp fmt v = let need_sep = ref false in Format.fprintf fmt pre; @@ -49,10 +49,9 @@ let pp_iter if !need_sep then Format.fprintf fmt sep else need_sep := true; Format.fprintf fmt format pp v; ) v; - Format.fprintf fmt suf; -;; + Format.fprintf fmt suf -let pp_iter2 ?pre ?sep ?suf ?(format=format_of_string "%a%a") +let pp_iter2 ?pre ?sep ?suf ?(format=format_of_string "@[<hv>%a%a@]") iter2 pp_key pp_val fmt v = let iter f = iter2 (fun k v -> f (k,v)) in let pp fmt (k,v) = Format.fprintf fmt format pp_key k pp_val v in @@ -247,7 +246,7 @@ struct type submemory = M.t let pretty fmt m = - pp_iter2 ~format:".%a%a" FieldMap.iter Field.pretty M.pretty fmt m.fields + pp_iter2 ~format:"@[<hv>.%a%a@]" FieldMap.iter Field.pretty M.pretty fmt m.fields let hash m = Hashtbl.hash (m.padding, FieldMap.hash m.fields) @@ -440,10 +439,14 @@ struct | Const _ -> Some b | Exp (e, j) -> let l = linearity vi e in - Some (Exp (e, Integer.(sub j (mul l i)))) - | Ptroffset (e, b, j) -> + if Integer.is_zero l + then Some b + else Option.map (fun i -> Exp (e, Integer.(sub j (mul l i)))) i + | Ptroffset (e, base, j) -> let l = linearity vi e in - Some (Ptroffset (e, b, Integer.(sub j (mul l i)))) + if Integer.is_zero l + then Some b + else Option.map (fun i -> Ptroffset (e, base, Integer.(sub j (mul l i)))) i with NonLinear -> None (* Stupid oracle built from an Ival oracle *) @@ -506,7 +509,7 @@ sig val is_included : t -> t -> bool val unify : oracle:bioracle -> (submemory -> submemory -> submemory) -> t -> t -> t - val singleton : bit -> bound -> bound -> submemory -> t + val single : bit -> bound -> bound -> submemory -> t val read : oracle:(Cil_types.exp -> Ival.t) -> (submemory -> 'a) -> ('a -> 'a -> 'a) -> t -> bound -> 'a @@ -722,7 +725,7 @@ struct padding = Bit.join p1 p2 ; } - let singleton padding lindex uindex value = + let single padding lindex uindex value = { padding ; start = lindex ; @@ -757,7 +760,7 @@ struct 1. reinforcement without loss 2. weak update without singularization 3. update reduces the number of segments to 3 *) - let write ~oracle f m lindex uindex = + let write ~oracle f m lindex uindex = (* lindex < uindex *) let (<=) b1 b2 = match Bound.cmp ~oracle b1 b2 with | Lower | Equal -> true | Greater | Uncomparable -> false @@ -765,26 +768,39 @@ struct | Greater | Equal -> true | Lower | Uncomparable -> false in + (* (start,head) : segmentation kept identical below the write indexes, + head is a list in reverse order + (l,v,u) : the segment (l,u) beeing overwriten with previous value v + + head = (_,l) :: _ + *) let rec aux_before l s = + (* Format.printf "aux before: %a@." pretty_segments (l,s); *) if lindex >= l then aux_below l [] l s else aux_over lindex [] lindex (M.of_raw m.padding) l s - and aux_below start head l = function (* l < index *) + and aux_below start head l = fun t -> + (* Format.printf "aux_below: %a [%a] %a@." pretty_segments (start,head) Bound.pretty l pretty_segments (l,t); *) + match t with (* l <= lindex *) | [] -> aux_end start head l (M.of_raw m.padding) uindex [] | (v,u) :: t -> if lindex >= u then aux_below start ((v,u) :: head) u t else aux_over start head l v u t - and aux_over start head l v u = function (* l >= index *) - | [] -> - aux_end start head l (M.smash ~oracle v (M.of_raw m.padding)) uindex [] - | ((v',u') :: t) as s -> - if uindex <= u' - then aux_end start head l v u s - (* TODO: do not smash if the slices are covered by the write *) - else aux_over start head l (M.smash ~oracle v v') u' t - and aux_end start head l v u tail = + and aux_over start head l v u s = (* l <= lindex *) + (* Format.printf "aux_over: %a [%a,%a,%a] %a@." pretty_segments (start,head) Bound.pretty l M.pretty v Bound.pretty u pretty_segments (u,s); *) + if uindex <= u then + aux_end start head l v u s + else + match s with + | [] -> + aux_end start head l (M.smash ~oracle v (M.of_raw m.padding)) uindex [] + | (v',u') :: t -> + (* TODO: do not smash if the slices are covered by the write *) + aux_over start head l (M.smash ~oracle v v') u' t + and aux_end start head l v u tail = (* l <= lindex < uindex <= u*) + (* Format.printf "aux_end: %a [%a,%a,%a] %a@." pretty_segments (start,head) Bound.pretty l M.pretty v Bound.pretty u pretty_segments (u,tail); *) let tail' = (if is_empty_segment ~oracle l lindex then [] else [(v,lindex)]) @ [(f v,uindex)] @ @@ -803,7 +819,7 @@ struct let rec aux acc = function | [] -> acc | (v,u) :: t -> - match Option.bind x (fun x -> Bound.incr vi x u) with + match Bound.incr vi x u with | Some u -> aux ((v,u) :: acc) t | None -> match t with @@ -814,7 +830,7 @@ struct | (v',u') :: t -> aux ((M.smash ~oracle v v',u') :: acc) t in let start, segments = - match Option.bind x (fun x -> Bound.incr vi x m.start) with + match Bound.incr vi x m.start with | Some start -> start, m.segments | None -> match m.segments with @@ -905,7 +921,8 @@ struct Format.fprintf fmt "%a" A.pretty a.array_value let pretty fmt m = pp ~root:false fmt m - let pretty_root fmt m = pp ~root:true fmt m + let pretty_root fmt m = + Format.fprintf fmt "@[<hv>%a@]" (pp ~root:true) m let rec hash m = match m with | Raw b -> Hashtbl.hash ( @@ -1114,21 +1131,20 @@ struct let l, u = Int_val.min_and_max index in let l = Option.get l and u = Option.get u in (* TODO: handle exceptions *) Bound.of_integer l, Bound.of_integer u, - weak || Integer.(equal (succ l) u) + weak || Integer.equal l u | Some e -> let b = Bound.of_exp e in - b, Bound.succ b, weak + b, b, weak in match m with | Array a when are_typ_compatible a.array_cell_type elem_type -> - let array_value = - A.write ~oracle (aux ~weak offset') a.array_value lindex uindex - in + let array_value = A.write ~oracle (aux ~weak offset') a.array_value + lindex (Bound.succ uindex) in Array { a with array_value } | _ -> let b = raw m in let new_value = aux ~weak offset' (Raw b) in - let array_value = A.singleton b lindex uindex new_value in + let array_value = A.single b lindex (Bound.succ uindex) new_value in Array { array_cell_type = elem_type ; array_value } in aux @@ -1169,19 +1185,30 @@ struct read ~oracle to_value V.join loc m let extract ~oracle (m : t) (loc : location) : t = - read ~oracle (fun _typ x -> x) (smash ~oracle) loc m + let r = read ~oracle (fun _typ x -> x) (smash ~oracle) loc m in + (* Format.printf "extract %a in %a : %a@." TypedOffset.pretty loc pretty m pretty r; *) + r let set ~oracle ~weak m offset new_v = let f ~weak typ m = of_value typ (if weak then V.join (to_value typ m) new_v else new_v) in - write ~oracle ~weak f offset m + let r = write ~oracle ~weak f offset m in + (* Format.printf "%a <- %a : %a@." TypedOffset.pretty offset V.pretty new_v pretty r; *) + r + + let join ~oracle m1 m2 = + let r = join ~oracle m1 m2 in + (* Format.printf "%a join %a : %a@." pretty m1 pretty m2 pretty r; *) + r let reinforce ~oracle f m offset = let f' ~weak typ m = if weak then m else of_value typ (f (to_value typ m)) in - write ~oracle ~weak:false f' offset m + let r = write ~oracle ~weak:false f' offset m in + (* Format.printf "reinforce at %a : %a@." TypedOffset.pretty offset pretty r; *) + r let erase ~oracle ~weak m offset b = let f ~weak _typ m = diff --git a/tests/value/multidim.c b/tests/value/multidim.c index c958cd19a1464b6a8d9cea7759a06fa802661df5..9d941f69452fa42871d135f382cf46cd4e51234d 100644 --- a/tests/value/multidim.c +++ b/tests/value/multidim.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-eva-msg-key d-multidim -eva-domains multidim -eva-plevel 0" + STDOPT: +"-eva-msg-key d-multidim -eva-domains multidim -eva-plevel 1" */ #include "__fc_builtin.h" #define N 4 @@ -42,14 +42,13 @@ void main(s x) { /* The multidim domain wont infer anything except the structure from the assign: it considers x can contain anything including pointers, and thus no reduction is done by are_finite */ - //@ assert \are_finite(x.t1[..].f) && \are_finite(x.t2[..].f); + //@ admit \are_finite(x.t1[..].f) && \are_finite(x.t2[..].f); Frama_C_domain_show_each(x); f(); - Frama_C_domain_show_each(z); - + Frama_C_domain_show_each(z); /* The multidim domain doesn't implement forward logic yet */ - //@ assert \are_finite(z[..].t1[..].f) && \are_finite(z[..].t2[..].f); + //@ check \are_finite(z[..].t1[..].f) && \are_finite(z[..].t2[..].f); for (int i = 0 ; i < M ; i ++) { for (int j = 0 ; j < N ; j ++) { @@ -64,3 +63,15 @@ void main(s x) { Frama_C_domain_show_each(t1); } + +void main2(void) { + int t[10] = {0}; + Frama_C_domain_show_each_begin(t); + for (int i = 0 ; i < 10 ; i++) { + Frama_C_domain_show_each_before(i, t); + t[i] = 1; + Frama_C_domain_show_each_after(i, t); + } + Frama_C_domain_show_each(t); + //@ check t[0..9] == 1; +} diff --git a/tests/value/oracle/multidim.res.oracle b/tests/value/oracle/multidim.res.oracle index fb1fde102da153e21bf7c4e8e714252e6f351a6c..9e283f9be301248921b7903f324c2d945be798bb 100644 --- a/tests/value/oracle/multidim.res.oracle +++ b/tests/value/oracle/multidim.res.oracle @@ -10,24 +10,36 @@ z[0..3] ∈ {0} w[0..3] ∈ {0} nondet ∈ [--..--] -[kernel] multidim.c:33: too many locations to update in array. Approximating. [eva] multidim.c:40: Frama_C_domain_show_each: x : # cvalue: .t1[0].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t1[0].i ∈ [--..--] .t1[1].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t1[1].i ∈ [--..--] - .t1[2..3]{.f#; .i#} ∈ [0..18446744073701163007] repeated %64 + .t1[2].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t1[2].i ∈ [--..--] + .t1[3].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t1[3].i ∈ [--..--] .t2[0].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t2[0].i ∈ [--..--] .t2[1].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t2[1].i ∈ [--..--] - .t2[2..3]{.f#; .i#} ∈ [0..18446744073701163007] repeated %64 + .t2[2].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t2[2].i ∈ [--..--] + .t2[3].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t2[3].i ∈ [--..--] # multidim: T y1 : # cvalue: .t1[0].f ∈ {3.} {.t1{[0].i; [1..3]}; .t2[0..3]} ∈ {0} - # multidim: { .t1[0] = { .f = [0. .. 3.], .i = {0} }, .t2[0..3] = { - .f = {0}, .i = {0} } } + # multidim: { + .t1[0] = { .f = {3.}, .i = {0} }, + .t2{ + [0] = { .f = {0}, .i = {0} }, + [1] = { .f = {0}, .i = {0} }, + [2] = { .f = {0}, .i = {0} }, + [3] = { .f = {0}, .i = {0} } + } + } y2 : # cvalue: .t1[0].f ∈ {4.} or UNINITIALIZED {.t1{[0].i; [1..3]}; .t2[0..3]} ∈ UNINITIALIZED # multidim: { .t1[0] = { .f = {4.} } } @@ -35,21 +47,28 @@ # multidim: 0 w : # cvalue: {0} # multidim: 0 -[eva:alarm] multidim.c:45: Warning: assertion got status unknown. [eva] multidim.c:46: Frama_C_domain_show_each: x : # cvalue: .t1[0].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t1[0].i ∈ [--..--] .t1[1].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t1[1].i ∈ [--..--] - .t1[2..3]{.f#; .i#} ∈ [0..18446744073701163007] repeated %64 + .t1[2].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t1[2].i ∈ [--..--] + .t1[3].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t1[3].i ∈ [--..--] .t2[0].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t2[0].i ∈ [--..--] .t2[1].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] .t2[1].i ∈ [--..--] - .t2[2..3]{.f#; .i#} ∈ [0..18446744073701163007] repeated %64 - # multidim: { .t1[0..2] = { .f = {{ ANYTHING }} }, .t2[0..2] = { - .f = {{ ANYTHING }} } } + .t2[2].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t2[2].i ∈ [--..--] + .t2[3].f ∈ [-3.40282346639e+38 .. 3.40282346639e+38] + .t2[3].i ∈ [--..--] + # multidim: { + .t1[0..3] = { .f = {{ ANYTHING }} }, + .t2[0..3] = { .f = {{ ANYTHING }} } + } [eva] computing for function f <- main. Called from multidim.c:48. [eva] using specification for function f @@ -57,47 +76,53 @@ [eva] multidim.c:49: Frama_C_domain_show_each: z : # cvalue: [--..--] - # multidim: [0..2] = { .t1[0..2] = { .f = T }, .t2[0..2] = { - .f = [-3.40282346639e+38 .. 3.40282346639e+38] } } -[eva:alarm] multidim.c:52: Warning: assertion got status unknown. -[eva] multidim.c:55: starting to merge loop iterations + # multidim: [0..3] = { + .t1[0..3] = { + .f = [-3.40282346639e+38 .. 3.40282346639e+38] + }, + .t2[0..3] = { + .f = [-3.40282346639e+38 .. 3.40282346639e+38] + } + } +[eva:alarm] multidim.c:51: Warning: check got status unknown. [eva] multidim.c:54: starting to merge loop iterations +[eva] multidim.c:53: starting to merge loop iterations +[kernel] multidim.c:55: + more than 1(20) locations to update in array. Approximating. [kernel] multidim.c:56: - more than 0(20) locations to update in array. Approximating. -[kernel] multidim.c:57: - more than 0(20) locations to update in array. Approximating. + more than 1(20) locations to update in array. Approximating. +[kernel] multidim.c:55: + more than 1(28) locations to update in array. Approximating. [kernel] multidim.c:56: - more than 0(28) locations to update in array. Approximating. -[kernel] multidim.c:57: - more than 0(28) locations to update in array. Approximating. -[eva] multidim.c:61: + more than 1(28) locations to update in array. Approximating. +[eva] multidim.c:60: Frama_C_domain_show_each: w : # cvalue: [0].t1[0].f ∈ [0. .. 2.] {[0]{.t1{[0].i; [1..3]}; .t2[0..3]}; [1..2]; [3].t1{[0..2]; [3].f}} ∈ [--..--] [3].t1[3].i ∈ {0; 2} [3].t2[0..3] ∈ {0} - # multidim: [0..3] = { .t1[0..3] = { .f = [0. .. 2.], .i = {0; 2} } } + # multidim: [0..3] = { .t1[-1..3] = { .f = [0. .. 2.], .i = {0; 2} } } [eva] computing for function Frama_C_interval <- main. - Called from multidim.c:63. + Called from multidim.c:62. [eva] using specification for function Frama_C_interval -[eva] multidim.c:63: +[eva] multidim.c:62: function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval [eva] computing for function Frama_C_interval <- main. - Called from multidim.c:63. -[eva] multidim.c:63: + Called from multidim.c:62. +[eva] multidim.c:62: function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval -[eva] multidim.c:65: +[eva] multidim.c:64: Frama_C_domain_show_each: t1 : # cvalue: [--..--] - # multidim: [--..--] + # multidim: T [eva] Recording results for main -[kernel] multidim.c:56: more than 0(28) elements to enumerate. Approximating. -[kernel] multidim.c:57: more than 0(28) elements to enumerate. Approximating. +[kernel] multidim.c:55: more than 1(28) elements to enumerate. Approximating. +[kernel] multidim.c:56: more than 1(28) elements to enumerate. Approximating. [eva] done for function main -[kernel] multidim.c:52: more than 0(28) elements to enumerate. Approximating. +[kernel] multidim.c:51: more than 1(28) elements to enumerate. Approximating. [eva] ====== VALUES COMPUTED ====== [eva:final-states] Values at end of function main: Frama_C_entropy_source ∈ [--..--] @@ -115,8 +140,8 @@ [from] Computing for function main [from] Computing for function f <-main [from] Done for function f -[kernel] multidim.c:56: more than 0(28) dependencies to update. Approximating. -[kernel] multidim.c:57: more than 0(28) dependencies to update. Approximating. +[kernel] multidim.c:55: more than 1(28) dependencies to update. Approximating. +[kernel] multidim.c:56: more than 1(28) dependencies to update. Approximating. [from] Computing for function Frama_C_interval <-main [from] Done for function Frama_C_interval [from] Done for function main