[clang] initialize dynamically-size stack-allocated arrays

Summary:
Previously all knowledge of the dynamic length of such arrays was lost to infer:
```
void foo(int len) {
    int a[len];
}
```
The translation of this program would make no reference to `len` (except as a
param of `foo`).

Translate this "initialization" using the existing `__set_array_length` infer
builtin, as:

```
   # Declare local a[_]
   n$0 = len;
   __set_array_length(a, len);
```

update-submodule: facebook-clang-plugins

Reviewed By: mbouaziz

Differential Revision: D4969446

fbshipit-source-id: dff860f
master
Jules Villard 8 years ago committed by Facebook Github Bot
parent d5f4784e61
commit 252c78bb0e

@ -1 +1 @@
Subproject commit 84b3c58ab12fd42779ea4f8c1214432801cf4a5f Subproject commit 0c9c4d0ebb43c686143edb51c6e80e551df05b99

@ -35,13 +35,17 @@ struct
type extras = Typ.Procname.t -> Procdesc.t option type extras = Typ.Procname.t -> Procdesc.t option
let set_uninitialized (typ : Typ.t) loc mem = match typ.desc with
| Tint _ | Tfloat _ -> Dom.Mem.weak_update_heap loc Dom.Val.top_itv mem
| _ -> mem
(* NOTE: heuristic *) (* NOTE: heuristic *)
let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t
= function = function
| Exp.BinOp (Binop.Mult, Exp.Sizeof {typ; nbytes}, length) | Exp.BinOp (Binop.Mult, Exp.Sizeof {typ; nbytes}, length)
| Exp.BinOp (Binop.Mult, length, Exp.Sizeof {typ; nbytes}) -> (typ, nbytes, length) | Exp.BinOp (Binop.Mult, length, Exp.Sizeof {typ; nbytes}) -> (typ, nbytes, length)
| Exp.Sizeof {typ; nbytes} -> (typ, nbytes, Exp.one) | Exp.Sizeof {typ; nbytes} -> (typ, nbytes, Exp.one)
| x -> (Typ.mk (Typ.Tint Typ.IChar), Some 1, x) | x -> (Typ.mk (Typ.Tint Typ.IChar), Some 1, x)
let model_malloc let model_malloc
: Typ.Procname.t -> (Ident.t * Typ.t) option -> (Exp.t * Typ.t) list -> CFG.node : Typ.Procname.t -> (Ident.t * Typ.t) option -> (Exp.t * Typ.t) list -> CFG.node
@ -49,19 +53,12 @@ struct
= fun pname ret params node mem -> = fun pname ret params node mem ->
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
let set_uninitialized typ loc mem = let (typ, stride, length0) = get_malloc_info (List.hd_exn params |> fst) in
match typ.Typ.desc with let length = Sem.eval length0 mem (CFG.loc node) |> Dom.Val.get_itv in
| Typ.Tint _ let v = Sem.eval_array_alloc pname node typ ?stride Itv.zero length 0 1 in
| Typ.Tfloat _ -> mem
Dom.Mem.weak_update_heap loc Dom.Val.top_itv mem |> Dom.Mem.add_stack (Loc.of_id id) v
| _ -> mem |> set_uninitialized typ (Dom.Val.get_array_locs v)
in
let (typ, stride, length0) = get_malloc_info (List.hd_exn params |> fst) in
let length = Sem.eval length0 mem (CFG.loc node) |> Dom.Val.get_itv in
let v = Sem.eval_array_alloc pname node typ ?stride Itv.zero length 0 1 in
mem
|> Dom.Mem.add_stack (Loc.of_id id) v
|> set_uninitialized typ (Dom.Val.get_array_locs v)
| _ -> mem | _ -> mem
let model_realloc let model_realloc
@ -74,8 +71,8 @@ struct
= fun ret mem -> = fun ret mem ->
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
let itv = Itv.make (Itv.Bound.of_int (-1)) Itv.Bound.PInf in let itv = Itv.make (Itv.Bound.of_int (-1)) Itv.Bound.PInf in
Dom.Mem.add_stack (Loc.of_id id) (Dom.Val.of_itv itv) mem Dom.Mem.add_stack (Loc.of_id id) (Dom.Val.of_itv itv) mem
| _ -> mem | _ -> mem
let model_natual_itv : (Ident.t * Typ.t) option -> Dom.Mem.astate -> Dom.Mem.astate let model_natual_itv : (Ident.t * Typ.t) option -> Dom.Mem.astate -> Dom.Mem.astate
@ -95,13 +92,28 @@ struct
= fun params mem loc -> = fun params mem loc ->
match params with match params with
| (e, _) :: _ -> | (e, _) :: _ ->
if Config.bo_debug >= 1 then if Config.bo_debug >= 1 then
L.err "@[<v>=== Infer Print === at %a@,%a@]%!" L.err "@[<v>=== Infer Print === at %a@,%a@]%!"
Location.pp loc Location.pp loc
Dom.Val.pp (Sem.eval e mem loc); Dom.Val.pp (Sem.eval e mem loc);
mem mem
| _ -> mem | _ -> mem
let model_infer_set_array_length pname node params mem loc =
match params with
| (Exp.Lvar array_pvar, {Typ.desc=Typ.Tarray (typ, _, stride0)})
:: (length_exp, _) :: [] ->
let length = Sem.eval length_exp mem loc |> Dom.Val.get_itv in
let stride = Option.map ~f:IntLit.to_int stride0 in
let v = Sem.eval_array_alloc pname node typ ?stride Itv.zero length 0 1 in
mem
|> Dom.Mem.add_stack (Loc.of_pvar array_pvar) v
|> set_uninitialized typ (Dom.Val.get_array_locs v)
| _ :: _ :: [] ->
failwithf "Unexpected type of arguments for __set_array_length()"
| _ ->
failwithf "Unexpected number of arguments for __set_array_length()"
let handle_unknown_call let handle_unknown_call
: Typ.Procname.t -> (Ident.t * Typ.t) option -> Typ.Procname.t : Typ.Procname.t -> (Ident.t * Typ.t) option -> Typ.Procname.t
-> (Exp.t * Typ.t) list -> CFG.node -> Dom.Mem.astate -> Location.t -> (Exp.t * Typ.t) list -> CFG.node -> Dom.Mem.astate -> Location.t
@ -114,13 +126,14 @@ struct
| "strlen" -> model_natual_itv ret mem | "strlen" -> model_natual_itv ret mem
| "fgetc" -> model_fgetc ret mem | "fgetc" -> model_fgetc ret mem
| "infer_print" -> model_infer_print params mem loc | "infer_print" -> model_infer_print params mem loc
| "__set_array_length" -> model_infer_set_array_length pname node params mem loc
| _ -> model_unknown_itv ret mem | _ -> model_unknown_itv ret mem
let rec declare_array let rec declare_array
: Typ.Procname.t -> CFG.node -> Loc.t -> Typ.t -> length:IntLit.t -> ?stride:int : Typ.Procname.t -> CFG.node -> Loc.t -> Typ.t -> length:IntLit.t option -> ?stride:int
-> inst_num:int -> dimension:int -> Dom.Mem.astate -> Dom.Mem.astate -> inst_num:int -> dimension:int -> Dom.Mem.astate -> Dom.Mem.astate
= fun pname node loc typ ~length ?stride ~inst_num ~dimension mem -> = fun pname node loc typ ~length ?stride ~inst_num ~dimension mem ->
let size = IntLit.to_int length |> Itv.of_int in let size = Option.value_map ~default:Itv.top ~f:Itv.of_int_lit length in
let arr = let arr =
Sem.eval_array_alloc pname node typ Itv.zero size ?stride inst_num dimension Sem.eval_array_alloc pname node typ Itv.zero size ?stride inst_num dimension
in in
@ -133,7 +146,7 @@ struct
Loc.of_allocsite (Sem.get_allocsite pname node inst_num dimension) Loc.of_allocsite (Sem.get_allocsite pname node inst_num dimension)
in in
match typ.Typ.desc with match typ.Typ.desc with
| Typ.Tarray (typ, Some length, stride) -> | Typ.Tarray (typ, length, stride) ->
declare_array pname node loc typ ~length ?stride:(Option.map ~f:IntLit.to_int stride) declare_array pname node loc typ ~length ?stride:(Option.map ~f:IntLit.to_int stride)
~inst_num ~dimension:(dimension + 1) mem ~inst_num ~dimension:(dimension + 1) mem
| _ -> mem | _ -> mem
@ -162,26 +175,26 @@ struct
match typ.Typ.desc with match typ.Typ.desc with
| Typ.Tint _ | Typ.Tint _
| Typ.Tfloat _ -> | Typ.Tfloat _ ->
let v = Dom.Val.make_sym pname sym_num in let v = Dom.Val.make_sym pname sym_num in
(Dom.Mem.add_heap field v mem, sym_num + 2) (Dom.Mem.add_heap field v mem, sym_num + 2)
| Typ.Tptr (typ, _) -> | Typ.Tptr (typ, _) ->
let offset = Itv.make_sym pname sym_num in let offset = Itv.make_sym pname sym_num in
let size = Itv.make_sym pname (sym_num + 2) in let size = Itv.make_sym pname (sym_num + 2) in
let v = let v =
Sem.eval_array_alloc pname node typ offset size inst_num dimension Sem.eval_array_alloc pname node typ offset size inst_num dimension
in in
(Dom.Mem.add_heap field v mem, sym_num + 4) (Dom.Mem.add_heap field v mem, sym_num + 4)
| _ -> | _ ->
if Config.bo_debug >= 3 then if Config.bo_debug >= 3 then
L.err "decl_fld of unhandled type: %a@." (Typ.pp Pp.text) typ; L.err "decl_fld of unhandled type: %a@." (Typ.pp Pp.text) typ;
(mem, sym_num) (mem, sym_num)
in in
match typ.Typ.desc with match typ.Typ.desc with
| Typ.Tstruct typename -> | Typ.Tstruct typename ->
(match Tenv.lookup tenv typename with (match Tenv.lookup tenv typename with
| Some str -> | Some str ->
List.fold ~f:decl_fld ~init:(mem, sym_num + 6) str.Typ.Struct.fields List.fold ~f:decl_fld ~init:(mem, sym_num + 6) str.Typ.Struct.fields
| _ -> (mem, sym_num + 6)) | _ -> (mem, sym_num + 6))
| _ -> (mem, sym_num + 6) | _ -> (mem, sym_num + 6)
let declare_symbolic_parameter let declare_symbolic_parameter
@ -191,19 +204,19 @@ struct
let add_formal (mem, inst_num, sym_num) (pvar, typ) = let add_formal (mem, inst_num, sym_num) (pvar, typ) =
match typ.Typ.desc with match typ.Typ.desc with
| Typ.Tint _ -> | Typ.Tint _ ->
let v = Dom.Val.make_sym pname sym_num in let v = Dom.Val.make_sym pname sym_num in
let mem = Dom.Mem.add_heap (Loc.of_pvar pvar) v mem in let mem = Dom.Mem.add_heap (Loc.of_pvar pvar) v mem in
(mem, inst_num + 1, sym_num + 2) (mem, inst_num + 1, sym_num + 2)
| Typ.Tptr (typ, _) -> | Typ.Tptr (typ, _) ->
let (mem, sym_num) = let (mem, sym_num) =
declare_symbolic_array pname tenv node (Loc.of_pvar pvar) typ declare_symbolic_array pname tenv node (Loc.of_pvar pvar) typ
~inst_num ~sym_num ~dimension:1 mem ~inst_num ~sym_num ~dimension:1 mem
in in
(mem, inst_num + 1, sym_num) (mem, inst_num + 1, sym_num)
| _ -> | _ ->
if Config.bo_debug >= 3 then if Config.bo_debug >= 3 then
L.err "declare_symbolic_parameter of unhandled type: %a@." (Typ.pp Pp.text) typ; L.err "declare_symbolic_parameter of unhandled type: %a@." (Typ.pp Pp.text) typ;
(mem, inst_num, sym_num) (* TODO: add other cases if necessary *) (mem, inst_num, sym_num) (* TODO: add other cases if necessary *)
in in
List.fold ~f:add_formal ~init:(mem, inst_num, 0) (Sem.get_formals pdesc) List.fold ~f:add_formal ~init:(mem, inst_num, 0) (Sem.get_formals pdesc)
|> fst3 |> fst3
@ -216,13 +229,13 @@ struct
let callee_exit_mem = Dom.Summary.get_output summary in let callee_exit_mem = Dom.Summary.get_output summary in
match callee_pdesc with match callee_pdesc with
| Some pdesc -> | Some pdesc ->
let subst_map = let subst_map =
Sem.get_subst_map tenv pdesc params caller_mem callee_entry_mem loc Sem.get_subst_map tenv pdesc params caller_mem callee_entry_mem loc
in in
let ret_loc = Loc.of_pvar (Pvar.get_ret_pvar callee_pname) in let ret_loc = Loc.of_pvar (Pvar.get_ret_pvar callee_pname) in
let ret_val = Dom.Mem.find_heap ret_loc callee_exit_mem in let ret_val = Dom.Mem.find_heap ret_loc callee_exit_mem in
Dom.Val.subst ret_val subst_map Dom.Val.subst ret_val subst_map
|> Dom.Val.normalize (* normalize bottom *) |> Dom.Val.normalize (* normalize bottom *)
| _ -> Dom.Val.top_itv | _ -> Dom.Val.top_itv
let print_debug_info : Sil.instr -> Dom.Mem.astate -> Dom.Mem.astate -> unit let print_debug_info : Sil.instr -> Dom.Mem.astate -> Dom.Mem.astate -> unit
@ -244,7 +257,7 @@ struct
let pname = Procdesc.get_proc_name pdesc in let pname = Procdesc.get_proc_name pdesc in
let try_decl_arr (mem, inst_num) (pvar, typ) = let try_decl_arr (mem, inst_num) (pvar, typ) =
match typ.Typ.desc with match typ.Typ.desc with
| Typ.Tarray (typ, Some length, stride0) -> | Typ.Tarray (typ, length, stride0) ->
let loc = Loc.of_pvar pvar in let loc = Loc.of_pvar pvar in
let stride = Option.map ~f:IntLit.to_int stride0 in let stride = Option.map ~f:IntLit.to_int stride0 in
let mem = let mem =
@ -256,32 +269,32 @@ struct
let output_mem = let output_mem =
match instr with match instr with
| Load (id, exp, _, loc) -> | Load (id, exp, _, loc) ->
let locs = Sem.eval exp mem loc |> Dom.Val.get_all_locs in let locs = Sem.eval exp mem loc |> Dom.Val.get_all_locs in
let v = Dom.Mem.find_heap_set locs mem in let v = Dom.Mem.find_heap_set locs mem in
Dom.Mem.add_stack (Loc.of_var (Var.of_id id)) v mem Dom.Mem.add_stack (Loc.of_var (Var.of_id id)) v mem
|> Dom.Mem.load_alias id exp |> Dom.Mem.load_alias id exp
| Store (exp1, _, exp2, loc) -> | Store (exp1, _, exp2, loc) ->
let locs = Sem.eval exp1 mem loc |> Dom.Val.get_all_locs in let locs = Sem.eval exp1 mem loc |> Dom.Val.get_all_locs in
Dom.Mem.update_mem locs (Sem.eval exp2 mem loc) mem Dom.Mem.update_mem locs (Sem.eval exp2 mem loc) mem
|> Dom.Mem.store_alias exp1 exp2 |> Dom.Mem.store_alias exp1 exp2
| Prune (exp, loc, _, _) -> Sem.prune exp loc mem | Prune (exp, loc, _, _) -> Sem.prune exp loc mem
| Call (ret, Const (Cfun callee_pname), params, loc, _) -> | Call (ret, Const (Cfun callee_pname), params, loc, _) ->
(match Summary.read_summary pdesc callee_pname with (match Summary.read_summary pdesc callee_pname with
| Some summary -> | Some summary ->
let callee = extras callee_pname in let callee = extras callee_pname in
let ret_val = let ret_val =
instantiate_ret tenv callee callee_pname params mem summary loc instantiate_ret tenv callee callee_pname params mem summary loc
in in
(match ret with (match ret with
| Some (id, _) -> | Some (id, _) ->
Dom.Mem.add_stack (Loc.of_var (Var.of_id id)) ret_val mem Dom.Mem.add_stack (Loc.of_var (Var.of_id id)) ret_val mem
| _ -> mem) | _ -> mem)
| None -> | None ->
handle_unknown_call pname ret callee_pname params node mem loc) handle_unknown_call pname ret callee_pname params node mem loc)
| Declare_locals (locals, _) -> | Declare_locals (locals, _) ->
(* array allocation in stack e.g., int arr[10] *) (* array allocation in stack e.g., int arr[10] *)
let (mem, inst_num) = List.fold ~f:try_decl_arr ~init:(mem, 1) locals in let (mem, inst_num) = List.fold ~f:try_decl_arr ~init:(mem, 1) locals in
declare_symbolic_parameter pdesc tenv node inst_num mem declare_symbolic_parameter pdesc tenv node inst_num mem
| Call _ | Call _
| Remove_temps _ | Remove_temps _
| Abstract _ | Abstract _
@ -308,33 +321,33 @@ struct
let array_access = let array_access =
match exp with match exp with
| Exp.Var _ -> | Exp.Var _ ->
let arr = Sem.eval exp mem loc |> Dom.Val.get_array_blk in let arr = Sem.eval exp mem loc |> Dom.Val.get_array_blk in
Some (arr, Itv.zero, true) Some (arr, Itv.zero, true)
| Exp.Lindex (e1, e2) | Exp.Lindex (e1, e2)
| Exp.BinOp (Binop.PlusA, e1, e2) -> | Exp.BinOp (Binop.PlusA, e1, e2) ->
let arr = Sem.eval e1 mem loc |> Dom.Val.get_array_blk in let arr = Sem.eval e1 mem loc |> Dom.Val.get_array_blk in
let idx = Sem.eval e2 mem loc |> Dom.Val.get_itv in let idx = Sem.eval e2 mem loc |> Dom.Val.get_itv in
Some (arr, idx, true) Some (arr, idx, true)
| Exp.BinOp (Binop.MinusA, e1, e2) -> | Exp.BinOp (Binop.MinusA, e1, e2) ->
let arr = Sem.eval e1 mem loc |> Dom.Val.get_array_blk in let arr = Sem.eval e1 mem loc |> Dom.Val.get_array_blk in
let idx = Sem.eval e2 mem loc |> Dom.Val.get_itv in let idx = Sem.eval e2 mem loc |> Dom.Val.get_itv in
Some (arr, idx, false) Some (arr, idx, false)
| _ -> None | _ -> None
in in
match array_access with match array_access with
| Some (arr, idx, is_plus) -> | Some (arr, idx, is_plus) ->
let site = Sem.get_allocsite pname node 0 0 in let site = Sem.get_allocsite pname node 0 0 in
let size = ArrayBlk.sizeof arr in let size = ArrayBlk.sizeof arr in
let offset = ArrayBlk.offsetof arr in let offset = ArrayBlk.offsetof arr in
let idx = (if is_plus then Itv.plus else Itv.minus) offset idx in let idx = (if is_plus then Itv.plus else Itv.minus) offset idx in
(if Config.bo_debug >= 2 then (if Config.bo_debug >= 2 then
(L.err "@[<v 2>Add condition :@,"; (L.err "@[<v 2>Add condition :@,";
L.err "array: %a@," ArrayBlk.pp arr; L.err "array: %a@," ArrayBlk.pp arr;
L.err " idx: %a@," Itv.pp idx; L.err " idx: %a@," Itv.pp idx;
L.err "@]@.")); L.err "@]@."));
if size <> Itv.bot && idx <> Itv.bot then if size <> Itv.bot && idx <> Itv.bot then
Dom.ConditionSet.add_bo_safety pname loc site ~size ~idx cond_set Dom.ConditionSet.add_bo_safety pname loc site ~size ~idx cond_set
else cond_set else cond_set
| None -> cond_set | None -> cond_set
let instantiate_cond let instantiate_cond
@ -345,11 +358,11 @@ struct
let callee_cond = Dom.Summary.get_cond_set summary in let callee_cond = Dom.Summary.get_cond_set summary in
match callee_pdesc with match callee_pdesc with
| Some pdesc -> | Some pdesc ->
let subst_map = let subst_map =
Sem.get_subst_map tenv pdesc params caller_mem callee_entry_mem loc Sem.get_subst_map tenv pdesc params caller_mem callee_entry_mem loc
in in
let pname = Procdesc.get_proc_name pdesc in let pname = Procdesc.get_proc_name pdesc in
Dom.ConditionSet.subst callee_cond subst_map caller_pname pname loc Dom.ConditionSet.subst callee_cond subst_map caller_pname pname loc
| _ -> callee_cond | _ -> callee_cond
let print_debug_info : Sil.instr -> Dom.Mem.astate -> Dom.ConditionSet.t -> unit let print_debug_info : Sil.instr -> Dom.Mem.astate -> Dom.ConditionSet.t -> unit
@ -371,15 +384,15 @@ struct
match instr with match instr with
| Sil.Load (_, exp, _, loc) | Sil.Load (_, exp, _, loc)
| Sil.Store (exp, _, _, loc) -> | Sil.Store (exp, _, _, loc) ->
add_condition pname node exp loc mem cond_set add_condition pname node exp loc mem cond_set
| Sil.Call (_, Const (Cfun callee_pname), params, loc, _) -> | Sil.Call (_, Const (Cfun callee_pname), params, loc, _) ->
(match Summary.read_summary pdesc callee_pname with (match Summary.read_summary pdesc callee_pname with
| Some summary -> | Some summary ->
let callee = extras callee_pname in let callee = extras callee_pname in
instantiate_cond tenv pname callee params mem summary loc instantiate_cond tenv pname callee params mem summary loc
|> Dom.ConditionSet.rm_invalid |> Dom.ConditionSet.rm_invalid
|> Dom.ConditionSet.join cond_set |> Dom.ConditionSet.join cond_set
| _ -> cond_set) | _ -> cond_set)
| _ -> cond_set | _ -> cond_set
in in
let mem = Analyzer.TransferFunctions.exec_instr mem pdata node instr in let mem = Analyzer.TransferFunctions.exec_instr mem pdata node instr in
@ -420,12 +433,12 @@ struct
match alarm with match alarm with
| None -> () | None -> ()
| Some bucket when Typ.Procname.equal pname caller_pname -> | Some bucket when Typ.Procname.equal pname caller_pname ->
let description = Dom.Condition.to_string cond in let description = Dom.Condition.to_string cond in
let error_desc = Localise.desc_buffer_overrun bucket description in let error_desc = Localise.desc_buffer_overrun bucket description in
let exn = let exn =
Exceptions.Checkers (Localise.to_issue_id Localise.buffer_overrun, error_desc) in Exceptions.Checkers (Localise.to_issue_id Localise.buffer_overrun, error_desc) in
let trace = [Errlog.make_trace_element 0 loc description []] in let trace = [Errlog.make_trace_element 0 loc description []] in
Reporting.log_error pname ~loc ~ltr:trace exn Reporting.log_error pname ~loc ~ltr:trace exn
| _ -> () | _ -> ()
in in
Dom.ConditionSet.iter report1 conds Dom.ConditionSet.iter report1 conds
@ -449,7 +462,7 @@ let compute_post
Report.report_error pdesc cond_set; Report.report_error pdesc cond_set;
match entry_mem, exit_mem with match entry_mem, exit_mem with
| Some entry_mem, Some exit_mem -> | Some entry_mem, Some exit_mem ->
Some (entry_mem, exit_mem, cond_set) Some (entry_mem, exit_mem, cond_set)
| _ -> None | _ -> None
let print_summary : Typ.Procname.t -> Dom.Summary.t -> unit let print_summary : Typ.Procname.t -> Dom.Summary.t -> unit

@ -859,6 +859,8 @@ let ub : t -> Bound.t
let of_int : int -> astate let of_int : int -> astate
= fun n -> NonBottom (ItvPure.of_int n) = fun n -> NonBottom (ItvPure.of_int n)
let of_int_lit n = of_int (IntLit.to_int n)
let is_bot : t -> bool let is_bot : t -> bool
= fun x -> equal x Bottom = fun x -> equal x Bottom

@ -1676,11 +1676,37 @@ struct
(* something's wrong *) (* something's wrong *)
{ empty_res_trans with root_nodes = trans_state.succ_nodes } { empty_res_trans with root_nodes = trans_state.succ_nodes }
and init_expr_trans trans_state var_exp_typ var_stmt_info init_expr_opt = and init_dynamic_array trans_state array_exp_typ array_stmt_info dynlength_stmt_pointer =
let dynlength_stmt = Clang_ast_main.PointerMap.find dynlength_stmt_pointer
!CFrontend_config.pointer_stmt_index in
let dynlength_stmt_info, _ = Clang_ast_proj.get_stmt_tuple dynlength_stmt in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state array_stmt_info in
let dynlength_trans_result = instruction trans_state_pri dynlength_stmt in
let dynlength_exp_typ = extract_exp_from_list dynlength_trans_result.exps
"WARNING: There should be one expression.\n" in
let sil_loc = CLocation.get_sil_location dynlength_stmt_info trans_state_pri.context in
let call_instr =
let call_exp = Exp.Const (Const.Cfun BuiltinDecl.__set_array_length) in
let actuals = [array_exp_typ; dynlength_exp_typ] in
Sil.Call (None, call_exp, actuals, sil_loc, CallFlags.default) in
let call_trans_result = { empty_res_trans with instrs = [call_instr] } in
let res_trans = PriorityNode.compute_results_to_parent trans_state_pri sil_loc
"Initialize dynamic array length" dynlength_stmt_info
[dynlength_trans_result; call_trans_result] in
{ res_trans with exps = [] }
and init_expr_trans trans_state var_exp_typ ?qual_type var_stmt_info init_expr_opt =
match init_expr_opt with match init_expr_opt with
| None -> | None -> (
(* Nothing to do if no init expression *) match Option.map ~f:(fun qt -> qt.Clang_ast_t.qt_type_ptr) qual_type
{ empty_res_trans with root_nodes = trans_state.succ_nodes } |> Option.find_map ~f:CAst_utils.get_type with
| Some (Clang_ast_t.VariableArrayType (_, _, stmt_pointer)) ->
(* Set the dynamic length of the variable length array. Variable length array cannot
have an initialization expression. *)
init_dynamic_array trans_state var_exp_typ var_stmt_info stmt_pointer
| _ ->
(* Nothing to do if no init expression and not a variable length array *)
{ empty_res_trans with root_nodes = trans_state.succ_nodes})
| Some ie -> (*For init expr, translate how to compute it and assign to the var*) | Some ie -> (*For init expr, translate how to compute it and assign to the var*)
let var_exp, _ = var_exp_typ in let var_exp, _ = var_exp_typ in
let context = trans_state.context in let context = trans_state.context in
@ -1732,7 +1758,8 @@ struct
let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in
CVar_decl.add_var_to_locals procdesc var_decl typ pvar; CVar_decl.add_var_to_locals procdesc var_decl typ pvar;
let trans_state' = { trans_state with succ_nodes = next_node } in let trans_state' = { trans_state with succ_nodes = next_node } in
init_expr_trans trans_state' (Exp.Lvar pvar, typ) stmt_info vdi.Clang_ast_t.vdi_init_expr in init_expr_trans trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info
vdi.Clang_ast_t.vdi_init_expr in
match var_decls with match var_decls with
| [] -> { empty_res_trans with root_nodes = next_nodes } | [] -> { empty_res_trans with root_nodes = next_nodes }

@ -97,7 +97,7 @@ and type_desc_of_c_type translate_decl tenv c_type : Typ.desc =
| IncompleteArrayType (_, {arti_element_type; arti_stride}) | IncompleteArrayType (_, {arti_element_type; arti_stride})
| DependentSizedArrayType (_, {arti_element_type; arti_stride}) -> | DependentSizedArrayType (_, {arti_element_type; arti_stride}) ->
build_array_type translate_decl tenv arti_element_type None arti_stride build_array_type translate_decl tenv arti_element_type None arti_stride
| VariableArrayType (_, {arti_element_type; arti_stride}) -> | VariableArrayType (_, {arti_element_type; arti_stride}, _) ->
build_array_type translate_decl tenv arti_element_type None arti_stride build_array_type translate_decl tenv arti_element_type None arti_stride
| ConstantArrayType (_, {arti_element_type; arti_stride}, n) -> | ConstantArrayType (_, {arti_element_type; arti_stride}, n) ->
build_array_type translate_decl tenv arti_element_type (Some n) arti_stride build_array_type translate_decl tenv arti_element_type (Some n) arti_stride

@ -0,0 +1,14 @@
/*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
void init_variable_array(int len) {
int x = 2 * len;
int a[len + x + 1];
a[len + x + 1] = 0;
}

@ -1,3 +1,4 @@
codetoanalyze/c/bufferoverrun/array_dynlength.c, init_variable_array, 3, BUFFER_OVERRUN, [Offset: [3xs$0 + 1, 3xs$1 + 1] Size: [3xs$0 + 1, 3xs$1 + 1] @ codetoanalyze/c/bufferoverrun/array_dynlength.c:13:3]
codetoanalyze/c/bufferoverrun/break_continue_return.c, break_continue_return, 16, BUFFER_OVERRUN, [Offset: [0, 10] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/break_continue_return.c:29:5] codetoanalyze/c/bufferoverrun/break_continue_return.c, break_continue_return, 16, BUFFER_OVERRUN, [Offset: [0, 10] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/break_continue_return.c:29:5]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 2, BUFFER_OVERRUN, [Offset: [0, +oo] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ] codetoanalyze/c/bufferoverrun/do_while.c, do_while, 2, BUFFER_OVERRUN, [Offset: [0, +oo] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 3, BUFFER_OVERRUN, [Offset: [0, +oo] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ] codetoanalyze/c/bufferoverrun/do_while.c, do_while, 3, BUFFER_OVERRUN, [Offset: [0, +oo] Size: [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ]

@ -7,7 +7,12 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
int main() { int init_const_array() {
int z; int z;
int a[2][3] = {{z + 1, 2, 3}, {5, 6, 7}}; int a[2][3] = {{z + 1, 2, 3}, {5, 6, 7}};
} }
void init_variable_array(int len) {
int x = 2 * len;
int a[len + x + 1];
}

@ -1,14 +1,29 @@
/* @generated */ /* @generated */
digraph iCFG { digraph iCFG {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: a:int[3*32][2*96] z:int \n DECLARE_LOCALS(&return,&a,&z); [line 10]\n " color=yellow style=filled] "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_1" [label="1: Start init_const_array\nFormals: \nLocals: a:int[3*32][2*96] z:int \n DECLARE_LOCALS(&return,&a,&z); [line 10]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_3" ; "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_1" -> "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_3" ;
"main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled] "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_2" [label="2: Exit init_const_array \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n n$0=*&z:int [line 12]\n *&a[0][0]:int=(n$0 + 1) [line 12]\n *&a[0][1]:int=2 [line 12]\n *&a[0][2]:int=3 [line 12]\n *&a[1][0]:int=5 [line 12]\n *&a[1][1]:int=6 [line 12]\n *&a[1][2]:int=7 [line 12]\n " shape="box"] "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_3" [label="3: DeclStmt \n n$0=*&z:int [line 12]\n *&a[0][0]:int=(n$0 + 1) [line 12]\n *&a[0][1]:int=2 [line 12]\n *&a[0][2]:int=3 [line 12]\n *&a[1][0]:int=5 [line 12]\n *&a[1][1]:int=6 [line 12]\n *&a[1][2]:int=7 [line 12]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ; "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_3" -> "init_const_array.b1cf412cdbd1beaf15a9f6a3789043b9_2" ;
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_1" [label="1: Start init_variable_array\nFormals: len:int\nLocals: a:int[_*32] x:int \n DECLARE_LOCALS(&return,&a,&x); [line 15]\n " color=yellow style=filled]
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_1" -> "init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_4" ;
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_2" [label="2: Exit init_variable_array \n " color=yellow style=filled]
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_3" [label="3: Fallback node \n n$0=*&len:int [line 17]\n n$1=*&x:int [line 17]\n _fun___set_array_length(&a:int[_*32],((n$0 + n$1) + 1):int) [line 17]\n " shape="box"]
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_3" -> "init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_2" ;
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_4" [label="4: DeclStmt \n n$2=*&len:int [line 16]\n *&x:int=(2 * n$2) [line 16]\n " shape="box"]
"init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_4" -> "init_variable_array.8cdc6857adcb1fd04fb6555d8ce3e4c1_3" ;
} }

Loading…
Cancel
Save