let subst_havoc (m:mem) = function

    | F.Aloc(_,(Path p| PRef p | PRpar(p,_)))
        when p.p_off=[] ->
        let x = get_funvar m p.p_arity p.p_root false in
        let v = L.fresh (F.basename_of_var x) (F.kind_of_var x) in
        [F.Fresh v;F.Update(x,fun _ -> F.var v)]
    | F.Aloc(_, (ARpar(p,_)| ARef p)) when p.p_off=[] ->
        let x = get_funvar m p.p_arity p.p_root true in
        let v = L.fresh (F.basename_of_var x) (F.kind_of_var x) in
        [F.Fresh v;F.Update(x,fun _ -> F.var v)]

    | F.Aloc(_,(Path p| PRef p | PRpar(p,_))) ->
        let x = get_funvar m p.p_arity p.p_root false in
        let v = 
          match p.p_type with
            | None -> Wp_parameters.fatal "[subst_havoc] pure logic var"
            | Some ty ->
                L.fresh "v" (Model (tau_of_object ty))
        in
        let newterm (sigma : (F.var * F.var) list ) : F.abstract =
          F.wrap ( update_offset
                     (fun _ -> F.var v)
                     (L.apply sigma (F.var x)) p.p_off )
        in
        [F.Fresh v;F.Update(x,newterm)]

    | F.Aloc(_, (ARpar(p,_)| ARef p)) ->
      let x = get_funvar m p.p_arity p.p_root true in
      let v = 
        match p.p_type with 
          | None -> Wp_parameters.fatal "[subst_havoc] of pure logic var"
          | Some ty -> L.fresh "v" (Model (tau_of_object ty))
      in
      let newterm (sigma : (F.var * F.var) list ) : F.abstract =
        F.wrap ( update_offset
                   (fun _ -> F.var v)
                   (L.apply sigma (F.var x)) p.p_off )
      in
      [F.Fresh v;F.Update(x,newterm)]
        
    | F.Arange(_,(Path p| PRef p | PRpar(p,_)),rg) ->
        let x = get_funvar m p.p_arity p.p_root false in
        let upd_range rg = fun array ->
          F.wrap (F.set_range_index (F.unwrap array) rg)
        in
        let newterm (sigma :(F.var * F.var) list ) : F.abstract =
          F.wrap (update_offset (upd_range rg) (L.apply sigma (F.var x)) 
                    p.p_off)
        in
        [F.Update(x,newterm)]
          
    | F.Arange(_, (ARpar(p,_)| ARef p),rg) ->
        let x = get_funvar m p.p_arity p.p_root true in
        let upd_range rg = fun array ->
          F.wrap (F.set_range_index (F.unwrap array) rg)
        in
        let newterm (sigma :(F.var * F.var) list ) : F.abstract =
          F.wrap (update_offset (upd_range rg) (L.apply sigma (F.var x))
                    p.p_off)
        in
        [F.Update(x,newterm)]
          
    | F.Aloc(te,Mloc l) -> 
        M.subst_havoc m.mem (F.Aloc(te,l))

    | F.Arange(te,Mloc l,rg) ->
        M.subst_havoc m.mem (F.Arange(te,l,rg))