diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 81be5c356..503cdc6d4 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -33,12 +33,6 @@ let protect ~f ~recover ~pp_context (trans_unit_ctx: CFrontend_config.translatio ClangLogging.log_caught_exception trans_unit_ctx "IncorrectAssumption" e.position e.source_range e.ast_node ; log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" e.msg - | CTrans_utils.Self.SelfClassException e -> - (* FIXME(t21762295): we do not expect this to happen but it does *) - Some (Typ.Name.to_string e.class_name) - |> ClangLogging.log_caught_exception trans_unit_ctx "SelfClassException" e.position - e.source_range ; - log_and_recover ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp e.class_name | exn -> let trace = Backtrace.get () in IExn.reraise_if exn ~f:(fun () -> diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 65e10e302..5554fd9df 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -136,13 +136,10 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s when they are the first argument of method calls. In that case they are not translated as expressions, but we take the type and create a static method call from it. This is done in objcMessageExpr_trans. *) - let exec_with_self_exception f trans_state stmt = - try f trans_state stmt with Self.SelfClassException e -> - let typ = Typ.mk (Tstruct e.class_name) in - { empty_res_trans with - exps= - [ ( Exp.Sizeof {typ; nbytes= None; dynamic_length= None; subtype= Subtype.exact} - , Typ.mk (Tint IULong) ) ] } + let sizeof_expr_class class_name = + let typ = Typ.mk (Tstruct class_name) in + ( Exp.Sizeof {typ; nbytes= None; dynamic_length= None; subtype= Subtype.exact} + , Typ.mk (Tint IULong) ) let add_reference_if_glvalue (typ: Typ.t) expr_info = @@ -756,15 +753,15 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s CContext.add_block_static_var context procname (pvar, typ) ; let var_exp = Exp.Lvar pvar in let exps = - if Self.is_var_self pvar (CContext.is_objc_method context) then + if Self.is_var_self pvar (CContext.is_objc_method context) && CType.is_class typ then let class_name = CContext.get_curr_class_typename stmt_info context in - if CType.is_class typ then + if trans_state.is_fst_arg_objc_method_call then raise (Self.SelfClassException {class_name; position= __POS__; source_range= stmt_info.Clang_ast_t.si_source_range}) else - let typ = CType.add_pointer_to_typ (Typ.mk (Tstruct class_name)) in - [(var_exp, typ)] + let exp_typ = sizeof_expr_class class_name in + [exp_typ] else [(var_exp, typ)] in L.(debug Capture Verbose) "@\n@\n PVAR ='%s'@\n@\n" (Pvar.to_string pvar) ; @@ -923,7 +920,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* NOTE: we create a node only if required. In that case this node *) (* becomes the successor of the nodes that may be created when *) (* translating the operands. *) - let res_trans_e1 = exec_with_self_exception instruction trans_state' s1 in + let res_trans_e1 = instruction trans_state' s1 in let (var_exp, var_exp_typ) as e1_with_typ = extract_exp_from_list res_trans_e1.exps "@\nWARNING: Missing LHS operand in BinOp. Returning -1. Fix needed...@\n" @@ -931,9 +928,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let trans_state'' = {trans_state' with var_exp_typ= Some e1_with_typ} in let res_trans_e2 = (* translation of s2 is done taking care of block special case *) - exec_with_block_priority_exception - (exec_with_self_exception instruction) - trans_state'' s2 stmt_info + exec_with_block_priority_exception instruction trans_state'' s2 stmt_info in let e2_with_typ = extract_exp_from_list res_trans_e2.exps @@ -1015,7 +1010,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* afterwards. The 'instructions' function does not do that *) let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in let result_trans_subexprs = - let instruction' = exec_with_self_exception (exec_with_glvalue_as_reference instruction) in + let instruction' = exec_with_glvalue_as_reference instruction in let res_trans_p = List.map ~f:(instruction' trans_state_param) params_stmt in res_trans_callee :: res_trans_p in @@ -1075,7 +1070,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s parameter and collect the results afterwards. The 'instructions' function does not do that *) let result_trans_subexprs = let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in - let instruction' = exec_with_self_exception (exec_with_glvalue_as_reference instruction) in + let instruction' = exec_with_glvalue_as_reference instruction in let res_trans_p = List.map ~f:(instruction' trans_state_param) params_stmt in result_trans_callee :: res_trans_p in @@ -1204,12 +1199,15 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s CMethod_trans.get_class_name_method_call_from_receiver_kind context obj_c_message_expr_info act_params in - (* alloc or new *) - (* FIXME(t21762295): we do not expect this to propagate to the top but it does *) - raise - (Self.SelfClassException - {class_name; position= __POS__; source_range= si.Clang_ast_t.si_source_range}) + if trans_state.is_fst_arg_objc_method_call then + raise + (Self.SelfClassException + {class_name; position= __POS__; source_range= si.Clang_ast_t.si_source_range}) + else + let exp, typ = sizeof_expr_class class_name in + Some {empty_res_trans with exps= [(exp, typ)]} else if + (* alloc or new *) String.equal selector CFrontend_config.alloc || String.equal selector CFrontend_config.new_str then @@ -1232,7 +1230,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | stmt :: rest -> let obj_c_message_expr_info, fst_res_trans = try - let fst_res_trans = instruction trans_state_param stmt in + let trans_state_param' = {trans_state_param with is_fst_arg_objc_method_call= true} in + let fst_res_trans = instruction trans_state_param' stmt in (obj_c_message_expr_info, fst_res_trans) with Self.SelfClassException e -> let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in @@ -1242,7 +1241,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s in (obj_c_message_expr_info, empty_res_trans) in - let instruction' = exec_with_self_exception (exec_with_glvalue_as_reference instruction) in + let instruction' = exec_with_glvalue_as_reference instruction in let l = List.map ~f:(instruction' trans_state_param) rest in (obj_c_message_expr_info, fst_res_trans :: l) | [] -> @@ -2208,9 +2207,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let trans_state' = {trans_state_pri with succ_nodes= []; var_exp_typ= Some var_exp_typ} in - let instruction' = - exec_with_self_exception (exec_with_glvalue_as_reference instruction) - in + let instruction' = exec_with_glvalue_as_reference instruction in exec_with_block_priority_exception instruction' trans_state' ie var_stmt_info in let sil_e1', ie_typ = @@ -2496,7 +2493,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let trans_state' = {trans_state_pri with succ_nodes= []; var_exp_typ= Some (ret_exp, ret_typ)} in - let res_trans_stmt = exec_with_self_exception instruction trans_state' stmt in + let res_trans_stmt = instruction trans_state' stmt in let sil_expr, _ = extract_exp_from_list res_trans_stmt.exps "WARNING: There should be only one return expression.@\n" @@ -2806,7 +2803,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let param = match stmt_list with [p] -> p | _ -> assert false in let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in let trans_state_param = {trans_state_pri with succ_nodes= []} in - let result_trans_param = exec_with_self_exception instruction trans_state_param param in + let result_trans_param = instruction trans_state_param param in let exp = extract_exp_from_list result_trans_param.exps "WARNING: There should be one expression to delete. @\n" @@ -3505,27 +3502,14 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s and expression_trans context stmt warning = - let trans_state = - { context - ; succ_nodes= [] - ; continuation= None - ; priority= Free - ; var_exp_typ= None - ; opaque_exp= None } - in + let trans_state = CTrans_utils.default_trans_state context in let res_trans_stmt = instruction trans_state stmt in fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning) let instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper = - let trans_state = - { context - ; succ_nodes= [exit_node] - ; continuation= None - ; priority= Free - ; var_exp_typ= None - ; opaque_exp= None } - in + let default_trans_state = CTrans_utils.default_trans_state context in + let trans_state = {default_trans_state with succ_nodes= [exit_node]} in let procname = Procdesc.get_proc_name context.CContext.procdesc in let is_destructor = match procname with diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 4a10a14e0..659b3fe78 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -137,7 +137,8 @@ type trans_state = ; continuation: continuation option (** current continuation *) ; priority: priority_node ; var_exp_typ: (Exp.t * Typ.t) option - ; opaque_exp: (Exp.t * Typ.t) option } + ; opaque_exp: (Exp.t * Typ.t) option + ; is_fst_arg_objc_method_call: bool } (** A translation result. It is returned by the translation function. *) type trans_result = @@ -153,6 +154,16 @@ let empty_res_trans = {root_nodes= []; leaf_nodes= []; instrs= []; exps= []; initd_exps= []; is_cpp_call_virtual= false} +let default_trans_state context = + { context + ; succ_nodes= [] + ; continuation= None + ; priority= Free + ; var_exp_typ= None + ; opaque_exp= None + ; is_fst_arg_objc_method_call= false } + + let undefined_expression () = Exp.Var (Ident.create_fresh Ident.knormal) (** Collect the results of translating a list of instructions, and link up the nodes created. *) diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index b49f8d3f4..977b82863 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -27,7 +27,8 @@ type trans_state = ; continuation: continuation option (** current continuation *) ; priority: priority_node ; var_exp_typ: (Exp.t * Typ.t) option - ; opaque_exp: (Exp.t * Typ.t) option } + ; opaque_exp: (Exp.t * Typ.t) option + ; is_fst_arg_objc_method_call: bool } (** A translation result. It is returned by the translation function. *) type trans_result = @@ -41,6 +42,8 @@ type trans_result = val empty_res_trans : trans_result +val default_trans_state : CContext.t -> trans_state + val undefined_expression : unit -> Exp.t val collect_res_trans : Procdesc.t -> trans_result list -> trans_result diff --git a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m index 9b13c1c49..7d3c695a0 100644 --- a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m +++ b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m @@ -97,4 +97,14 @@ } else return 0; } + +Class foo(); + +BOOL class_method_in_conditional() { + Class c = foo(); + if ([c class]) { + return YES; + } + return NO; +} @end diff --git a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot index 09194681b..02ba9120d 100644 --- a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot @@ -1,5 +1,37 @@ /* @generated */ digraph cfg { +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_1" [label="1: Start class_method_in_conditional\nFormals: \nLocals: c:objc_class* \n DECLARE_LOCALS(&return,&c); [line 103, column 1]\n " color=yellow style=filled] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_1" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_8" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_2" [label="2: Exit class_method_in_conditional \n " color=yellow style=filled] + + +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_3" [label="3: Return Stmt \n *&return:_Bool=0 [line 108, column 3]\n " shape="box"] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_3" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_2" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_4" [label="4: + \n " ] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_4" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_3" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_5" [label="5: Prune (true branch, if) \n PRUNE(sizeof(t=objc_class), true); [line 105, column 7]\n " shape="invhouse"] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_5" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_7" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_6" [label="6: Prune (false branch, if) \n PRUNE(!sizeof(t=objc_class), false); [line 105, column 7]\n " shape="invhouse"] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_6" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_4" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_7" [label="7: Return Stmt \n *&return:_Bool=1 [line 106, column 5]\n " shape="box"] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_7" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_2" ; +"class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_8" [label="8: DeclStmt \n n$1=_fun_foo() [line 104, column 13]\n *&c:objc_class*=n$1 [line 104, column 3]\n " shape="box"] + + + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_8" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_5" ; + "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_8" -> "class_method_in_conditional.2a19b0bd8eafdb3235f52585a49ef84a_6" ; "b_m#B#class.82af96ad418803b2f96fc1bfa1572c10_1" [label="1: Start B_b_m\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 20, column 1]\n " color=yellow style=filled] @@ -172,16 +204,16 @@ digraph cfg { "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_4" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_2" ; -"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_5" [label="5: BinaryOperatorStmt: NE \n n$15=*&c:objc_class* [line 95, column 15]\n " shape="box"] +"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_5" [label="5: BinaryOperatorStmt: NE \n n$15=*sizeof(t=A):objc_class* [line 95, column 7]\n n$16=*&c:objc_class* [line 95, column 15]\n " shape="box"] "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_5" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_6" ; "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_5" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" ; -"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_6" [label="6: Prune (true branch, if) \n PRUNE((sizeof(t=A) != n$15), true); [line 95, column 7]\n " shape="invhouse"] +"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_6" [label="6: Prune (true branch, if) \n PRUNE((n$15 != n$16), true); [line 95, column 7]\n " shape="invhouse"] "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_6" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_8" ; -"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" [label="7: Prune (false branch, if) \n PRUNE(!(sizeof(t=A) != n$15), false); [line 95, column 7]\n " shape="invhouse"] +"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" [label="7: Prune (false branch, if) \n PRUNE(!(n$15 != n$16), false); [line 95, column 7]\n " shape="invhouse"] "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_9" ;