Translate enums as ints and not add them to the tenv

Summary: public This diff changes the way we treat enums in Infer.
1. The semantics of the translation is now correct, it was a bit incorrect before.
2. We don't add the enum types to the tenv anymore, which saves a lot of disk space
and avoids errors in the backend dealing with the enum type.

Reviewed By: akotulski

Differential Revision: D2641903

fb-gh-sync-id: 6295e5f
master
Dulma Rodriguez 9 years ago committed by facebook-github-bot-1
parent 80af77a528
commit de1a627335

@ -217,3 +217,9 @@ let bin_op_to_string boi =
| `XorAssign -> "XorAssign" | `XorAssign -> "XorAssign"
| `OrAssign -> "OrAssign" | `OrAssign -> "OrAssign"
| `Comma -> "Comma" | `Comma -> "Comma"
let sil_const_plus_one const =
match const with
| Sil.Const (Sil.Cint n) ->
Sil.Const (Sil.Cint (Sil.Int.add n Sil.Int.one))
| _ -> Sil.BinOp (Sil.PlusA, const, Sil.Const (Sil.Cint (Sil.Int.one)))

@ -25,3 +25,5 @@ val compound_assignment_binary_operation_instruction : Clang_ast_t.binary_operat
val assignment_arc_mode : val assignment_arc_mode :
CContext.t -> Sil.exp -> Sil.typ -> Sil.exp -> Location.t -> bool -> bool -> CContext.t -> Sil.exp -> Sil.typ -> Sil.exp -> Location.t -> bool -> bool ->
Sil.exp * Sil.instr list * Ident.t list Sil.exp * Sil.instr list * Ident.t list
val sil_const_plus_one : Sil.exp -> Sil.exp

@ -13,52 +13,40 @@
open Utils open Utils
open CFrontend_utils open CFrontend_utils
let create_empty_procdesc () = (*Check if the constant is in the map, in which case that means that all the *)
let proc_name = Procname.from_string_c_fun "__INFER_$GLOBAL_VAR_env" in (* contants of this enum are in the map, by invariant. Otherwise, add the constant *)
let proc_attributes = ProcAttributes.default proc_name Config.C_CPP in (* to the map. *)
Cfg.Procdesc.create { let add_enum_constant_to_map_if_needed decl_pointer pred_decl_opt =
Cfg.Procdesc.cfg = Cfg.Node.create_cfg (); try
proc_attributes = proc_attributes; ignore (Ast_utils.get_enum_constant_exp decl_pointer);
} true
with Not_found ->
Ast_utils.add_enum_constant decl_pointer pred_decl_opt;
false
(* We will use global_procdesc for storing global variables. *) (* Add the constants of this enum to the map if they are not in the map yet *)
(* Globals will be stored as locals in global_procdesc and they are added*) let enum_decl decl =
(* when traversing the AST. *) let open Clang_ast_t in
let global_procdesc = ref (create_empty_procdesc ()) let get_constant_decl_ptr decl =
match decl with
| EnumConstantDecl (decl_info, _, _, _) -> decl_info.di_pointer
| _ -> assert false in
let rec add_enum_constants_to_map decl_list =
match decl_list with
| decl :: pred_decl :: rest ->
let decl_pointer = get_constant_decl_ptr decl in
let pred_decl_pointer = get_constant_decl_ptr pred_decl in
if not (add_enum_constant_to_map_if_needed decl_pointer (Some pred_decl_pointer)) then
add_enum_constants_to_map (pred_decl::rest)
| [decl] ->
let decl_pointer = get_constant_decl_ptr decl in
ignore (add_enum_constant_to_map_if_needed decl_pointer None)
| _ -> () in
match decl with
| EnumDecl (decl_info, _, _, type_ptr, decl_list, _, _) ->
add_enum_constants_to_map (IList.rev decl_list);
let sil_type = Sil.Tint Sil.IInt in
Ast_utils.update_sil_types_map type_ptr sil_type;
sil_type
let rec get_enum_constants context decl_list v =
match decl_list with
| [] -> []
| Clang_ast_t.EnumConstantDecl (decl_info, name_info, type_ptr, enum_constant_decl_info) :: decl_list' ->
let name = name_info.Clang_ast_t.ni_name in
(match enum_constant_decl_info.Clang_ast_t.ecdi_init_expr with
| None -> Printing.log_out "%s" (" ...Defining Enum Constant ("^name^", "^(string_of_int v));
(Mangled.from_string name, Sil.Cint (Sil.Int.of_int v))
:: get_enum_constants context decl_list' (v + 1)
| Some stmt ->
let e = CGen_trans.CTransImpl.expression_trans context stmt
"WARNING: Expression in Enumeration constant not found\n" in
let const = (match Prop.exp_normalize_prop Prop.prop_emp e with
| Sil.Const c -> c
| _ -> (* This is a hack to avoid failing in some strange definition of Enum *)
Sil.Cint Sil.Int.zero) in
Printing.log_out " ...Defining Enum Constant ('%s', " name;
Printing.log_out "'%s')\n" (Sil.exp_to_string (Sil.Const const));
(Mangled.from_string name, const) :: get_enum_constants context decl_list' v)
| _ -> assert false | _ -> assert false
let enum_decl name tenv cfg cg namespace type_ptr decl_list opt_type =
Printing.log_out "ADDING: EnumDecl '%s'\n" name;
let context' =
CContext.create_context tenv cg cfg !global_procdesc namespace CContext.ContextNoCls
false None in
let enum_constants = get_enum_constants context' decl_list 0 in
let name = (match opt_type with (* If the type is defined it's of the kind "enum name" and we take that.*)
| `Type s -> s
| `NoType -> assert false) in
(* Here we could give "enum "^name but I want to check that this the type is always defined *)
let typename = CTypes.mk_enumname name in
let typ = Sil.Tenum enum_constants in
Ast_utils.update_sil_types_map type_ptr typ;
Printing.log_out " TN_typename('%s')\n" (Sil.typename_to_string typename);
Sil.tenv_add tenv typename typ

@ -9,6 +9,6 @@
(** Translate an enumeration declaration by adding it to the tenv and *) (** Translate an enumeration declaration by adding it to the tenv and *)
(** translating the code and adding it to a fake procdesc *) (** translating the code and adding it to a fake procdesc *)
open CFrontend_utils
val enum_decl : string -> Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> Clang_ast_t.type_ptr -> val enum_decl : Clang_ast_t.decl -> Sil.typ
Clang_ast_t.decl list -> Clang_ast_t.opt_type -> unit

@ -29,7 +29,6 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
CLocation.update_curr_file info; CLocation.update_curr_file info;
let source_range = info.Clang_ast_t.di_source_range in let source_range = info.Clang_ast_t.di_source_range in
let should_translate_decl = CLocation.should_translate_lib source_range in let should_translate_decl = CLocation.should_translate_lib source_range in
let should_translate_enum = CLocation.should_translate_enum source_range in
let open Clang_ast_t in let open Clang_ast_t in
match dec with match dec with
| FunctionDecl(di, name_info, tp, fdecl_info) when should_translate_decl -> | FunctionDecl(di, name_info, tp, fdecl_info) when should_translate_decl ->
@ -99,10 +98,7 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
| Some dec -> Printing.log_stats "Methods of %s skipped\n" (Ast_utils.string_of_decl dec) | Some dec -> Printing.log_stats "Methods of %s skipped\n" (Ast_utils.string_of_decl dec)
| None -> ()) | None -> ())
| EnumDecl(decl_info, name_info, opt_type, pointer, decl_list, decl_context_info, enum_decl_info) | EnumDecl _ -> ignore (CEnum_decl.enum_decl dec)
when should_translate_enum ->
let name = name_info.Clang_ast_t.ni_name in
CEnum_decl.enum_decl name tenv cfg cg namespace pointer decl_list opt_type
| LinkageSpecDecl(decl_info, decl_list, decl_context_info) -> | LinkageSpecDecl(decl_info, decl_list, decl_context_info) ->
Printing.log_out "ADDING: LinkageSpecDecl decl list\n"; Printing.log_out "ADDING: LinkageSpecDecl decl list\n";
@ -112,8 +108,7 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
IList.iter (translate_one_declaration tenv cg cfg (Some name) dec) decl_list IList.iter (translate_one_declaration tenv cg cfg (Some name) dec) decl_list
| EmptyDecl _ -> | EmptyDecl _ ->
Printing.log_out "Passing from EmptyDecl. Treated as skip\n"; Printing.log_out "Passing from EmptyDecl. Treated as skip\n";
| dec -> | dec -> ()
Printing.log_stats "\nWARNING: found Declaration %s skipped\n" (Ast_utils.string_of_decl dec)
(* Translates a file by translating the ast into a cfg. *) (* Translates a file by translating the ast into a cfg. *)
let compute_icfg tenv source_file ast = let compute_icfg tenv source_file ast =

@ -156,6 +156,9 @@ let pointer_type_index = ref Clang_ast_main.PointerMap.empty
(* Map from type pointers or declaration pointers to sil types *) (* Map from type pointers or declaration pointers to sil types *)
let sil_types_map = ref Clang_ast_types.TypePointerMap.empty let sil_types_map = ref Clang_ast_types.TypePointerMap.empty
(* Map from enum constants pointers to their predecesor and their sil value *)
let enum_map = ref Clang_ast_main.PointerMap.empty
let type_pointer_prefix = "internal_type" let type_pointer_prefix = "internal_type"
let nsarray_cl = "NSArray" let nsarray_cl = "NSArray"

@ -151,6 +151,9 @@ val pointer_type_index : Clang_ast_t.c_type Clang_ast_main.PointerMap.t ref
Populated during frontend execution when new type is found *) Populated during frontend execution when new type is found *)
val sil_types_map : (Sil.typ Clang_ast_types.TypePointerMap.t) ref val sil_types_map : (Sil.typ Clang_ast_types.TypePointerMap.t) ref
(** Map from enum constants pointers to their predecesor and their sil value *)
val enum_map : (Clang_ast_t.pointer option * Sil.exp option) Clang_ast_main.PointerMap.t ref
val type_pointer_prefix : string val type_pointer_prefix : string
val nsarray_cl : string val nsarray_cl : string

@ -286,6 +286,23 @@ struct
CFrontend_config.sil_types_map := CFrontend_config.sil_types_map :=
Clang_ast_types.TypePointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map Clang_ast_types.TypePointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map
let update_enum_map enum_constant_pointer sil_exp =
let open Clang_ast_main in
let (predecessor_pointer_opt, sil_exp_opt) =
try PointerMap.find enum_constant_pointer !CFrontend_config.enum_map
with Not_found -> assert false in
let enum_map_value = (predecessor_pointer_opt, Some sil_exp) in
CFrontend_config.enum_map :=
PointerMap.add enum_constant_pointer enum_map_value !CFrontend_config.enum_map
let add_enum_constant enum_constant_pointer predecessor_pointer_opt =
let enum_map_value = (predecessor_pointer_opt, None) in
CFrontend_config.enum_map :=
Clang_ast_main.PointerMap.add enum_constant_pointer enum_map_value !CFrontend_config.enum_map
let get_enum_constant_exp enum_constant_pointer =
Clang_ast_main.PointerMap.find enum_constant_pointer !CFrontend_config.enum_map
let get_type type_ptr = let get_type type_ptr =
try try
(* There is chance for success only if type_ptr is in fact clang pointer *) (* There is chance for success only if type_ptr is in fact clang pointer *)

@ -81,6 +81,12 @@ sig
val update_sil_types_map : Clang_ast_t.type_ptr -> Sil.typ -> unit val update_sil_types_map : Clang_ast_t.type_ptr -> Sil.typ -> unit
val update_enum_map : Clang_ast_t.pointer -> Sil.exp -> unit
val add_enum_constant : Clang_ast_t.pointer -> Clang_ast_t.pointer option -> unit
val get_enum_constant_exp : Clang_ast_t.pointer -> Clang_ast_t.pointer option * Sil.exp option
(** creates a string to append to a name from a list of qualifiers to a name *) (** creates a string to append to a name from a list of qualifiers to a name *)
val get_qualifier_string : Clang_ast_t.named_decl_info -> string val get_qualifier_string : Clang_ast_t.named_decl_info -> string

@ -25,10 +25,6 @@ module type CTrans = sig
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list -> val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list ->
Cfg.Node.t -> Cfg.Node.t list Cfg.Node.t -> Cfg.Node.t list
(** It receives the context and a statement and a warning string and returns the translated sil expression *)
(** that represents the translation of the stmts into sil. *)
val expression_trans : CContext.t -> Clang_ast_t.stmt -> string -> Sil.exp
end end
module CTrans_funct(M: CModule_type.CMethod_declaration) : CTrans = module CTrans_funct(M: CModule_type.CMethod_declaration) : CTrans =
@ -125,7 +121,7 @@ struct
if pred_exit = [] then if pred_exit = [] then
[Sil.Nullify(block_var, loc, true)] [Sil.Nullify(block_var, loc, true)]
else (IList.iter (fun n -> let loc = Cfg.Node.get_loc n in else (IList.iter (fun n -> let loc = Cfg.Node.get_loc n in
Cfg.Node.append_instrs_temps n [Sil.Nullify(block_var, loc, true)] []) pred_exit; Cfg.Node.append_instrs_temps n [Sil.Nullify(block_var, loc, true)] []) pred_exit;
[]) in []) in
let set_instr = Sil.Set(Sil.Lvar block_var, block_type, Sil.Var id_block, loc) in let set_instr = Sil.Set(Sil.Lvar block_var, block_type, Sil.Var id_block, loc) in
let ids, captured_instrs = IList.split (IList.map (fun (vname, typ, _) -> let ids, captured_instrs = IList.split (IList.map (fun (vname, typ, _) ->
@ -302,24 +298,6 @@ struct
let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in
{ empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes } { empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes }
let enum_constant_trans trans_state decl_ref =
let open CContext in
let context = trans_state.context in
let name_info, _ , type_ptr = get_info_from_decl_ref decl_ref in
let name = name_info.Clang_ast_t.ni_name in
let typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in
let const_exp = match CTypes.search_enum_type_by_name context.tenv name with
| Some v ->
let ce = Sil.Const v in
Printing.log_out " ....Found enum constant '%s', " name;
Printing.log_out "replacing with integer '%s' \n" (Sil.exp_to_string ce); ce
| None ->
Printing.log_out
"WARNING: Found enum constant '%s', but its value was not found in the tenv.\n"
name;
(Sil.Const(Sil.Cint Sil.Int.zero)) in
{ root_nodes = []; leaf_nodes = []; ids = []; instrs = []; exps = [(const_exp, typ)]}
let function_deref_trans trans_state decl_ref = let function_deref_trans trans_state decl_ref =
let open CContext in let open CContext in
let context = trans_state.context in let context = trans_state.context in
@ -413,7 +391,34 @@ struct
(* TODO for static methods we shouldn't return (obj_sil, class_typ) *) (* TODO for static methods we shouldn't return (obj_sil, class_typ) *)
{ pre_trans_result with exps = [method_exp; (obj_sil, class_typ)] } { pre_trans_result with exps = [method_exp; (obj_sil, class_typ)] }
let decl_ref_trans trans_state pre_trans_result stmt_info expr_info decl_ref = let cxxThisExpr_trans trans_state stmt_info expr_info =
let context = trans_state.context in
let pln = trans_state.parent_line_number in
let sil_loc = CLocation.get_sil_location stmt_info pln context in
let tp = expr_info.Clang_ast_t.ei_type_ptr in
let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in
let name = CFrontend_config.this in
let pvar = Sil.mk_pvar (Mangled.from_string name) procname in
let exp = Sil.Lvar pvar in
let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv tp in
let exps = [(exp, typ)] in
(* there is no cast operation in AST, but backend needs it *)
dereference_value_from_result sil_loc { empty_res_trans with exps = exps }
let rec labelStmt_trans trans_state stmt_info stmt_list label_name =
(* go ahead with the translation *)
let res_trans = match stmt_list with
| [stmt] ->
instruction trans_state stmt
| _ -> assert false (* expected a stmt or at most a compoundstmt *) in
(* create the label root node into the hashtbl *)
let sil_loc =
CLocation.get_sil_location stmt_info trans_state.parent_line_number trans_state.context in
let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in
Cfg.Node.set_succs_exn root_node' res_trans.root_nodes [];
{ empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes }
and decl_ref_trans trans_state pre_trans_result stmt_info expr_info decl_ref =
let open CContext in let open CContext in
Printing.log_out " priority node free = '%s'\n@." Printing.log_out " priority node free = '%s'\n@."
(string_of_bool (PriorityNode.is_priority_free trans_state)); (string_of_bool (PriorityNode.is_priority_free trans_state));
@ -432,7 +437,7 @@ struct
decl_ref.Clang_ast_t.dr_decl_pointer in decl_ref.Clang_ast_t.dr_decl_pointer in
print_error decl_kind; assert false print_error decl_kind; assert false
let declRefExpr_trans trans_state stmt_info expr_info decl_ref_expr_info e = and declRefExpr_trans trans_state stmt_info expr_info decl_ref_expr_info e =
let open CContext in let open CContext in
Printing.log_out " priority node free = '%s'\n@." Printing.log_out " priority node free = '%s'\n@."
(string_of_bool (PriorityNode.is_priority_free trans_state)); (string_of_bool (PriorityNode.is_priority_free trans_state));
@ -441,31 +446,42 @@ struct
| None -> assert false in | None -> assert false in
decl_ref_trans trans_state empty_res_trans stmt_info expr_info decl_ref decl_ref_trans trans_state empty_res_trans stmt_info expr_info decl_ref
let cxxThisExpr_trans trans_state stmt_info expr_info = (* evaluates an enum constant *)
let context = trans_state.context in and enum_const_eval context enum_constant_pointer prev_enum_constant_opt zero =
let pln = trans_state.parent_line_number in match Ast_utils.get_decl enum_constant_pointer with
let sil_loc = CLocation.get_sil_location stmt_info pln context in | Some Clang_ast_t.EnumConstantDecl (_, _, _, enum_constant_decl_info) ->
let tp = expr_info.Clang_ast_t.ei_type_ptr in (match enum_constant_decl_info.Clang_ast_t.ecdi_init_expr with
let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in | Some stmt ->
let name = CFrontend_config.this in expression_trans context stmt
let pvar = Sil.mk_pvar (Mangled.from_string name) procname in "WARNING: Expression in Enumeration constant not found\n"
let exp = Sil.Lvar pvar in | None ->
let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv tp in match prev_enum_constant_opt with
let exps = [(exp, typ)] in | Some prev_constant_pointer ->
(* there is no cast operation in AST, but backend needs it *) let previous_exp = get_enum_constant_expr context prev_constant_pointer in
dereference_value_from_result sil_loc { empty_res_trans with exps = exps } CArithmetic_trans.sil_const_plus_one previous_exp
| None -> zero)
| _ -> zero
(* get the sil value of the enum constant from the map or by evaluating it *)
and get_enum_constant_expr context enum_constant_pointer =
let zero = Sil.Const (Sil.Cint Sil.Int.zero) in
try
let (prev_enum_constant_opt, sil_exp_opt) =
Ast_utils.get_enum_constant_exp enum_constant_pointer in
match sil_exp_opt with
| Some exp -> exp
| None ->
let exp = enum_const_eval context enum_constant_pointer prev_enum_constant_opt zero in
Ast_utils.update_enum_map enum_constant_pointer exp;
exp
with Not_found -> zero
let rec labelStmt_trans trans_state stmt_info stmt_list label_name = and enum_constant_trans trans_state decl_ref =
(* go ahead with the translation *) let context = trans_state.context in
let res_trans = match stmt_list with let _, _, type_ptr = get_info_from_decl_ref decl_ref in
| [stmt] -> let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv type_ptr in
instruction trans_state stmt let const_exp = get_enum_constant_expr context decl_ref.Clang_ast_t.dr_decl_pointer in
| _ -> assert false (* expected a stmt or at most a compoundstmt *) in { empty_res_trans with exps = [(const_exp, typ)] }
(* create the label root node into the hashtbl *)
let sil_loc = CLocation.get_sil_location stmt_info trans_state.parent_line_number trans_state.context in
let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in
Cfg.Node.set_succs_exn root_node' res_trans.root_nodes [];
{ empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes }
and arraySubscriptExpr_trans trans_state stmt_info expr_info stmt_list = and arraySubscriptExpr_trans trans_state stmt_info expr_info stmt_list =
let typ = CTypes_decl.get_type_from_expr_info expr_info trans_state.context.CContext.tenv in let typ = CTypes_decl.get_type_from_expr_info expr_info trans_state.context.CContext.tenv in
@ -553,9 +569,9 @@ struct
let instrs_after_assign, assign_ids, exp_to_parent = let instrs_after_assign, assign_ids, exp_to_parent =
if (is_binary_assign_op binary_operator_info) if (is_binary_assign_op binary_operator_info)
(* assignment operator result is lvalue in CPP, rvalue in C, hence the difference *) (* assignment operator result is lvalue in CPP, rvalue in C, hence the difference *)
&& (not (General_utils.is_cpp_translation !CFrontend_config.language)) && (not (General_utils.is_cpp_translation !CFrontend_config.language))
&& ((not creating_node) || (is_return_temp trans_state.continuation)) then ( && ((not creating_node) || (is_return_temp trans_state.continuation)) then (
(* We are in this case when an assignment is inside *) (* We are in this case when an assignment is inside *)
(* another operator that creates a node. Eg. another *) (* another operator that creates a node. Eg. another *)
(* assignment. *) (* assignment. *)
@ -613,7 +629,7 @@ struct
Printing.log_out " |nodes_e2|=%s .\n" Printing.log_out " |nodes_e2|=%s .\n"
(string_of_int (IList.length res_trans_e2.root_nodes)); (string_of_int (IList.length res_trans_e2.root_nodes));
IList.iter (fun id -> Printing.log_out " ... '%s'\n" IList.iter (fun id -> Printing.log_out " ... '%s'\n"
(Ident.to_string id)) ids_to_ancestor; (Ident.to_string id)) ids_to_ancestor;
{ root_nodes = root_nodes_to_ancestor; { root_nodes = root_nodes_to_ancestor;
leaf_nodes = leaf_nodes_to_ancestor; leaf_nodes = leaf_nodes_to_ancestor;
ids = ids_to_ancestor; ids = ids_to_ancestor;
@ -2157,7 +2173,7 @@ struct
and instructions trans_state stmt_list = and instructions trans_state stmt_list =
exec_trans_instrs trans_state (get_clang_stmt_trans stmt_list) exec_trans_instrs trans_state (get_clang_stmt_trans stmt_list)
let expression_trans context stmt warning = and expression_trans context stmt warning =
let trans_state = { context = context; succ_nodes =[]; continuation = None; parent_line_number = -1; priority = Free } in let trans_state = { context = context; succ_nodes =[]; continuation = None; parent_line_number = -1; priority = Free } in
let res_trans_stmt = instruction trans_state stmt in let res_trans_stmt = instruction trans_state stmt in
fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning) fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning)

@ -16,10 +16,6 @@ module type CTrans = sig
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list -> val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list ->
Cfg.Node.t -> Cfg.Node.t list Cfg.Node.t -> Cfg.Node.t list
(** It receives the context and a statement and a warning string and returns the translated sil expression *)
(** that represents the translation of the stmts into sil. *)
val expression_trans : CContext.t -> Clang_ast_t.stmt -> string -> Sil.exp
end end

@ -136,17 +136,16 @@ and decl_ptr_to_sil_type translate_decl tenv decl_ptr =
| Some (ObjCImplementationDecl _ as d) | Some (ObjCImplementationDecl _ as d)
| Some (ObjCProtocolDecl _ as d) | Some (ObjCProtocolDecl _ as d)
| Some (ObjCCategoryDecl _ as d) | Some (ObjCCategoryDecl _ as d)
| Some (ObjCCategoryImplDecl _ as d) -> translate_decl tenv None d | Some (ObjCCategoryImplDecl _ as d)
| Some (EnumDecl(_, name_info, _, _, _, _, _) ) -> | Some (EnumDecl _ as d) -> translate_decl tenv None d
Sil.Tvar (CTypes.mk_enumname name_info.Clang_ast_t.ni_name) | Some _ ->
| Some _ -> Printing.log_err "Warning: Wrong decl found for pointer %s "
Printing.log_err "Warning: Wrong decl found for pointer %s " (Clang_ast_j.string_of_pointer decl_ptr);
(Clang_ast_j.string_of_pointer decl_ptr); Sil.Tvoid
Sil.Tvoid | None ->
| None -> Printing.log_err "Warning: Decl pointer %s not found."
Printing.log_err "Warning: Decl pointer %s not found." (Clang_ast_j.string_of_pointer decl_ptr);
(Clang_ast_j.string_of_pointer decl_ptr); Sil.Tvoid
Sil.Tvoid
and clang_type_ptr_to_sil_type translate_decl tenv type_ptr = and clang_type_ptr_to_sil_type translate_decl tenv type_ptr =
try try

@ -202,6 +202,7 @@ and add_types_from_decl_to_tenv tenv namespace decl =
| ObjCProtocolDecl _ -> ObjcProtocol_decl.protocol_decl type_ptr_to_sil_type tenv decl | ObjCProtocolDecl _ -> ObjcProtocol_decl.protocol_decl type_ptr_to_sil_type tenv decl
| ObjCCategoryDecl _ -> ObjcCategory_decl.category_decl type_ptr_to_sil_type tenv decl | ObjCCategoryDecl _ -> ObjcCategory_decl.category_decl type_ptr_to_sil_type tenv decl
| ObjCCategoryImplDecl _ -> ObjcCategory_decl.category_impl_decl type_ptr_to_sil_type tenv decl | ObjCCategoryImplDecl _ -> ObjcCategory_decl.category_impl_decl type_ptr_to_sil_type tenv decl
| EnumDecl _ -> CEnum_decl.enum_decl decl
| _ -> assert false | _ -> assert false
and type_ptr_to_sil_type tenv tp = and type_ptr_to_sil_type tenv tp =

@ -7,14 +7,14 @@
* 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.
*/ */
enum week{ sunday, monday, tuesday, wednesday=0, thursday, friday, saturday}; enum week{ sunday, monday, tuesday, wednesday = 0, thursday, friday, saturday};
int main(){ int main(){
enum week today; enum week today;
today=wednesday; today = wednesday;
today=monday; today = monday;
today=today+4; today = today + 4;
today=(enum week) tuesday+1; today = (enum week) tuesday + 1;
int i = tuesday+(friday-sunday); int i = tuesday + (friday - sunday);
return 0; return 0;
} }

@ -1,21 +1,21 @@
digraph iCFG { digraph iCFG {
8 [label="8: BinaryOperatorStmt: Assign \n *&today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) }=0 [line 14]\n NULLIFY(&today,false); [line 14]\n " shape="box"] 8 [label="8: BinaryOperatorStmt: Assign \n *&today:int =0 [line 14]\n NULLIFY(&today,false); [line 14]\n " shape="box"]
8 -> 7 ; 8 -> 7 ;
7 [label="7: BinaryOperatorStmt: Assign \n *&today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) }=1 [line 15]\n " shape="box"] 7 [label="7: BinaryOperatorStmt: Assign \n *&today:int =1 [line 15]\n " shape="box"]
7 -> 6 ; 7 -> 6 ;
6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) } [line 16]\n *&today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) }=(n$0 + 4) [line 16]\n REMOVE_TEMPS(n$0); [line 16]\n NULLIFY(&today,false); [line 16]\n " shape="box"] 6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&today:int [line 16]\n *&today:int =(n$0 + 4) [line 16]\n REMOVE_TEMPS(n$0); [line 16]\n NULLIFY(&today,false); [line 16]\n " shape="box"]
6 -> 5 ; 6 -> 5 ;
5 [label="5: BinaryOperatorStmt: Assign \n *&today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) }=(2 + 1) [line 17]\n NULLIFY(&today,false); [line 17]\n " shape="box"] 5 [label="5: BinaryOperatorStmt: Assign \n *&today:int =(2 + 1) [line 17]\n NULLIFY(&today,false); [line 17]\n " shape="box"]
5 -> 4 ; 5 -> 4 ;
4 [label="4: DeclStmt \n *&i:int =(2 + (4 - 0)) [line 18]\n NULLIFY(&i,false); [line 18]\n " shape="box"] 4 [label="4: DeclStmt \n *&i:int =(2 + (2 - 0)) [line 18]\n NULLIFY(&i,false); [line 18]\n " shape="box"]
4 -> 3 ; 4 -> 3 ;
@ -26,7 +26,7 @@ digraph iCFG {
2 [label="2: Exit main \n " color=yellow style=filled] 2 [label="2: Exit main \n " color=yellow style=filled]
1 [label="1: Start main\nFormals: \nLocals: i:int today:enum { (sunday, 0) (monday, 1) (tuesday, 2) (wednesday, 0) (thursday, 3) (friday, 4) (saturday, 5) } \n DECLARE_LOCALS(&return,&i,&today); [line 12]\n NULLIFY(&i,false); [line 12]\n NULLIFY(&today,false); [line 12]\n " color=yellow style=filled] 1 [label="1: Start main\nFormals: \nLocals: i:int today:int \n DECLARE_LOCALS(&return,&i,&today); [line 12]\n NULLIFY(&i,false); [line 12]\n NULLIFY(&today,false); [line 12]\n " color=yellow style=filled]
1 -> 8 ; 1 -> 8 ;

@ -0,0 +1,18 @@
/*
* Copyright (c) 2015 - 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.
*/
typedef enum MyOption {
MyOption1 = 1 << 0,
MyOption2 = 1 << 1,
};
int main() {
MyOption option1 = MyOption1;
MyOption option2 = MyOption2;
}

@ -0,0 +1,17 @@
digraph iCFG {
4 [label="4: DeclStmt \n *&option1:int =(1 << 0) [line 16]\n NULLIFY(&option1,false); [line 16]\n " shape="box"]
4 -> 3 ;
3 [label="3: DeclStmt \n *&option2:int =(1 << 1) [line 17]\n NULLIFY(&option2,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit main \n " color=yellow style=filled]
1 [label="1: Start main\nFormals: \nLocals: option2:int option1:int \n DECLARE_LOCALS(&return,&option2,&option1); [line 15]\n NULLIFY(&option1,false); [line 15]\n NULLIFY(&option2,false); [line 15]\n " color=yellow style=filled]
1 -> 4 ;
}

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015 - 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.
*/
enum Foo { A, B, C = 10, D, E = 1, F, G = F + C };
int main() {
enum Foo foo_a = A;
enum Foo foo_b = B;
enum Foo foo_c = C;
enum Foo foo_d = D;
enum Foo foo_e = E;
enum Foo foo_f = F;
enum Foo foo_g = G;
}
int test() {
enum Foo foo_g = G;
enum Foo foo_a = A;
if (foo_g == 12)
return foo_g/ foo_a;
else return 0;
}

@ -0,0 +1,77 @@
digraph iCFG {
19 [label="19: DeclStmt \n *&foo_g:int =(2 + 10) [line 23]\n " shape="box"]
19 -> 18 ;
18 [label="18: DeclStmt \n *&foo_a:int =0 [line 24]\n " shape="box"]
18 -> 13 ;
17 [label="17: Return Stmt \n NULLIFY(&foo_a,false); [line 27]\n NULLIFY(&foo_g,false); [line 27]\n *&return:int =0 [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"]
17 -> 11 ;
16 [label="16: Return Stmt \n n$1=*&foo_g:int [line 26]\n n$2=*&foo_a:int [line 26]\n *&return:int =(n$1 / n$2) [line 26]\n REMOVE_TEMPS(n$1,n$2); [line 26]\n NULLIFY(&foo_a,false); [line 26]\n NULLIFY(&foo_g,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"]
16 -> 11 ;
15 [label="15: Prune (false branch) \n PRUNE(((n$0 == 12) == 0), false); [line 25]\n REMOVE_TEMPS(n$0); [line 25]\n " shape="invhouse"]
15 -> 17 ;
14 [label="14: Prune (true branch) \n PRUNE(((n$0 == 12) != 0), true); [line 25]\n REMOVE_TEMPS(n$0); [line 25]\n " shape="invhouse"]
14 -> 16 ;
13 [label="13: BinaryOperatorStmt: EQ \n n$0=*&foo_g:int [line 25]\n " shape="box"]
13 -> 14 ;
13 -> 15 ;
12 [label="12: + \n NULLIFY(&foo_a,false); [line 25]\n NULLIFY(&foo_g,false); [line 25]\n " ]
12 -> 11 ;
11 [label="11: Exit test \n " color=yellow style=filled]
10 [label="10: Start test\nFormals: \nLocals: foo_a:int foo_g:int \n DECLARE_LOCALS(&return,&foo_a,&foo_g); [line 22]\n NULLIFY(&foo_a,false); [line 22]\n NULLIFY(&foo_g,false); [line 22]\n " color=yellow style=filled]
10 -> 19 ;
9 [label="9: DeclStmt \n *&foo_a:int =0 [line 13]\n NULLIFY(&foo_a,false); [line 13]\n " shape="box"]
9 -> 8 ;
8 [label="8: DeclStmt \n *&foo_b:int =1 [line 14]\n NULLIFY(&foo_b,false); [line 14]\n " shape="box"]
8 -> 7 ;
7 [label="7: DeclStmt \n *&foo_c:int =10 [line 15]\n NULLIFY(&foo_c,false); [line 15]\n " shape="box"]
7 -> 6 ;
6 [label="6: DeclStmt \n *&foo_d:int =11 [line 16]\n NULLIFY(&foo_d,false); [line 16]\n " shape="box"]
6 -> 5 ;
5 [label="5: DeclStmt \n *&foo_e:int =1 [line 17]\n NULLIFY(&foo_e,false); [line 17]\n " shape="box"]
5 -> 4 ;
4 [label="4: DeclStmt \n *&foo_f:int =2 [line 18]\n NULLIFY(&foo_f,false); [line 18]\n " shape="box"]
4 -> 3 ;
3 [label="3: DeclStmt \n *&foo_g:int =(2 + 10) [line 19]\n NULLIFY(&foo_g,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit main \n " color=yellow style=filled]
1 [label="1: Start main\nFormals: \nLocals: foo_g:int foo_f:int foo_e:int foo_d:int foo_c:int foo_b:int foo_a:int \n DECLARE_LOCALS(&return,&foo_g,&foo_f,&foo_e,&foo_d,&foo_c,&foo_b,&foo_a); [line 12]\n NULLIFY(&foo_a,false); [line 12]\n NULLIFY(&foo_b,false); [line 12]\n NULLIFY(&foo_c,false); [line 12]\n NULLIFY(&foo_d,false); [line 12]\n NULLIFY(&foo_e,false); [line 12]\n NULLIFY(&foo_f,false); [line 12]\n NULLIFY(&foo_g,false); [line 12]\n " color=yellow style=filled]
1 -> 9 ;
}

@ -0,0 +1,62 @@
/*
* 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.
*/
package endtoend.c;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferResults;
import utils.InferRunner;
public class EnumTest {
public static final String SOURCE_FILE =
"infer/tests/codetoanalyze/c/frontend/enumeration/other_enum.c";
public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";
private static ImmutableList<String> inferCmd;
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCInferCommand(folder, SOURCE_FILE);
}
@Test
public void whenInferRunsOnDivideByZeroThenDivideByZeroIsFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferC(inferCmd);
String[] procedures = {"test"};
assertThat(
"Results should contain divide by zero error",
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
SOURCE_FILE,
procedures
)
);
}
}

@ -31,4 +31,18 @@ public class EnumerationTest {
ClangFrontendUtils.createAndCompareCDotFiles(folder, src); ClangFrontendUtils.createAndCompareCDotFiles(folder, src);
} }
@Test
public void whenCaptureRunOnOtherEnumThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String src = "infer/tests/codetoanalyze/c/frontend/enumeration/other_enum.c";
ClangFrontendUtils.createAndCompareCDotFiles(folder, src);
}
@Test
public void whenCaptureRunOnEnumBitmaskThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String src = "infer/tests/codetoanalyze/c/frontend/enumeration/enum_bitmask.c";
ClangFrontendUtils.createAndCompareCDotFiles(folder, src);
}
} }

Loading…
Cancel
Save