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 894419b0 fix(reflection): require exact field and method name matches 
(#674)
894419b0 is described below

commit 894419b0021b284d25883519c21e4faadfe8389c
Author: Kathryn (Jinqi) Chen <[email protected]>
AuthorDate: Sat Jul 18 00:08:09 2026 -0700

    fix(reflection): require exact field and method name matches (#674)
    
    GetFieldInfo and GetMethodInfo previously compared only the stored name
    length, allowing longer queries with the same prefix to resolve to the
    wrong member. This PR fixes the bug.
---
 include/tvm/ffi/reflection/accessor.h |  6 ++++--
 tests/cpp/test_reflection.cc          | 23 +++++++++++++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/include/tvm/ffi/reflection/accessor.h 
b/include/tvm/ffi/reflection/accessor.h
index 9ea14b4d..daa0f26d 100644
--- a/include/tvm/ffi/reflection/accessor.h
+++ b/include/tvm/ffi/reflection/accessor.h
@@ -43,7 +43,8 @@ inline const TVMFFIFieldInfo* GetFieldInfo(std::string_view 
type_key, const char
   TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_array, &type_index));
   const TypeInfo* info = TVMFFIGetTypeInfo(type_index);
   for (int32_t i = 0; i < info->num_fields; ++i) {
-    if (std::strncmp(info->fields[i].name.data, field_name, 
info->fields[i].name.size) == 0) {
+    if (std::strncmp(info->fields[i].name.data, field_name, 
info->fields[i].name.size) == 0 &&
+        field_name[info->fields[i].name.size] == '\0') {
       return &(info->fields[i]);
     }
   }
@@ -207,7 +208,8 @@ inline const TVMFFIMethodInfo* 
GetMethodInfo(std::string_view type_key, const ch
   TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_array, &type_index));
   const TypeInfo* info = TVMFFIGetTypeInfo(type_index);
   for (int32_t i = 0; i < info->num_methods; ++i) {
-    if (std::strncmp(info->methods[i].name.data, method_name, 
info->methods[i].name.size) == 0) {
+    if (std::strncmp(info->methods[i].name.data, method_name, 
info->methods[i].name.size) == 0 &&
+        method_name[info->methods[i].name.size] == '\0') {
       return &(info->methods[i]);
     }
   }
diff --git a/tests/cpp/test_reflection.cc b/tests/cpp/test_reflection.cc
index 711c9faf..89746fc6 100644
--- a/tests/cpp/test_reflection.cc
+++ b/tests/cpp/test_reflection.cc
@@ -62,6 +62,12 @@ struct TestObjRefADerived : public ObjectRef {
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestObjRefADerived, ObjectRef, 
TestObjADerived);
 };
 
+struct PrefixLookupObj : public Object {
+  int64_t stage;
+
+  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("test.PrefixLookup", PrefixLookupObj, 
Object);
+};
+
 TVM_FFI_STATIC_INIT_BLOCK() {
   namespace refl = tvm::ffi::reflection;
 
@@ -91,6 +97,9 @@ TVM_FFI_STATIC_INIT_BLOCK() {
   refl::ObjectDef<TestObjADerived>()
       .def(refl::init<int64_t, int64_t, int64_t>())
       .def_ro("z", &TestObjADerived::z);
+  refl::ObjectDef<PrefixLookupObj>()
+      .def_ro("stage", &PrefixLookupObj::stage)
+      .def_static("run", []() -> int64_t { return 1; });
   refl::TypeAttrDef<TestObjADerived>()
       .def("test.attr.type_attr_def.literal", "derived-literal")
       .def("test.attr.type_attr_def.string", String("derived-string"))
@@ -114,6 +123,13 @@ TEST(Reflection, FieldGetter) {
   EXPECT_EQ(getter_float(b).cast<double>(), 10.0);
 }
 
+TEST(Reflection, FieldLookupRequiresExactName) {
+  const TVMFFIFieldInfo* info = 
reflection::GetFieldInfo(PrefixLookupObj::_type_key, "stage");
+  EXPECT_EQ(std::string_view(info->name.data, info->name.size), "stage");
+
+  EXPECT_THROW(reflection::GetFieldInfo(PrefixLookupObj::_type_key, 
"stage_bytes"), Error);
+}
+
 TEST(Reflection, FieldSetter) {
   ObjectRef a = TFloat(10.0);
   reflection::FieldSetter setter("test.Float", "value");
@@ -233,6 +249,13 @@ TEST(Reflection, MethodInfo) {
   EXPECT_EQ(Bytes(info_float_sub->doc).operator std::string(), "");
 }
 
+TEST(Reflection, MethodLookupRequiresExactName) {
+  const TVMFFIMethodInfo* info = 
reflection::GetMethodInfo(PrefixLookupObj::_type_key, "run");
+  EXPECT_EQ(std::string_view(info->name.data, info->name.size), "run");
+
+  EXPECT_THROW(reflection::GetMethodInfo(PrefixLookupObj::_type_key, 
"runner"), Error);
+}
+
 TEST(Reflection, CallMethod) {
   Function static_int_add = reflection::GetMethod("test.Int", "static_add");
   EXPECT_EQ(static_int_add(TInt(1), TInt(2)).cast<TInt>()->value, 3);

Reply via email to