From 7b75ee7f5a3fb686c64f61796b4666f8192f95f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezgi=20=C3=87i=C3=A7ek?= Date: Wed, 20 May 2020 06:34:14 -0700 Subject: [PATCH] [objc][blocks] Load block instruction Summary: ## Problem In method specialization, we don't translate the loads of specialized blocks (e.g. `n$0 = block:_fn_`) and only add them to the id map. Later on, when the block is called with arguments (`n$0(arg1,..argn))` we lookup the id and use the substitution for the block. However, this means, if the program uses the id loading the block (n$0) anywhere else in the program, we have no declaration for it. ## When does this happen? For blocks that return a nullable result, objC programs usually do a null check as in the following example: ``` typedef id _Nullable (^BlockType)(id object); + (void)useBlock:(int) x myBlock:(BlockType)myBlock{ if (myBlock){ myBlock(x); } } + (void)callUseBlock{ [X useBlock 1 myBlock:^id(id object) { return nil; }]; } ``` Here, method specialization currently ignores the loads of this block (`n$0=*&myBlock:_fn_(*)`) which results in having variables in prune nodes that are not defined anywhere in the CFG (like `n$0`). This confuses control variable analysis when the conditional is wrapped in a loop because it cannot lookup where `n$0` is coming from. ## Fix This diff fixes the issue by translating the loading of the blocks. Reviewed By: dulmarod Differential Revision: D21642924 fbshipit-source-id: 2bc0442ff --- infer/src/IR/SpecializeProcdesc.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/infer/src/IR/SpecializeProcdesc.ml b/infer/src/IR/SpecializeProcdesc.ml index f2752ba24..7d6ca7304 100644 --- a/infer/src/IR/SpecializeProcdesc.ml +++ b/infer/src/IR/SpecializeProcdesc.ml @@ -225,11 +225,10 @@ let with_block_args_instrs resolved_pdesc substitutions = (call_instr :: instrs, id_map) in match instr with - | Sil.Load {id; e= Exp.Lvar block_param} + | Sil.Load {id; e= Exp.Lvar block_param as origin_exp; root_typ; typ; loc} when Mangled.Map.mem (Pvar.get_name block_param) substitutions -> let id_map = Ident.Map.add id (Pvar.get_name block_param) id_map in - (* we don't need the load the block param instruction anymore *) - (instrs, id_map) + (Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map) | Sil.Load {id; e= origin_exp; root_typ; typ; loc} -> (Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map) | Sil.Store {e1= assignee_exp; root_typ= origin_typ; e2= Exp.Var id; loc}