This is an automated email from the ASF dual-hosted git repository.

junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new 86bbddf  feat: Add overflow check for uint64_t/size_t in 
TypeTraits<Int>::CopyToAnyView (#370)
86bbddf is described below

commit 86bbddfdbaa9103016e3f39633b8b2402ea24428
Author: Nan <[email protected]>
AuthorDate: Thu Jan 8 17:49:37 2026 +0800

    feat: Add overflow check for uint64_t/size_t in 
TypeTraits<Int>::CopyToAnyView (#370)
    
    Related discussion here  #357
    Adds runtime overflow detection when converting unsigned 64-bit integers
    ([uint64_t or
    
size_t](https://stackoverflow.com/questions/73820966/stdis-same-vsize-t-uint64-t-evaluates-to-false-when-both-types-are-8-by
    )) to int64_t in TVM FFI Any.
    
    
    128-bit signed integers (if exists) are not considered.
    
    ---------
    
    Co-authored-by: Junru Shao <[email protected]>
---
 include/tvm/ffi/type_traits.h    |  8 ++++++++
 src/ffi/extra/structural_hash.cc | 24 ++++++++++++++++++------
 tests/cpp/test_any.cc            | 16 ++++++++++++++++
 tests/cpp/testing_object.h       |  5 ++---
 4 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/include/tvm/ffi/type_traits.h b/include/tvm/ffi/type_traits.h
index 437dcd9..1fd1304 100644
--- a/include/tvm/ffi/type_traits.h
+++ b/include/tvm/ffi/type_traits.h
@@ -28,6 +28,7 @@
 #include <tvm/ffi/error.h>
 #include <tvm/ffi/object.h>
 
+#include <limits>
 #include <string>
 #include <type_traits>
 #include <utility>
@@ -279,6 +280,13 @@ struct TypeTraits<Int, 
std::enable_if_t<std::is_integral_v<Int>>> : public TypeT
   static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIInt;
 
   TVM_FFI_INLINE static void CopyToAnyView(const Int& src, TVMFFIAny* result) {
+    if constexpr (std::is_unsigned_v<Int> && sizeof(Int) >= sizeof(int64_t)) {
+      if (src > static_cast<Int>(std::numeric_limits<int64_t>::max())) {
+        TVM_FFI_THROW(OverflowError)
+            << "Integer value " << src << " is too large to fit in int64_t. "
+            << "Consider explicitly casting to int64_t first if this is 
intentional.";
+      }
+    }
     result->type_index = TypeIndex::kTVMFFIInt;
     result->zero_padding = 0;
     result->v_int64 = static_cast<int64_t>(src);
diff --git a/src/ffi/extra/structural_hash.cc b/src/ffi/extra/structural_hash.cc
index 271a0db..5bb9eb1 100644
--- a/src/ffi/extra/structural_hash.cc
+++ b/src/ffi/extra/structural_hash.cc
@@ -150,15 +150,19 @@ class StructuralHashHandler {
                 std::swap(allow_free_var, map_free_vars_);
                 uint64_t hash_value = HashAny(val);
                 std::swap(allow_free_var, map_free_vars_);
-                return details::StableHashCombine(init_hash, hash_value);
+                return 
static_cast<int64_t>(details::StableHashCombine(init_hash, hash_value));
               } else {
-                return details::StableHashCombine(init_hash, HashAny(val));
+                // we explicitly bitcast the result from `uint64_t` to 
`int64_t`.
+                // The range of `uint64_t` is too large to fit as `int64_t`, 
so if we don't bitcast,
+                // it will trigger an overflow error in `uint64_t` -> `Any` 
conversion.
+                return 
static_cast<int64_t>(details::StableHashCombine(init_hash, HashAny(val)));
               }
             });
       }
-      hash_value = custom_s_hash[type_info->type_index]
-                       .cast<ffi::Function>()(obj, hash_value, 
s_hash_callback_)
-                       .cast<uint64_t>();
+      hash_value =
+          custom_s_hash[type_info->type_index]
+              .cast<ffi::Function>()(obj, static_cast<int64_t>(hash_value), 
s_hash_callback_)
+              .cast<uint64_t>();
     }
 
     if (structural_eq_hash_kind == kTVMFFISEqHashKindFreeVar) {
@@ -311,9 +315,17 @@ uint64_t StructuralHash::Hash(const Any& value, bool 
map_free_vars, bool skip_te
   return handler.HashAny(value);
 }
 
+static int64_t FFIStructuralHash(const Any& value, bool map_free_vars, bool 
skip_tensor_content) {
+  uint64_t result = StructuralHash::Hash(value, map_free_vars, 
skip_tensor_content);
+  // we explicitly bitcast the result from `uint64_t` to `int64_t`.
+  // The range of `uint64_t` is too large to fit as `int64_t`, so if we don't 
bitcast,
+  // it will trigger an overflow error in `uint64_t` -> `Any` conversion.
+  return static_cast<int64_t>(result);
+}
+
 TVM_FFI_STATIC_INIT_BLOCK() {
   namespace refl = tvm::ffi::reflection;
-  refl::GlobalDef().def("ffi.StructuralHash", StructuralHash::Hash);
+  refl::GlobalDef().def("ffi.StructuralHash", FFIStructuralHash);
   refl::EnsureTypeAttrColumn("__s_hash__");
 }
 
diff --git a/tests/cpp/test_any.cc b/tests/cpp/test_any.cc
index 55abbbf..c29ad5c 100644
--- a/tests/cpp/test_any.cc
+++ b/tests/cpp/test_any.cc
@@ -20,6 +20,8 @@
 #include <tvm/ffi/any.h>
 #include <tvm/ffi/memory.h>
 
+#include <limits>
+
 #include "./testing_object.h"
 
 namespace {
@@ -58,6 +60,20 @@ TEST(Any, Int) {
   view0 = v1;
   EXPECT_EQ(view0.CopyToTVMFFIAny().type_index, TypeIndex::kTVMFFIInt);
   EXPECT_EQ(view0.CopyToTVMFFIAny().v_int64, 2);
+
+  uint64_t v2 = static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
+  EXPECT_THROW(
+      {
+        try {
+          view0 = v2;
+        } catch (const Error& error) {
+          EXPECT_EQ(error.kind(), "OverflowError");
+          std::string what = error.what();
+          EXPECT_NE(what.find("is too large to fit in int64_t"), 
std::string::npos);
+          throw;
+        }
+      },
+      ::tvm::ffi::Error);
 }
 
 TEST(Any, Enum) {
diff --git a/tests/cpp/testing_object.h b/tests/cpp/testing_object.h
index 933ba99..318aa11 100644
--- a/tests/cpp/testing_object.h
+++ b/tests/cpp/testing_object.h
@@ -233,9 +233,8 @@ class TCustomFuncObj : public Object {
     return true;
   }
 
-  uint64_t SHash(uint64_t init_hash,
-                 ffi::TypedFunction<uint64_t(AnyView, uint64_t, bool)> hash) 
const {
-    uint64_t hash_value = init_hash;
+  int64_t SHash(int64_t init_hash, ffi::TypedFunction<int64_t(AnyView, 
int64_t, bool)> hash) const {
+    int64_t hash_value = init_hash;
     hash_value = hash(params, hash_value, true);
     hash_value = hash(body, hash_value, false);
     return hash_value;

Reply via email to