[frontend][clang][RFC] fix translation of enum constant

Summary:
Previous translation of enum constants were wrong since they assumed that the enum constant didn't include any global variable (hence they just looked up the enum exp from the map, forgetting to tie the respective instructions into the cfg).

```
const int gvar = 0;

enum {
  evar = gvar,

};

 int dangling() {
  return evar;
}
```

as a result, the CFG was missing the instruction for the load of the `gvar`.

{F237004587}

This diff fixes this issue by hooking up the instructions that load the enum constant in to the CFG. Note that in this example, it is only a load instruction but there could be more instructions (e.g. if we had `gvar > 1`, we would have prune +join).

{F237004493}

Reviewed By: ezgicicek

Differential Revision: D21549781

fbshipit-source-id: 525534fb2
master
Sungkeun Cho 5 years ago committed by Facebook GitHub Bot
parent e0da0b00c3
commit 4e64657d50

@ -867,47 +867,47 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
decl_ref_trans ~context:DeclRefExpr trans_state stmt_info decl_ref decl_ref_trans ~context:DeclRefExpr trans_state stmt_info decl_ref
(** evaluates an enum constant *) and enum_constant_trans trans_state decl_ref =
and enum_const_eval context enum_constant_pointer prev_enum_constant_opt zero = let typ =
match CAst_utils.get_decl enum_constant_pointer with let {CContext.tenv} = trans_state.context in
let _, _, qual_type = CAst_utils.get_info_from_decl_ref decl_ref in
CType_decl.qual_type_to_sil_type tenv qual_type
in
let zero () = mk_trans_result (Exp.Const (Const.Cint IntLit.zero), typ) empty_control in
(* translate enum declaration statements *)
let rec trans_enum_decl ~prev_decl_pointer_opt decl_pointer =
match CAst_utils.get_decl decl_pointer with
| Some (Clang_ast_t.EnumConstantDecl (_, _, _, enum_constant_decl_info)) -> ( | Some (Clang_ast_t.EnumConstantDecl (_, _, _, enum_constant_decl_info)) -> (
match enum_constant_decl_info.Clang_ast_t.ecdi_init_expr with match enum_constant_decl_info.Clang_ast_t.ecdi_init_expr with
| Some stmt -> | Some stmt ->
expression_trans context stmt instruction trans_state stmt
| None -> ( | None -> (
match prev_enum_constant_opt with match prev_decl_pointer_opt with
| Some prev_constant_pointer -> | Some prev_decl_pointer ->
let previous_exp = get_enum_constant_expr context prev_constant_pointer in let ({return= exp, typ} as trans_result) = trans_with_cache prev_decl_pointer in
CArithmetic_trans.sil_const_plus_one previous_exp {trans_result with return= (CArithmetic_trans.sil_const_plus_one exp, typ)}
| None -> | None ->
zero ) ) zero () ) )
| _ -> | _ ->
zero zero ()
(* try looking up from cache before calling [trans_enum_decl] *)
and trans_with_cache decl_pointer =
(** 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 = Exp.Const (Const.Cint IntLit.zero) in
try try
let prev_enum_constant_opt, sil_exp_opt = let prev_decl_pointer_opt, cached_exp = CAst_utils.get_enum_constant_exp_exn decl_pointer in
CAst_utils.get_enum_constant_exp_exn enum_constant_pointer match cached_exp with
in
match sil_exp_opt with
| Some exp -> | Some exp ->
exp mk_trans_result (exp, typ) empty_control
| None -> | None ->
let exp = enum_const_eval context enum_constant_pointer prev_enum_constant_opt zero in let trans_result = trans_enum_decl ~prev_decl_pointer_opt decl_pointer in
CAst_utils.update_enum_map_exn enum_constant_pointer exp ; ( match fst trans_result.return with
exp | Exp.Const _ as exp ->
with Not_found_s _ | Caml.Not_found -> zero CAst_utils.update_enum_map_exn decl_pointer exp
| _ ->
() ) ;
and enum_constant_trans trans_state decl_ref = trans_result
let context = trans_state.context in with Not_found_s _ | Caml.Not_found -> zero ()
let _, _, qual_type = CAst_utils.get_info_from_decl_ref decl_ref in in
let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in trans_with_cache decl_ref.Clang_ast_t.dr_decl_pointer
let const_exp = get_enum_constant_expr context decl_ref.Clang_ast_t.dr_decl_pointer in
mk_trans_result (const_exp, typ) empty_control
and arraySubscriptExpr_trans trans_state expr_info stmt_list = and arraySubscriptExpr_trans trans_state expr_info stmt_list =
@ -3898,12 +3898,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
exec_trans_instrs trans_state stmt_trans_fun exec_trans_instrs trans_state stmt_trans_fun
and expression_trans context stmt =
let trans_state = CTrans_utils.default_trans_state context in
let res_trans_stmt = instruction trans_state stmt in
fst res_trans_stmt.return
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 default_trans_state = CTrans_utils.default_trans_state context 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 trans_state = {default_trans_state with succ_nodes= [exit_node]} in

@ -22,7 +22,7 @@ void compare_global_const_enum_Bad() {
arr[10] = 1; arr[10] = 1;
} }
void compare_global_const_enum_Good_FP() { void compare_global_const_enum_Good() {
char arr[10]; char arr[10];
if (global_const > 10) if (global_const > 10)
arr[10] = 1; arr[10] = 1;

@ -127,8 +127,9 @@ codetoanalyze/c/bufferoverrun/get_field.c, call_get_v2_Bad, 8, BUFFER_OVERRUN_L5
codetoanalyze/c/bufferoverrun/get_field.c, call_get_v2_Good_FP, 8, BUFFER_OVERRUN_L5, no_bucket, ERROR, [<Offset trace>,Call,Assignment,<Length trace>,Array declaration,Array access: Offset: [-oo, +oo] Size: 10] codetoanalyze/c/bufferoverrun/get_field.c, call_get_v2_Good_FP, 8, BUFFER_OVERRUN_L5, no_bucket, ERROR, [<Offset trace>,Call,Assignment,<Length trace>,Array declaration,Array access: Offset: [-oo, +oo] Size: 10]
codetoanalyze/c/bufferoverrun/get_field.c, call_get_v_Bad, 8, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Assignment,Call,Parameter `l->next->prev->v`,Assignment,<Length trace>,Array declaration,Array access: Offset: 10 Size: 10] codetoanalyze/c/bufferoverrun/get_field.c, call_get_v_Bad, 8, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Assignment,Call,Parameter `l->next->prev->v`,Assignment,<Length trace>,Array declaration,Array access: Offset: 10 Size: 10]
codetoanalyze/c/bufferoverrun/get_field.c, make_many_locations, 1, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here] codetoanalyze/c/bufferoverrun/get_field.c, make_many_locations, 1, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/c/bufferoverrun/global.c, compare_global_const_enum_Bad, 2, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/c/bufferoverrun/global.c, compare_global_const_enum_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10] codetoanalyze/c/bufferoverrun/global.c, compare_global_const_enum_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10]
codetoanalyze/c/bufferoverrun/global.c, compare_global_const_enum_Good_FP, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10] codetoanalyze/c/bufferoverrun/global.c, compare_global_const_enum_Good, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/c/bufferoverrun/global.c, compare_global_variable_bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10] codetoanalyze/c/bufferoverrun/global.c, compare_global_variable_bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10]
codetoanalyze/c/bufferoverrun/global.c, copyfilter_Good_FP, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: ([0, +oo] + 1):signed32] codetoanalyze/c/bufferoverrun/global.c, copyfilter_Good_FP, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/c/bufferoverrun/global.c, use_global_const_ten_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Assignment,<Length trace>,Array declaration,Array access: Offset: 10 Size: 5] codetoanalyze/c/bufferoverrun/global.c, use_global_const_ten_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Assignment,<Length trace>,Array declaration,Array access: Offset: 10 Size: 5]

Loading…
Cancel
Save