From 84c7824afcadfc7aef5246e141d5ef98d2e8d822 Mon Sep 17 00:00:00 2001 From: Julien Signoles <julien.signoles@cea.fr> Date: Wed, 23 Mar 2016 08:59:23 +0100 Subject: [PATCH] [typing] fix bug with floats/reals; more generally force typing of every non-integer term --- .../tests/bts/oracle/bts1307.res.oracle | 3 +- .../e-acsl/tests/bts/oracle/gen_bts1307.c | 6 +- .../e-acsl-runtime/oracle/valid.res.oracle | 4 +- src/plugins/e-acsl/typing.ml | 159 +++++++++--------- src/plugins/e-acsl/typing.mli | 2 +- 5 files changed, 92 insertions(+), 82 deletions(-) diff --git a/src/plugins/e-acsl/tests/bts/oracle/bts1307.res.oracle b/src/plugins/e-acsl/tests/bts/oracle/bts1307.res.oracle index 7785f52bb95..1b9b45f9fc2 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/bts1307.res.oracle +++ b/src/plugins/e-acsl/tests/bts/oracle/bts1307.res.oracle @@ -6,4 +6,5 @@ tests/bts/bts1307.i:11:[e-acsl] warning: approximating a real number by a float [e-acsl] translation done in project "e-acsl". FRAMAC_SHARE/e-acsl/e_acsl.h:43:[value] warning: function __e_acsl_assert: precondition got status unknown. [value] user error: type long double not implemented. Using double instead -FRAMAC_SHARE/e-acsl/e_acsl.h:43:[value] warning: function __e_acsl_assert: precondition got status invalid. +tests/bts/bts1307.i:23:[value] warning: function bar, behavior UnderEstimate_Motoring: postcondition got status unknown. +tests/bts/bts1307.i:23:[value] warning: function __gen_e_acsl_bar, behavior UnderEstimate_Motoring: postcondition got status unknown. diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c index d15f8673865..121b10cc72f 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c @@ -254,9 +254,9 @@ void __gen_e_acsl_foo(float *Mtmax_in, float *Mwmax, float *Mtmax_out) sizeof(float)); __e_acsl_assert(__gen_e_acsl_valid_read_3,(char *)"RTE",(char *)"foo", (char *)"mem_access: \\valid_read(__gen_e_acsl_at)",11); - __e_acsl_assert(*__gen_e_acsl_at == *__gen_e_acsl_at_2 + (long double)( - (long double)5 - ((long double)( - 5 / 80) * *__gen_e_acsl_at_3) * 0.4), + __e_acsl_assert(*__gen_e_acsl_at == *__gen_e_acsl_at_2 + ((long double)5 - + ((long double)( + 5 / 80) * *__gen_e_acsl_at_3) * 0.4), (char *)"Postcondition",(char *)"foo", (char *)"*\\old(Mtmax_out) == *\\old(Mtmax_in)+(5-((5/80)**\\old(Mwmax))*0.4)", 11); diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/valid.res.oracle b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/valid.res.oracle index 58ac8f9ec26..e1eb42c942a 100644 --- a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/valid.res.oracle +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/valid.res.oracle @@ -5,13 +5,15 @@ tests/e-acsl-runtime/valid.c:14:[e-acsl] warning: E-ACSL construct `complete beh Ignoring annotation. tests/e-acsl-runtime/valid.c:14:[e-acsl] warning: E-ACSL construct `disjoint behaviors' is not yet supported. Ignoring annotation. -FRAMAC_SHARE/libc/stdlib.h:178:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. +FRAMAC_SHARE/libc/stdlib.h:179:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/stdlib.h:178:[e-acsl] warning: E-ACSL construct `\allocate' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/stdlib.h:178:[e-acsl] warning: E-ACSL construct `complete behaviors' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/stdlib.h:178:[e-acsl] warning: E-ACSL construct `disjoint behaviors' is not yet supported. Ignoring annotation. +FRAMAC_SHARE/libc/stdlib.h:178:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. FRAMAC_SHARE/libc/stdlib.h:161:[e-acsl] warning: E-ACSL construct `logic function application' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/stdlib.h:161:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. diff --git a/src/plugins/e-acsl/typing.ml b/src/plugins/e-acsl/typing.ml index 85e3cb650dc..341dc9f7aa9 100644 --- a/src/plugins/e-acsl/typing.ml +++ b/src/plugins/e-acsl/typing.ml @@ -192,11 +192,11 @@ let rec type_term env ~ctx t = let ty = try let i = Interval.infer env t in - type_term_lval env tlv; ty_of_interv ~ctx i with Interval.Not_an_integer -> Other in + type_term_lval env tlv; dup ty | Toffset(_, t') @@ -210,7 +210,7 @@ let rec type_term env ~ctx t = ignore (type_term env ~ctx:Other t'); ty_of_interv ~ctx i with Interval.Not_an_integer -> - Other + assert false in dup ty @@ -223,50 +223,51 @@ let rec type_term env ~ctx t = ignore (type_term env ~ctx:Other t2); ty_of_interv ~ctx i with Interval.Not_an_integer -> - Other + assert false in dup ty | TUnOp (unop, t') -> - let ty = - let i = Interval.infer env t in - let i' = Interval.infer env t' in - let ctx = mk_ctx (ty_of_interv ~ctx (Interval.join i i')) in - ignore (type_term env ~ctx t'); - ctx + let ctx = + try + let i = Interval.infer env t in + let i' = Interval.infer env t' in + mk_ctx (ty_of_interv ~ctx (Interval.join i i')) + with Interval.Not_an_integer -> + Other (* real *) in + ignore (type_term env ~ctx t'); (match unop with - | LNot -> c_int, ty (* converted into [t == 0] in casse of GMP *) - | Neg | BNot -> dup ty) + | LNot -> c_int, ctx (* converted into [t == 0] in casse of GMP *) + | Neg | BNot -> dup ctx) | TBinOp((PlusA | MinusA | Mult | Div | Mod | Shiftlt | Shiftrt), t1, t2) -> - let ty = - let i = Interval.infer env t in - let i1 = Interval.infer env t1 in - let i2 = Interval.infer env t2 in - let ctx = + let ctx = + try + let i = Interval.infer env t in + let i1 = Interval.infer env t1 in + let i2 = Interval.infer env t2 in mk_ctx (ty_of_interv ~ctx (Interval.join i (Interval.join i1 i2))) - in - ignore (type_term env ~ctx t1); - ignore (type_term env ~ctx t2); - ctx + with Interval.Not_an_integer -> + Other (* real *) in - dup ty + ignore (type_term env ~ctx t1); + ignore (type_term env ~ctx t2); + dup ctx | TBinOp ((Lt | Gt | Le | Ge | Eq | Ne), t1, t2) -> assert (compare ctx c_int >= 0); - let ty = - let ctx = - try - let i1 = Interval.infer env t1 in - let i2 = Interval.infer env t2 in - mk_ctx (ty_of_interv ~ctx (Interval.join i1 i2)) - with Interval.Not_an_integer -> - Other - in - ignore (type_term env ~ctx t1); - ignore (type_term env ~ctx t2); - match ctx with + let ctx = + try + let i1 = Interval.infer env t1 in + let i2 = Interval.infer env t2 in + mk_ctx (ty_of_interv ~ctx (Interval.join i1 i2)) + with Interval.Not_an_integer -> + Other + in + ignore (type_term env ~ctx t1); + ignore (type_term env ~ctx t2); + let ty = match ctx with | Other -> c_int | Gmp | C_type _ -> ctx in @@ -274,14 +275,16 @@ let rec type_term env ~ctx t = | TBinOp ((LAnd | LOr), t1, t2) -> let ty = - assert (compare ctx c_int >= 1); - let i1 = Interval.infer env t1 in - let i2 = Interval.infer env t2 in - (* both operands fit in an int. *) - ignore (type_term env ~ctx:c_int t1); - ignore (type_term env ~ctx:c_int t2); - ty_of_interv ~ctx (Interval.join i1 i2) + try + let i1 = Interval.infer env t1 in + let i2 = Interval.infer env t2 in + ty_of_interv ~ctx (Interval.join i1 i2) + with Interval.Not_an_integer -> + Other in + (* both operands fit in an int. *) + ignore (type_term env ~ctx:c_int t1); + ignore (type_term env ~ctx:c_int t2); dup ty | TBinOp (BAnd, _, _) -> Error.not_yet "bitwise and" @@ -290,55 +293,51 @@ let rec type_term env ~ctx t = | TCastE(_, t') | TCoerce(t', _) -> - let ty = - (* in any case, must type the subterms *) + let ctx = try let i = Interval.infer env t' in - (* nothing to do more: [i] is already more precise than what we could - infer from the arguments of the cast. Also, do not type the + (* nothing to do more: [i] is already more precise than what we + could infer from the arguments of the cast. Also, do not type the internal term: possibly it is not even an integer *) - let ty = ty_of_interv ~ctx i in - ignore (type_term env ~ctx:ty t'); - ty + ty_of_interv ~ctx i with Interval.Not_an_integer -> - ignore (type_term env ~ctx:Other t'); Other in - dup ty + ignore (type_term env ~ctx t'); + dup ctx | Tif (t1, t2, t3) -> - let ty = - let ctx = mk_ctx c_int in - ignore (type_term env ~ctx t1); - let i = Interval.infer env t in - let ctx = - try - let i2 = Interval.infer env t2 in - let i3 = Interval.infer env t3 in - mk_ctx (ty_of_interv ~ctx (Interval.join i (Interval.join i2 i3))) - with Interval.Not_an_integer -> - Other - in - ignore (type_term env ~ctx t2); - ignore (type_term env ~ctx t3); - ctx + let ctx = mk_ctx c_int in + ignore (type_term env ~ctx t1); + let i = Interval.infer env t in + let ctx = + try + let i2 = Interval.infer env t2 in + let i3 = Interval.infer env t3 in + mk_ctx (ty_of_interv ~ctx (Interval.join i (Interval.join i2 i3))) + with Interval.Not_an_integer -> + Other in - dup ty + ignore (type_term env ~ctx t2); + ignore (type_term env ~ctx t3); + dup ctx | Tat (t, _) | TLogic_coerce (_, t) -> dup (type_term env ~ctx t).ty | TCoerceE (t1, t2) -> - let ty = - let i = Interval.infer env t in - let i1 = Interval.infer env t1 in - let i2 = Interval.infer env t2 in - let ty = ty_of_interv ~ctx (Interval.join i (Interval.join i1 i2)) in - ignore (type_term env ~ctx:ty t1); - ignore (type_term env ~ctx:ty t2); - ty + let ctx = + try + let i = Interval.infer env t in + let i1 = Interval.infer env t1 in + let i2 = Interval.infer env t2 in + ty_of_interv ~ctx (Interval.join i (Interval.join i1 i2)) + with Interval.Not_an_integer -> + Other in - dup ty + ignore (type_term env ~ctx t1); + ignore (type_term env ~ctx t2); + dup ctx | TAddrOf tlv | TStartOf tlv -> @@ -516,13 +515,21 @@ let get_integer_op t = (Memo.get t).op let get_integer_op_of_predicate p = (type_predicate_named Interval.Env.empty (* the env is useless *) p).op +let extract_typ t ty = + try typ_of_integer_ty ty + with Not_an_integer -> + let ty = t.term_type in + if Cil.isLogicRealType ty then TFloat(FLongDouble, []) + else if Cil.isLogicFloatType ty then Logic_utils.logicCType ty + else assert false + let get_typ t = let info = Memo.get t in - try typ_of_integer_ty info.ty with Not_an_integer -> assert false + extract_typ t info.ty let get_op t = let info = Memo.get t in - try typ_of_integer_ty info.op with Not_an_integer -> assert false + extract_typ t info.op let get_cast t = Cil.CurrentLoc.set t.term_loc; diff --git a/src/plugins/e-acsl/typing.mli b/src/plugins/e-acsl/typing.mli index a65d34c137f..93b80b960c4 100644 --- a/src/plugins/e-acsl/typing.mli +++ b/src/plugins/e-acsl/typing.mli @@ -58,7 +58,7 @@ val get_integer_op: term -> integer_ty val get_integer_op_of_predicate: predicate named -> integer_ty val get_typ: term -> typ -(** Get the type of the given term which must be an integer. +(** Get the type of the given term. {!type_named_predicate} must already have been called on the englobing predicate. *) -- GitLab