[objc frontend] Raise SelfClassException only inside ObjCMethodCallExpr nodes

Reviewed By: jvillard

Differential Revision: D7816329

fbshipit-source-id: 3b46ef5
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent d718275402
commit 038c0b92d4

@ -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 ClangLogging.log_caught_exception trans_unit_ctx "IncorrectAssumption" e.position
e.source_range e.ast_node ; e.source_range e.ast_node ;
log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" e.msg 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 -> | exn ->
let trace = Backtrace.get () in let trace = Backtrace.get () in
IExn.reraise_if exn ~f:(fun () -> IExn.reraise_if exn ~f:(fun () ->

@ -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 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 expressions, but we take the type and create a static method call from it. This is done in
objcMessageExpr_trans. *) objcMessageExpr_trans. *)
let exec_with_self_exception f trans_state stmt = let sizeof_expr_class class_name =
try f trans_state stmt with Self.SelfClassException e -> let typ = Typ.mk (Tstruct class_name) in
let typ = Typ.mk (Tstruct e.class_name) in ( Exp.Sizeof {typ; nbytes= None; dynamic_length= None; subtype= Subtype.exact}
{ empty_res_trans with , Typ.mk (Tint IULong) )
exps=
[ ( 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 = 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) ; CContext.add_block_static_var context procname (pvar, typ) ;
let var_exp = Exp.Lvar pvar in let var_exp = Exp.Lvar pvar in
let exps = 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 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 raise
(Self.SelfClassException (Self.SelfClassException
{class_name; position= __POS__; source_range= stmt_info.Clang_ast_t.si_source_range}) {class_name; position= __POS__; source_range= stmt_info.Clang_ast_t.si_source_range})
else else
let typ = CType.add_pointer_to_typ (Typ.mk (Tstruct class_name)) in let exp_typ = sizeof_expr_class class_name in
[(var_exp, typ)] [exp_typ]
else [(var_exp, typ)] else [(var_exp, typ)]
in in
L.(debug Capture Verbose) "@\n@\n PVAR ='%s'@\n@\n" (Pvar.to_string pvar) ; 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 *) (* NOTE: we create a node only if required. In that case this node *)
(* becomes the successor of the nodes that may be created when *) (* becomes the successor of the nodes that may be created when *)
(* translating the operands. *) (* 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 = let (var_exp, var_exp_typ) as e1_with_typ =
extract_exp_from_list res_trans_e1.exps extract_exp_from_list res_trans_e1.exps
"@\nWARNING: Missing LHS operand in BinOp. Returning -1. Fix needed...@\n" "@\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 trans_state'' = {trans_state' with var_exp_typ= Some e1_with_typ} in
let res_trans_e2 = let res_trans_e2 =
(* translation of s2 is done taking care of block special case *) (* translation of s2 is done taking care of block special case *)
exec_with_block_priority_exception exec_with_block_priority_exception instruction trans_state'' s2 stmt_info
(exec_with_self_exception instruction)
trans_state'' s2 stmt_info
in in
let e2_with_typ = let e2_with_typ =
extract_exp_from_list res_trans_e2.exps 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 *) (* afterwards. The 'instructions' function does not do that *)
let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in
let result_trans_subexprs = 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 let res_trans_p = List.map ~f:(instruction' trans_state_param) params_stmt in
res_trans_callee :: res_trans_p res_trans_callee :: res_trans_p
in 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 *) parameter and collect the results afterwards. The 'instructions' function does not do that *)
let result_trans_subexprs = let result_trans_subexprs =
let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in 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 let res_trans_p = List.map ~f:(instruction' trans_state_param) params_stmt in
result_trans_callee :: res_trans_p result_trans_callee :: res_trans_p
in 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 CMethod_trans.get_class_name_method_call_from_receiver_kind context obj_c_message_expr_info
act_params act_params
in in
(* alloc or new *) if trans_state.is_fst_arg_objc_method_call then
(* FIXME(t21762295): we do not expect this to propagate to the top but it does *) raise
raise (Self.SelfClassException
(Self.SelfClassException {class_name; position= __POS__; source_range= si.Clang_ast_t.si_source_range})
{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 else if
(* alloc or new *)
String.equal selector CFrontend_config.alloc String.equal selector CFrontend_config.alloc
|| String.equal selector CFrontend_config.new_str || String.equal selector CFrontend_config.new_str
then then
@ -1232,7 +1230,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
| stmt :: rest -> | stmt :: rest ->
let obj_c_message_expr_info, fst_res_trans = let obj_c_message_expr_info, fst_res_trans =
try 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) (obj_c_message_expr_info, fst_res_trans)
with Self.SelfClassException e -> with Self.SelfClassException e ->
let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in 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 in
(obj_c_message_expr_info, empty_res_trans) (obj_c_message_expr_info, empty_res_trans)
in 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 let l = List.map ~f:(instruction' trans_state_param) rest in
(obj_c_message_expr_info, fst_res_trans :: l) (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' = let trans_state' =
{trans_state_pri with succ_nodes= []; var_exp_typ= Some var_exp_typ} {trans_state_pri with succ_nodes= []; var_exp_typ= Some var_exp_typ}
in in
let instruction' = let instruction' = exec_with_glvalue_as_reference instruction in
exec_with_self_exception (exec_with_glvalue_as_reference instruction)
in
exec_with_block_priority_exception instruction' trans_state' ie var_stmt_info exec_with_block_priority_exception instruction' trans_state' ie var_stmt_info
in in
let sil_e1', ie_typ = let sil_e1', ie_typ =
@ -2496,7 +2493,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let trans_state' = let trans_state' =
{trans_state_pri with succ_nodes= []; var_exp_typ= Some (ret_exp, ret_typ)} {trans_state_pri with succ_nodes= []; var_exp_typ= Some (ret_exp, ret_typ)}
in 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, _ = let sil_expr, _ =
extract_exp_from_list res_trans_stmt.exps extract_exp_from_list res_trans_stmt.exps
"WARNING: There should be only one return expression.@\n" "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 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_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in
let trans_state_param = {trans_state_pri with succ_nodes= []} 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 = let exp =
extract_exp_from_list result_trans_param.exps extract_exp_from_list result_trans_param.exps
"WARNING: There should be one expression to delete. @\n" "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 = and expression_trans context stmt warning =
let trans_state = let trans_state = CTrans_utils.default_trans_state context in
{ context
; succ_nodes= []
; continuation= None
; priority= Free
; var_exp_typ= None
; opaque_exp= None }
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)
let instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper = let instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper =
let trans_state = let default_trans_state = CTrans_utils.default_trans_state context in
{ context let trans_state = {default_trans_state with succ_nodes= [exit_node]} in
; succ_nodes= [exit_node]
; continuation= None
; priority= Free
; var_exp_typ= None
; opaque_exp= None }
in
let procname = Procdesc.get_proc_name context.CContext.procdesc in let procname = Procdesc.get_proc_name context.CContext.procdesc in
let is_destructor = let is_destructor =
match procname with match procname with

@ -137,7 +137,8 @@ type trans_state =
; continuation: continuation option (** current continuation *) ; continuation: continuation option (** current continuation *)
; priority: priority_node ; priority: priority_node
; var_exp_typ: (Exp.t * Typ.t) option ; 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. *) (** A translation result. It is returned by the translation function. *)
type trans_result = type trans_result =
@ -153,6 +154,16 @@ let empty_res_trans =
{root_nodes= []; leaf_nodes= []; instrs= []; exps= []; initd_exps= []; is_cpp_call_virtual= false} {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) 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. *) (** Collect the results of translating a list of instructions, and link up the nodes created. *)

@ -27,7 +27,8 @@ type trans_state =
; continuation: continuation option (** current continuation *) ; continuation: continuation option (** current continuation *)
; priority: priority_node ; priority: priority_node
; var_exp_typ: (Exp.t * Typ.t) option ; 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. *) (** A translation result. It is returned by the translation function. *)
type trans_result = type trans_result =
@ -41,6 +42,8 @@ type trans_result =
val empty_res_trans : trans_result val empty_res_trans : trans_result
val default_trans_state : CContext.t -> trans_state
val undefined_expression : unit -> Exp.t val undefined_expression : unit -> Exp.t
val collect_res_trans : Procdesc.t -> trans_result list -> trans_result val collect_res_trans : Procdesc.t -> trans_result list -> trans_result

@ -97,4 +97,14 @@
} else } else
return 0; return 0;
} }
Class foo();
BOOL class_method_in_conditional() {
Class c = foo();
if ([c class]) {
return YES;
}
return NO;
}
@end @end

@ -1,5 +1,37 @@
/* @generated */ /* @generated */
digraph cfg { 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] "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_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_6" ;
"used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_5" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" ; "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_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" ; "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_7" -> "used_in_binary_op:#A#class.9f855a338b344f4b5060d2d4a2a955ed_9" ;

Loading…
Cancel
Save