[frontend] Parse binary operator using types of parameters

Summary: It parses "+" (and "-") to PlusA and PlusPI (and MinusA, MinusPI, MinusPP) using types of parameters.

Reviewed By: mbouaziz

Differential Revision: D7443048

fbshipit-source-id: bd560c7
master
Sungkeun Cho 7 years ago committed by Facebook Github Bot
parent f63a9c0836
commit 00e1139071

@ -385,9 +385,9 @@ module Report = struct
-> PO.ConditionSet.t -> PO.ConditionSet.t = -> PO.ConditionSet.t -> PO.ConditionSet.t =
fun pname ~bop ~e1 ~e2 location mem cond_set -> fun pname ~bop ~e1 ~e2 location mem cond_set ->
match bop with match bop with
| Binop.PlusA -> | Binop.PlusPI ->
check_binop_array_access pname ~is_plus:true ~e1 ~e2 location mem cond_set check_binop_array_access pname ~is_plus:true ~e1 ~e2 location mem cond_set
| Binop.MinusA -> | Binop.MinusPI ->
check_binop_array_access pname ~is_plus:false ~e1 ~e2 location mem cond_set check_binop_array_access pname ~is_plus:false ~e1 ~e2 location mem cond_set
| _ -> | _ ->
cond_set cond_set

@ -16,16 +16,18 @@ module L = Logging
(* CompoundAssignment. "binary_expression" is returned when we are calculating an expression*) (* CompoundAssignment. "binary_expression" is returned when we are calculating an expression*)
(* "instructions" is not empty when the binary operator is actually a statement like an *) (* "instructions" is not empty when the binary operator is actually a statement like an *)
(* assignment. *) (* assignment. *)
let compound_assignment_binary_operation_instruction boi_kind e1 typ e2 loc = let compound_assignment_binary_operation_instruction boi_kind (e1, t1) typ e2 loc =
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e1, typ, loc) in let instr1 = Sil.Load (id, e1, typ, loc) in
let e_res, instr_op = let e_res, instr_op =
match boi_kind with match boi_kind with
| `AddAssign -> | `AddAssign ->
let e1_plus_e2 = Exp.BinOp (Binop.PlusA, Exp.Var id, e2) in let bop = if Typ.is_pointer t1 then Binop.PlusPI else Binop.PlusA in
let e1_plus_e2 = Exp.BinOp (bop, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_plus_e2, loc)]) (e1, [Sil.Store (e1, typ, e1_plus_e2, loc)])
| `SubAssign -> | `SubAssign ->
let e1_sub_e2 = Exp.BinOp (Binop.MinusA, Exp.Var id, e2) in let bop = if Typ.is_pointer t1 then Binop.MinusPI else Binop.MinusA in
let e1_sub_e2 = Exp.BinOp (bop, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_sub_e2, loc)]) (e1, [Sil.Store (e1, typ, e1_sub_e2, loc)])
| `MulAssign -> | `MulAssign ->
let e1_mul_e2 = Exp.BinOp (Binop.Mult, Exp.Var id, e2) in let e1_mul_e2 = Exp.BinOp (Binop.Mult, Exp.Var id, e2) in
@ -58,8 +60,10 @@ let compound_assignment_binary_operation_instruction boi_kind e1 typ e2 loc =
(** Returns a pair ([binary_expression], instructions). "binary_expression" is returned when we are (** Returns a pair ([binary_expression], instructions). "binary_expression" is returned when we are
calculating an expression "instructions" is not empty when the binary operator is actually a calculating an expression "instructions" is not empty when the binary operator is actually a
statement like an assignment. *) statement like an assignment. *)
let binary_operation_instruction source_range boi e1 typ e2 loc = let binary_operation_instruction source_range boi ((e1, t1) as e1_with_typ) typ (e2, t2) loc =
let binop_exp op = Exp.BinOp (op, e1, e2) in let binop_exp ?(change_order= false) op =
if change_order then Exp.BinOp (op, e2, e1) else Exp.BinOp (op, e1, e2)
in
match boi.Clang_ast_t.boi_kind with match boi.Clang_ast_t.boi_kind with
(* Note: Pointers to members that are not statically known are not (* Note: Pointers to members that are not statically known are not
expressible in Sil. The translation of the PtrMem ops treats the field as expressible in Sil. The translation of the PtrMem ops treats the field as
@ -72,7 +76,9 @@ let binary_operation_instruction source_range boi e1 typ e2 loc =
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
(Exp.BinOp (PlusPI, Exp.Var id, e2), [Sil.Load (id, e1, typ, loc)]) (Exp.BinOp (PlusPI, Exp.Var id, e2), [Sil.Load (id, e1, typ, loc)])
| `Add -> | `Add ->
(binop_exp Binop.PlusA, []) if Typ.is_pointer t1 then (binop_exp Binop.PlusPI, [])
else if Typ.is_pointer t2 then (binop_exp ~change_order:true Binop.PlusPI, [])
else (binop_exp Binop.PlusA, [])
| `Mul -> | `Mul ->
(binop_exp Binop.Mult, []) (binop_exp Binop.Mult, [])
| `Div -> | `Div ->
@ -80,7 +86,9 @@ let binary_operation_instruction source_range boi e1 typ e2 loc =
| `Rem -> | `Rem ->
(binop_exp Binop.Mod, []) (binop_exp Binop.Mod, [])
| `Sub -> | `Sub ->
(binop_exp Binop.MinusA, []) if Typ.is_pointer t1 then
if Typ.is_pointer t2 then (binop_exp Binop.MinusPP, []) else (binop_exp Binop.MinusPI, [])
else (binop_exp Binop.MinusA, [])
| `Shl -> | `Shl ->
(binop_exp Binop.Shiftlt, []) (binop_exp Binop.Shiftlt, [])
| `Shr -> | `Shr ->
@ -124,7 +132,7 @@ let binary_operation_instruction source_range boi e1 typ e2 loc =
| `AndAssign | `AndAssign
| `XorAssign | `XorAssign
| `OrAssign ) as boi_kind -> | `OrAssign ) as boi_kind ->
compound_assignment_binary_operation_instruction boi_kind e1 typ e2 loc compound_assignment_binary_operation_instruction boi_kind e1_with_typ typ e2 loc
let unary_operation_instruction translation_unit_context uoi e typ loc = let unary_operation_instruction translation_unit_context uoi e typ loc =
@ -133,12 +141,14 @@ let unary_operation_instruction translation_unit_context uoi e typ loc =
| `PostInc -> | `PostInc ->
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in let instr1 = Sil.Load (id, e, typ, loc) in
let e_plus_1 = Exp.BinOp (Binop.PlusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in let bop = if Typ.is_pointer typ then Binop.PlusPI else Binop.PlusA in
let e_plus_1 = Exp.BinOp (bop, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
(Exp.Var id, [instr1; Sil.Store (e, typ, e_plus_1, loc)]) (Exp.Var id, [instr1; Sil.Store (e, typ, e_plus_1, loc)])
| `PreInc -> | `PreInc ->
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in let instr1 = Sil.Load (id, e, typ, loc) in
let e_plus_1 = Exp.BinOp (Binop.PlusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in let bop = if Typ.is_pointer typ then Binop.PlusPI else Binop.PlusA in
let e_plus_1 = Exp.BinOp (bop, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
let exp = let exp =
if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_plus_1 if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_plus_1
in in
@ -146,12 +156,14 @@ let unary_operation_instruction translation_unit_context uoi e typ loc =
| `PostDec -> | `PostDec ->
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in let instr1 = Sil.Load (id, e, typ, loc) in
let e_minus_1 = Exp.BinOp (Binop.MinusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in let bop = if Typ.is_pointer typ then Binop.MinusPI else Binop.MinusA in
let e_minus_1 = Exp.BinOp (bop, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
(Exp.Var id, [instr1; Sil.Store (e, typ, e_minus_1, loc)]) (Exp.Var id, [instr1; Sil.Store (e, typ, e_minus_1, loc)])
| `PreDec -> | `PreDec ->
let id = Ident.create_fresh Ident.knormal in let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in let instr1 = Sil.Load (id, e, typ, loc) in
let e_minus_1 = Exp.BinOp (Binop.MinusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in let bop = if Typ.is_pointer typ then Binop.MinusPI else Binop.MinusA in
let e_minus_1 = Exp.BinOp (bop, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
let exp = let exp =
if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_minus_1 if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_minus_1
in in

@ -14,8 +14,8 @@ open! IStd
val bin_op_to_string : Clang_ast_t.binary_operator_info -> string val bin_op_to_string : Clang_ast_t.binary_operator_info -> string
val binary_operation_instruction : val binary_operation_instruction :
Clang_ast_t.source_range -> Clang_ast_t.binary_operator_info -> Exp.t -> Typ.t -> Exp.t Clang_ast_t.source_range -> Clang_ast_t.binary_operator_info -> Exp.t * Typ.t -> Typ.t
-> Location.t -> Exp.t * Sil.instr list -> Exp.t * Typ.t -> Location.t -> Exp.t * Sil.instr list
(** Returns a pair ([binary_expression], instructions). "binary_expression" is returned when we are (** Returns a pair ([binary_expression], instructions). "binary_expression" is returned when we are
calculating an expression "instructions" is not empty when the binary operator is actually a calculating an expression "instructions" is not empty when the binary operator is actually a
statement like an assignment. *) statement like an assignment. *)

@ -930,18 +930,18 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(* 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 = exec_with_self_exception instruction trans_state' s1 in
let var_exp, var_exp_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"
in in
let trans_state'' = {trans_state' with var_exp_typ= Some (var_exp, var_exp_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
(exec_with_self_exception instruction) (exec_with_self_exception instruction)
trans_state'' s2 stmt_info trans_state'' s2 stmt_info
in in
let sil_e2, _ = let e2_with_typ =
extract_exp_from_list res_trans_e2.exps extract_exp_from_list res_trans_e2.exps
"@\nWARNING: Missing RHS operand in BinOp. Returning -1. Fix needed...@\n" "@\nWARNING: Missing RHS operand in BinOp. Returning -1. Fix needed...@\n"
in in
@ -950,7 +950,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
else else
let exp_op, instr_bin = let exp_op, instr_bin =
CArithmetic_trans.binary_operation_instruction stmt_info.Clang_ast_t.si_source_range CArithmetic_trans.binary_operation_instruction stmt_info.Clang_ast_t.si_source_range
binary_operator_info var_exp typ sil_e2 sil_loc binary_operator_info e1_with_typ typ e2_with_typ sil_loc
in in
(* Create a node if the priority if free and there are instructions *) (* Create a node if the priority if free and there are instructions *)
let creating_node = let creating_node =

@ -59,8 +59,9 @@ codetoanalyze/c/bufferoverrun/models.c, fgetc_256_bad, 3, BUFFER_OVERRUN_L2, ERR
codetoanalyze/c/bufferoverrun/models.c, fgetc_m1_bad, 3, BUFFER_OVERRUN_L3, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [-1, 255] Size: [10000, 10000]] codetoanalyze/c/bufferoverrun/models.c, fgetc_m1_bad, 3, BUFFER_OVERRUN_L3, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [-1, 255] Size: [10000, 10000]]
codetoanalyze/c/bufferoverrun/nested_loop.c, nested_loop, 7, BUFFER_OVERRUN_L2, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [0, 10] Size: [10, 10]] codetoanalyze/c/bufferoverrun/nested_loop.c, nested_loop, 7, BUFFER_OVERRUN_L2, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [0, 10] Size: [10, 10]]
codetoanalyze/c/bufferoverrun/nested_loop_with_label.c, nested_loop_with_label, 6, BUFFER_OVERRUN_L4, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [0, +oo] Size: [10, 10]] codetoanalyze/c/bufferoverrun/nested_loop_with_label.c, nested_loop_with_label, 6, BUFFER_OVERRUN_L4, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [0, +oo] Size: [10, 10]]
codetoanalyze/c/bufferoverrun/pointer_arith.c, FN_pointer_arith_bad, 3, CONDITION_ALWAYS_FALSE, WARNING, []
codetoanalyze/c/bufferoverrun/pointer_arith.c, FN_pointer_arith_bad, 3, CONDITION_ALWAYS_TRUE, WARNING, []
codetoanalyze/c/bufferoverrun/pointer_arith.c, array_pointer_arith_Bad, 3, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [10, 10] Size: [10, 10]] codetoanalyze/c/bufferoverrun/pointer_arith.c, array_pointer_arith_Bad, 3, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [10, 10] Size: [10, 10]]
codetoanalyze/c/bufferoverrun/pointer_arith.c, pointer_arith_bad, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [10, 10] Size: [10, 10]]
codetoanalyze/c/bufferoverrun/prune_alias.c, FP_call_prune_arrblk_eq_Ok, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,Call,Parameter: x,ArrayAccess: Offset: [15, 5] Size: [5, 5] @ codetoanalyze/c/bufferoverrun/prune_alias.c:135:5 by call to `prune_arrblk_eq()` ] codetoanalyze/c/bufferoverrun/prune_alias.c, FP_call_prune_arrblk_eq_Ok, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,Call,Parameter: x,ArrayAccess: Offset: [15, 5] Size: [5, 5] @ codetoanalyze/c/bufferoverrun/prune_alias.c:135:5 by call to `prune_arrblk_eq()` ]
codetoanalyze/c/bufferoverrun/prune_alias.c, FP_prune_alias_exp_Ok, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [1, 1] Size: [1, 1]] codetoanalyze/c/bufferoverrun/prune_alias.c, FP_prune_alias_exp_Ok, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [1, 1] Size: [1, 1]]
codetoanalyze/c/bufferoverrun/prune_alias.c, call_prune_arrblk_ne_Bad, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,Call,Parameter: x,ArrayAccess: Offset: [5, 5] Size: [5, 5] @ codetoanalyze/c/bufferoverrun/prune_alias.c:117:5 by call to `prune_arrblk_ne()` ] codetoanalyze/c/bufferoverrun/prune_alias.c, call_prune_arrblk_ne_Bad, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,Call,Parameter: x,ArrayAccess: Offset: [5, 5] Size: [5, 5] @ codetoanalyze/c/bufferoverrun/prune_alias.c:117:5 by call to `prune_arrblk_ne()` ]
@ -83,9 +84,9 @@ codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_not_Bad, 3, CONDI
codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_not_Bad, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [1, 1] Size: [1, 1]] codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_not_Bad, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,Assignment,ArrayAccess: Offset: [1, 1] Size: [1, 1]]
codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_true_Ok, 3, CONDITION_ALWAYS_TRUE, WARNING, [] codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_true_Ok, 3, CONDITION_ALWAYS_TRUE, WARNING, []
codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_value_Ok, 3, CONDITION_ALWAYS_FALSE, WARNING, [] codetoanalyze/c/bufferoverrun/prune_constant.c, prune_constant_value_Ok, 3, CONDITION_ALWAYS_FALSE, WARNING, []
codetoanalyze/c/bufferoverrun/sizeof.c, FN_static_stride_bad, 5, CONDITION_ALWAYS_FALSE, WARNING, []
codetoanalyze/c/bufferoverrun/sizeof.c, eval_sizeof_bad, 1, CONDITION_ALWAYS_TRUE, WARNING, [] codetoanalyze/c/bufferoverrun/sizeof.c, eval_sizeof_bad, 1, CONDITION_ALWAYS_TRUE, WARNING, []
codetoanalyze/c/bufferoverrun/sizeof.c, eval_sizeof_bad, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [1, 1] Size: [0, 0]] codetoanalyze/c/bufferoverrun/sizeof.c, eval_sizeof_bad, 4, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [1, 1] Size: [0, 0]]
codetoanalyze/c/bufferoverrun/sizeof.c, static_stride_bad, 7, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [1, 1] Size: [0, 0]]
codetoanalyze/c/bufferoverrun/trivial.c, trivial, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [10, 10] Size: [10, 10]] codetoanalyze/c/bufferoverrun/trivial.c, trivial, 2, BUFFER_OVERRUN_L1, ERROR, [ArrayDeclaration,ArrayAccess: Offset: [10, 10] Size: [10, 10]]
codetoanalyze/c/bufferoverrun/unreachable.c, FP_loop_once_intentional_good, 3, CONDITION_ALWAYS_FALSE, WARNING, [] codetoanalyze/c/bufferoverrun/unreachable.c, FP_loop_once_intentional_good, 3, CONDITION_ALWAYS_FALSE, WARNING, []
codetoanalyze/c/bufferoverrun/unreachable.c, FP_loop_with_break_good, 1, CONDITION_ALWAYS_TRUE, WARNING, [] codetoanalyze/c/bufferoverrun/unreachable.c, FP_loop_with_break_good, 1, CONDITION_ALWAYS_TRUE, WARNING, []

@ -7,7 +7,7 @@
* 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.
*/ */
void pointer_arith_bad() { void FN_pointer_arith_bad() {
char arr[10]; char arr[10];
int x = 0; int x = 0;
if (&x - 1 == 0) if (&x - 1 == 0)

@ -22,7 +22,7 @@ struct some_struct {
int x1; int x1;
}; };
void static_stride_bad() { void FN_static_stride_bad() {
struct some_struct a[10]; struct some_struct a[10];
struct some_struct *x, *y; struct some_struct *x, *y;
x = &(a[5]); x = &(a[5]);

Loading…
Cancel
Save