From 13718eb34d0e086c873a4d66102b1bad861af511 Mon Sep 17 00:00:00 2001 From: Virgile Prevosto <virgile.prevosto@m4x.org> Date: Wed, 7 Apr 2021 19:29:22 +0200 Subject: [PATCH] [convert] Fixes erroneous handling of big unsigned constants This is arguably a short-term fix, and a better fix would be to rely directly on big integers, at least on OCaml side, in the intermediate format. --- convert.ml | 58 +++++++++++-------- .../basic/oracle/enum_neg_const.0.res.oracle | 2 +- .../basic/oracle/enum_neg_const.1.res.oracle | 15 ++++- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/convert.ml b/convert.ml index fb58f938..99ca4218 100644 --- a/convert.ml +++ b/convert.ml @@ -143,7 +143,7 @@ let spec_of_ikind s = ) let make_integral_constant_kind k v = - let v = Int64.to_string v in + let v = Integer.to_string v in let s = match k with | IBool @@ -157,6 +157,17 @@ let make_integral_constant_kind k v = | IULongLong -> "ULL" in CONST_INT (v ^ s) +let is_unsigned_kind = function + | IBool -> true (* standard says that bool is neither signed nor unsigned, + but at some point you have to take sides. *) + | IChar_s | ISChar | IWChar_s | IWSChar -> false + | IChar | IWChar -> Cil.theMachine.theMachine.char_is_unsigned + | IShort | IInt -> false + | IChar_u | IUChar | IChar16 | IChar32 | IWChar_u | IWUChar + | IUShort | IUInt -> true + | ILong | ILongLong -> false + | IULong | IULongLong -> true + let closure_name = "__fc_closure" let mk_expr_l expr_loc expr_node = { expr_loc; expr_node } @@ -173,11 +184,28 @@ let mk_var env name = mk_expr env (VARIABLE name) let mk_addrof env e = mk_expr env (UNARY(ADDROF,e)) -let mk_int64_cst_n i = CONSTANT (CONST_INT (Int64.to_string i)) +let mk_int64_cst_n env ?(kind=IInt) i = + let mk_node i = CONSTANT (make_integral_constant_kind kind i) in + let mk_node_64 i = mk_node (Integer.of_int64 i) in + let mk_exp_64 i = mk_expr env (mk_node_64 i) in + if i < Int64.zero then begin + if is_unsigned_kind kind then begin + (* must convert back into unsigned version. *) + let v = Integer.of_int64 i in + let v = + Integer.(add (neg (mul (of_int 2) (of_int64 Int64.min_int)))) v + in + mk_node v + end else if i = Int64.min_int then begin + let m = Int64.neg (Int64.succ i) in + BINARY( + SUB, mk_expr env (UNARY (MINUS, (mk_exp_64 m))), mk_exp_64 Int64.one) + end else UNARY(MINUS, mk_exp_64 i) + end else mk_node_64 i -let mk_int64_cst env i = mk_expr env (mk_int64_cst_n i) +let mk_int64_cst env ?kind i = mk_expr env (mk_int64_cst_n env ?kind i) -let mk_zero env = (mk_int64_cst env Int64.zero) +let mk_zero ?kind env = (mk_int64_cst env ?kind Int64.zero) let mk_assign env dst src = mk_expr env (BINARY(ASSIGN, dst, src)) @@ -765,10 +793,7 @@ and make_prototype loc env name kind rt args variadic does_remove_virtual = env, (rt, (name,decl (PROTO(JUSTBASE,args,[],variadic)),[],loc)) and convert_constant env c does_remove_virtual = match c with - | IntCst (t,_,v) -> - if ((Int64.compare v Int64.zero) >= 0) - then CONSTANT (make_integral_constant_kind t v) - else UNARY(MINUS, mk_int64_cst env (Int64.neg v)) + | IntCst (kind,_,v) -> mk_int64_cst_n env ~kind v | FloatCst(_,v) -> CONSTANT(CONST_FLOAT v) | EnumCst(n,e,_) -> let n, t = Convert_env.typedef_normalize env n TStandard in @@ -2469,7 +2494,7 @@ and convert_stmt_list env l does_remove_virtual = in List.rev stmts, env -let convert_enum_constant env ikind e = +let convert_enum_constant env kind e = let loc = Convert_env.get_loc env in match e with | EnumCst(name,e,value) -> @@ -2480,20 +2505,7 @@ let convert_enum_constant env ikind e = in (* If the value is negative, create an expression with a positive value. *) - let value = - if value < Int64.zero then begin - (* The negation of min_int may overflow. *) - if value = Int64.min_int then - Frama_Clang_option.abort - ~current:true "Enum constant has value -2^63"; - UNARY(MINUS, - mk_expr env - (CONSTANT - (make_integral_constant_kind ikind (Int64.neg value)))) - end else - CONSTANT (make_integral_constant_kind ikind value) - in - (name,mk_expr env value,loc) + (name,mk_int64_cst env ~kind value,loc) | FloatCst _ | IntCst _ | TypeCst _ -> Frama_Clang_option.fatal "Enum constant has a wrong kind" diff --git a/tests/basic/oracle/enum_neg_const.0.res.oracle b/tests/basic/oracle/enum_neg_const.0.res.oracle index 93760dbb..1e5cba71 100644 --- a/tests/basic/oracle/enum_neg_const.0.res.oracle +++ b/tests/basic/oracle/enum_neg_const.0.res.oracle @@ -2,7 +2,7 @@ Now output intermediate result /* Generated by Frama-C */ enum foo { - A = -2UL + A = 18446744073709551614UL }; int main(void) { diff --git a/tests/basic/oracle/enum_neg_const.1.res.oracle b/tests/basic/oracle/enum_neg_const.1.res.oracle index 875f5966..de6564fe 100644 --- a/tests/basic/oracle/enum_neg_const.1.res.oracle +++ b/tests/basic/oracle/enum_neg_const.1.res.oracle @@ -1,5 +1,14 @@ [kernel] Parsing tests/basic/enum_neg_const.cpp (external front-end) Now output intermediate result -[fclang] tests/basic/enum_neg_const.cpp:6: User Error: - Enum constant has value -2^63 -[kernel] Plug-in fclang aborted: invalid user input. +/* Generated by Frama-C */ +enum foo { + A = 9223372036854775808UL +}; +int main(void) +{ + int __retres; + __retres = (int)((enum foo)A); + return __retres; +} + + -- GitLab