let frama_c_memcpy state actuals =
  try
    match actuals with
      | [exp_dst,dst,_; exp_src,src,_ ; exp_size,size,_] ->
          let size = Cvalue_type.V.project_ival size in
          let min,max = Ival.min_and_max size in
          let min = match min with
            | None -> Int.zero
            | Some m -> Int.max m Int.zero
          and max = match max with
            | None -> assert false (* TODO *)
            | Some m -> m
          in
          let size_min = Int.mul Int.eight min in
          let right = loc_bytes_to_loc_bits src in
          let left = loc_bytes_to_loc_bits dst in
          let right_loc = make_loc right (Int_Base.inject size_min) in
          let term_size = Logic_utils.expr_to_term ~cast:true exp_size in
          let array_src = Logic_utils.array_with_range exp_src term_size
          and array_dst = Logic_utils.array_with_range exp_dst term_size
          in
          CilE.set_syntactic_context (CilE.SyMemLogic array_src);
          begin
            match Relations_type.Model.copy_offsetmap
             ~with_alarms:(warn_all_quiet_mode ())
             right_loc
             state
            with
              | None ->
                  None,
                  Relations_type.Model.bottom,
                  Location_Bits.Top_Param.bottom

              | Some offsetmap ->
                  CilE.set_syntactic_context (CilE.SyMemLogic array_dst);
                  let new_state =
                    Relations_type.Model.paste_offsetmap
                      offsetmap left Int.zero size_min state
                  in
                  let fuzz = Int.sub max min in
                  if Int.is_zero fuzz
                  then None, new_state, Location_Bits.get_bases right
                  else
                    let fuzz = Int.mul Int.eight fuzz in
                    let fuzz = Int_Base.inject fuzz in
                    let ival_min = Ival.inject_singleton size_min in
                    let left = Location_Bits.location_shift ival_min left in
                    let right = Location_Bits.location_shift ival_min right in
                    CilE.set_syntactic_context (CilE.SyMemLogic array_src);
                    let garb =
                      Relations_type.Model.find
                        ~conflate_bottom:false
                        ~with_alarms:(warn_all_quiet_mode ())
                        state
                        (make_loc right fuzz)
                    in
                    CilE.set_syntactic_context (CilE.SyMemLogic array_dst);
                    let new_state =
                      Relations_type.Model.add_binding
                        ~exact:false
                        ~with_alarms:(warn_all_quiet_mode ())
                        new_state
                        (make_loc left fuzz)
                        garb
                    in
                    None, new_state, Location_Bits.get_bases right
          end
      | _ ->
          raise Db.Value.Aborted
  with
      V.Not_based_on_null | Lmap.Cannot_copy | Db.Value.Aborted ->
        Value_parameters.error
          "Invalid call to Frama_C_memcpy%a"
          pretty_actuals
          actuals;
        do_degenerate None;
        raise Db.Value.Aborted