From b0375e267c55ae97e65b50ce51200e012ac3e8ad Mon Sep 17 00:00:00 2001
From: Yong Tang <yong.tang.github@outlook.com>
Date: Sat, 6 Jun 2020 01:24:20 +0000
Subject: [PATCH 1/2] Fix floating point exception with tf.unravel_index

This PR tries to address the issue raised in 40204 where
`tf.unravel_index` caused floating point exception when any one
element is 0 in `dims`.

The issue is that `indices` in `tf.unravel_index` should make sure
it is not out of boundary compared to `dims`.

This PR fixes the issue by adding a check before hand, though Eigen.

This PR fixes 40204.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
---
 tensorflow/core/kernels/unravel_index_op.cc    | 18 ++++++++++++++++++
 .../python/kernel_tests/array_ops_test.py      | 10 ++++++++++
 2 files changed, 28 insertions(+)

diff --git a/tensorflow/core/kernels/unravel_index_op.cc b/tensorflow/core/kernels/unravel_index_op.cc
index 8d839ba85a7..d41915e5c14 100644
--- a/tensorflow/core/kernels/unravel_index_op.cc
+++ b/tensorflow/core/kernels/unravel_index_op.cc
@@ -54,6 +54,24 @@ class UnravelIndexOp : public OpKernel {
 
     auto dims = dims_tensor.vec<Tidx>();
 
+    // Chek to make sure indices is not out of boundary
+    Eigen::Tensor<bool, 0, Eigen::RowMajor> check;
+    if (TensorShapeUtils::IsScalar(indices_tensor.shape())) {
+      auto indices = indices_tensor.scalar<Tidx>();
+      auto dims_prod = dims.prod();
+      check = (indices < dims_prod).all();
+    } else {
+      auto indices = indices_tensor.vec<Tidx>();
+      auto dims_prod = dims.prod()
+          .reshape(Eigen::array<Eigen::Index, 1>({1}))
+          .broadcast(
+              Eigen::array<Eigen::Index, 1>({indices_tensor.NumElements()}));
+      check = (indices < dims_prod).all();
+    }
+    OP_REQUIRES(
+        ctx, check(),
+        errors::InvalidArgument("index is out of bound as with dims"));
+
     Eigen::array<bool, 1> reverse({true});
 
     Tensor strides_tensor;
diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py
index ec3ed932996..caf05042557 100644
--- a/tensorflow/python/kernel_tests/array_ops_test.py
+++ b/tensorflow/python/kernel_tests/array_ops_test.py
@@ -1384,6 +1384,16 @@ class UnravelIndexTest(test_util.TensorFlowTestCase):
         out_3 = array_ops.unravel_index(indices_3, dims_3)
         self.assertAllEqual(out_3.eval(), [[3, 6, 6], [4, 5, 1]])
 
+  # Test case for GitHub issue 40204.
+  def testUnravelIndexZeroDim(self):
+    with self.cached_session():
+      for dtype in [dtypes.int32, dtypes.int64]:
+        with self.assertRaisesRegexp(
+            errors.InvalidArgumentError, "index is out of bound as with dims"):
+          indices = constant_op.constant([2, 5, 7], dtype=dtype)
+          dims = constant_op.constant([3, 0], dtype=dtype)
+          self.evaluate(array_ops.unravel_index(indices=indices, dims=dims))
+
 
 class GuaranteeConstOpTest(test_util.TensorFlowTestCase):
 

From 43930312404d885f1d6de086120712ddb633afdb Mon Sep 17 00:00:00 2001
From: Yong Tang <yong.tang.github@outlook.com>
Date: Sun, 7 Jun 2020 17:20:27 +0000
Subject: [PATCH 2/2] Update the boundary check in unravel_index to use
 std::all_of instead of eigen

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
---
 tensorflow/core/kernels/unravel_index_op.cc | 22 ++++++++-------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/tensorflow/core/kernels/unravel_index_op.cc b/tensorflow/core/kernels/unravel_index_op.cc
index d41915e5c14..fb8d6703d57 100644
--- a/tensorflow/core/kernels/unravel_index_op.cc
+++ b/tensorflow/core/kernels/unravel_index_op.cc
@@ -55,21 +55,15 @@ class UnravelIndexOp : public OpKernel {
     auto dims = dims_tensor.vec<Tidx>();
 
     // Chek to make sure indices is not out of boundary
-    Eigen::Tensor<bool, 0, Eigen::RowMajor> check;
-    if (TensorShapeUtils::IsScalar(indices_tensor.shape())) {
-      auto indices = indices_tensor.scalar<Tidx>();
-      auto dims_prod = dims.prod();
-      check = (indices < dims_prod).all();
-    } else {
-      auto indices = indices_tensor.vec<Tidx>();
-      auto dims_prod = dims.prod()
-          .reshape(Eigen::array<Eigen::Index, 1>({1}))
-          .broadcast(
-              Eigen::array<Eigen::Index, 1>({indices_tensor.NumElements()}));
-      check = (indices < dims_prod).all();
-    }
+    Eigen::Tensor<Tidx, 0, Eigen::RowMajor> dims_prod_eigen = dims.prod();
+    Tidx dims_prod = dims_prod_eigen();
+    const Tidx* indices = indices_tensor.flat<Tidx>().data();
+    int64 size = indices_tensor.NumElements();
+    bool check = std::all_of(indices, indices + size, [&](Tidx index) {
+        return index < dims_prod;
+    });
     OP_REQUIRES(
-        ctx, check(),
+        ctx, check,
         errors::InvalidArgument("index is out of bound as with dims"));
 
     Eigen::array<bool, 1> reverse({true});