feat(tvix/eval): detect division by zero

This detects if the second argument of a division is a zero (either as integer
or as float). If so, an error message is displayed.

This fixes b/219.

Change-Id: I50203d14a71482bc757832a2c8dee08eb7d35c49
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7258
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
jhahn 2022-11-09 23:47:07 +00:00 committed by jrhahn
parent 40826e664d
commit d00030128e
4 changed files with 22 additions and 1 deletions

View file

@ -20,6 +20,8 @@ pub enum ErrorKind {
Abort(String),
AssertionFailed,
DivisionByZero,
DuplicateAttrsKey {
key: String,
},
@ -215,6 +217,8 @@ impl Display for Error {
ErrorKind::Abort(msg) => write!(f, "evaluation aborted: {}", msg),
ErrorKind::AssertionFailed => write!(f, "assertion failed"),
ErrorKind::DivisionByZero => write!(f, "division by zero"),
ErrorKind::DuplicateAttrsKey { key } => {
write!(f, "attribute key '{}' already defined", key)
}
@ -656,6 +660,7 @@ impl Error {
| ErrorKind::TailEmptyList
| ErrorKind::TypeError { .. }
| ErrorKind::Incomparable { .. }
| ErrorKind::DivisionByZero
| ErrorKind::DynamicKeyInScope(_)
| ErrorKind::UnknownStaticVariable
| ErrorKind::UnknownDynamicVariable(_)
@ -717,6 +722,7 @@ impl Error {
ErrorKind::FromJsonError { .. } => "E030",
ErrorKind::UnexpectedArgument { .. } => "E031",
ErrorKind::RelativePathResolution(_) => "E032",
ErrorKind::DivisionByZero => "E033",
// Special error code that is not part of the normal
// ordering.

View file

@ -0,0 +1 @@
1.0 / 0.0

View file

@ -0,0 +1 @@
1 / 0

View file

@ -412,7 +412,20 @@ impl<'o> VM<'o> {
OpCode::OpSub => arithmetic_op!(self, -),
OpCode::OpMul => arithmetic_op!(self, *),
OpCode::OpDiv => arithmetic_op!(self, /),
OpCode::OpDiv => {
let b = self.peek(0);
match b {
Value::Integer(0) => return Err(self.error(ErrorKind::DivisionByZero)),
Value::Float(b) => {
if *b == (0.0 as f64) {
return Err(self.error(ErrorKind::DivisionByZero));
}
arithmetic_op!(self, /)
}
_ => arithmetic_op!(self, /),
};
}
OpCode::OpInvert => {
let v = fallible!(self, self.pop().as_bool());