This is an automated email from the ASF dual-hosted git repository.
tqchen 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 bdad218 fix: Type mismatch aborts on OpaquePyObject (#56)
bdad218 is described below
commit bdad2184551353e49a9b6882f7b9a75a258862bb
Author: Junru Shao <[email protected]>
AuthorDate: Thu Sep 25 12:38:37 2025 -0700
fix: Type mismatch aborts on OpaquePyObject (#56)
In
[#49](https://github.com/apache/tvm-ffi/pull/49#issuecomment-3331042097),
We noticed an issue with `OpaquePyObject`:
```
Exception caught during TVMFFIGetTypeInfo:
Traceback (most recent call last):
File "include/tvm/ffi/type_traits.h", line 92, in
tvm::ffi::TypeTraitsBase::GetMismatchTypeInfo[abi:cxx11](TVMFFIAny const*)
File "include/tvm/ffi/object.h", line 121, in
tvm::ffi::TypeIndexToTypeKey[abi:cxx11](int)
File "src/ffi/object.cc", line 493, in TVMFFIGetTypeInfo
File "src/ffi/object.cc", line 193, in tvm::ffi::TypeTable::Entry*
tvm::ffi::TypeTable::GetTypeEntry(int32_t)
InternalError: Check failed: (entry != nullptr) is false: Cannot find type
info for type_index=74
```
where when an `OpaquePyObject` is fed into a TVM-FFI function, which
expects a different type (e.g. `int`), the entire program aborts without
proper error message inside `TVMFFIGetTypeInfo`, which uses `exit(1)`
instead of C error code.
This PR fixes this issue by registering
`TypeIndex::kTVMFFIOpaquePyObject` as a builtin type index.
---
include/tvm/ffi/object.h | 2 ++
python/tvm_ffi/testing.py | 5 +++++
src/ffi/extra/testing.cc | 1 +
src/ffi/object.cc | 2 +-
tests/python/test_object.py | 10 ++++++++++
5 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/include/tvm/ffi/object.h b/include/tvm/ffi/object.h
index 93ef6d8..64db8d7 100644
--- a/include/tvm/ffi/object.h
+++ b/include/tvm/ffi/object.h
@@ -110,6 +110,8 @@ struct StaticTypeKey {
static constexpr const char* kTVMFFIMap = "ffi.Map";
/*! \brief The type key for Module */
static constexpr const char* kTVMFFIModule = "ffi.Module";
+ /*! \brief The type key for OpaquePyObject */
+ static constexpr const char* kTVMFFIOpaquePyObject = "ffi.OpaquePyObject";
};
/*!
diff --git a/python/tvm_ffi/testing.py b/python/tvm_ffi/testing.py
index 155030b..dbf8636 100644
--- a/python/tvm_ffi/testing.py
+++ b/python/tvm_ffi/testing.py
@@ -89,6 +89,11 @@ def make_unregistered_object() -> Object:
return get_global_func("testing.make_unregistered_object")()
+def add_one(x: int) -> int:
+ """Add one to the input integer."""
+ return get_global_func("testing.add_one")(x)
+
+
@c_class("testing.TestCxxClassBase")
class _TestCxxClassBase:
v_i64: int
diff --git a/src/ffi/extra/testing.cc b/src/ffi/extra/testing.cc
index f67752f..5d7ef58 100644
--- a/src/ffi/extra/testing.cc
+++ b/src/ffi/extra/testing.cc
@@ -217,6 +217,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
refl::GlobalDef()
.def("testing.test_raise_error", TestRaiseError)
+ .def("testing.add_one", [](int x) { return x + 1; })
.def_packed("testing.nop", [](PackedArgs args, Any* ret) {})
.def_packed("testing.echo", [](PackedArgs args, Any* ret) { *ret =
args[0]; })
.def_packed("testing.apply", TestApply)
diff --git a/src/ffi/object.cc b/src/ffi/object.cc
index d9c6698..aa7edbb 100644
--- a/src/ffi/object.cc
+++ b/src/ffi/object.cc
@@ -29,7 +29,6 @@
#include <tvm/ffi/string.h>
#include <memory>
-#include <string>
#include <utility>
#include <vector>
@@ -340,6 +339,7 @@ class TypeTable {
TypeIndex::kTVMFFIObjectRValueRef);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFISmallStr,
TypeIndex::kTVMFFISmallStr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFISmallBytes,
TypeIndex::kTVMFFISmallBytes);
+ ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIOpaquePyObject,
TypeIndex::kTVMFFIOpaquePyObject);
// no need to reserve for object types as they will be registered
}
diff --git a/tests/python/test_object.py b/tests/python/test_object.py
index 0c64e46..d23aa10 100644
--- a/tests/python/test_object.py
+++ b/tests/python/test_object.py
@@ -103,6 +103,16 @@ def test_opaque_object() -> None:
assert sys.getrefcount(obj0) == 2
+def test_opaque_type_error() -> None:
+ obj0 = MyObject("hello")
+ with pytest.raises(TypeError) as e:
+ tvm_ffi.testing.add_one(obj0) # type: ignore[arg-type]
+ assert (
+ "Mismatched type on argument #0 when calling: `testing.add_one(0: int)
-> int`. Expected `int` but got `ffi.OpaquePyObject`"
+ in str(e.value)
+ )
+
+
def test_unregistered_object_fallback() -> None:
def _check_type(x: Any) -> None:
type_info: TypeInfo = type(x).__tvm_ffi_type_info__ # type:
ignore[attr-defined]