about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjhahn <mail.jhahn@gmail.com>2022-11-09T23·47+0000
committerjrhahn <mail.jhahn@gmail.com>2022-11-10T13·12+0000
commitd00030128e465c8351412b1aefb4260681d8b497 (patch)
tree0c546e16df84ef098c7eb31322736de3e51c12a1
parent40826e664de6c5d243ced77fd6662b004b8fef49 (diff)
feat(tvix/eval): detect division by zero r/5276
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>
-rw-r--r--tvix/eval/src/errors.rs6
-rw-r--r--tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-float.nix1
-rw-r--r--tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-int.nix1
-rw-r--r--tvix/eval/src/vm.rs15
4 files changed, 22 insertions, 1 deletions
diff --git a/tvix/eval/src/errors.rs b/tvix/eval/src/errors.rs
index 8f782cb86151..ba9d6cb98ba6 100644
--- a/tvix/eval/src/errors.rs
+++ b/tvix/eval/src/errors.rs
@@ -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.
diff --git a/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-float.nix b/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-float.nix
new file mode 100644
index 000000000000..82dd6873218e
--- /dev/null
+++ b/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-float.nix
@@ -0,0 +1 @@
+1.0 / 0.0
diff --git a/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-int.nix b/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-int.nix
new file mode 100644
index 000000000000..72dca4d5e478
--- /dev/null
+++ b/tvix/eval/src/tests/nix_tests/eval-fail-division-by-zero-int.nix
@@ -0,0 +1 @@
+1 / 0
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 8c45ee7363e1..127d9bfa513c 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -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());