From e0c62dfdfc2455f325cae62ea2e77758554e171e Mon Sep 17 00:00:00 2001 From: Лач Date: Wed, 01 Jul 2020 18:35:30 +0000 Subject: [PATCH] feat(evaluator): number overflow checks --- --- a/crates/jrsonnet-evaluator/src/evaluate.rs +++ b/crates/jrsonnet-evaluator/src/evaluate.rs @@ -92,7 +92,7 @@ (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())), (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())), - (Val::Num(v1), Val::Num(v2)) => Val::Num(v1 + v2), + (Val::Num(v1), Val::Num(v2)) => Val::new_checked_num(v1 + v2)?, _ => create_error_result(Error::BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Add, a.value_type()?, @@ -135,15 +135,15 @@ (Val::Str(v1), BinaryOpType::Gte, Val::Str(v2)) => Val::Bool(v1 >= v2), // Num X Num - (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2), + (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::new_checked_num(v1 * v2)?, (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => { if *v2 <= f64::EPSILON { create_error_result(crate::Error::DivisionByZero)? } - Val::Num(v1 / v2) + Val::new_checked_num(v1 / v2)? } - (Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2), + (Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::new_checked_num(v1 - v2)?, (Val::Num(v1), BinaryOpType::Lt, Val::Num(v2)) => Val::Bool(v1 < v2), (Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => Val::Bool(v1 > v2), @@ -644,7 +644,7 @@ Literal(LiteralType::Null) => Val::Null, Parened(e) => evaluate(context, e)?, Str(v) => Val::Str(v.clone()), - Num(v) => Val::Num(*v), + Num(v) => Val::new_checked_num(*v)?, BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?, UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?, Var(name) => push(loc, "var", || { --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -134,6 +134,15 @@ }; } impl Val { + /// Creates Val::Num after checking for overflow. As numbers are f64, we can just check for finity + pub fn new_checked_num(num: f64) -> Result { + if num.is_finite() { + Ok(Val::Num(num)) + } else { + create_error_result(Error::RuntimeError("overflow".into())) + } + } + pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> { let this_type = self.value_type()?; if this_type != val_type { -- gitstuff