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

tqchen pushed a commit to branch refactor-s3
in repository https://gitbox.apache.org/repos/asf/tvm.git

commit 4cf015723a346de52d3535695d488bd6d5e4d72c
Author: tqchen <[email protected]>
AuthorDate: Mon May 5 17:21:05 2025 -0400

    [FFI] Update the API to use the ByteArray API
---
 ffi/CMakeLists.txt                          |  1 +
 ffi/include/tvm/ffi/c_api.h                 | 44 ++++++++-------
 ffi/include/tvm/ffi/dtype.h                 |  2 +-
 ffi/include/tvm/ffi/error.h                 | 49 ++++++++++++----
 ffi/include/tvm/ffi/function.h              | 37 +++++++-----
 ffi/include/tvm/ffi/object.h                | 38 +++++++------
 ffi/include/tvm/ffi/reflection/reflection.h | 10 ++--
 ffi/include/tvm/ffi/string.h                | 14 +++++
 ffi/src/ffi/dtype.cc                        |  4 +-
 ffi/src/ffi/error.cc                        | 87 +++++++++++++++++++++++++++++
 ffi/src/ffi/function.cc                     | 66 +++-------------------
 ffi/src/ffi/object.cc                       | 30 +++++-----
 ffi/src/ffi/traceback.cc                    | 14 +++--
 ffi/src/ffi/traceback_win.cc                |  7 ++-
 ffi/tests/cpp/test_any.cc                   | 12 ++--
 ffi/tests/cpp/test_array.cc                 |  4 +-
 ffi/tests/cpp/test_dtype.cc                 |  2 +-
 ffi/tests/cpp/test_error.cc                 | 10 ++--
 ffi/tests/cpp/test_function.cc              | 32 +++++------
 ffi/tests/cpp/test_map.cc                   |  4 +-
 ffi/tests/cpp/test_optional.cc              |  2 +-
 ffi/tests/cpp/test_rvalue_ref.cc            | 14 ++---
 ffi/tests/cpp/test_tuple.cc                 | 20 +++----
 ffi/tests/cpp/test_variant.cc               | 16 +++---
 python/tvm/ffi/cython/base.pxi              | 56 +++++++++++++------
 python/tvm/ffi/cython/dtype.pxi             |  3 +-
 python/tvm/ffi/cython/error.pxi             | 21 ++++---
 python/tvm/ffi/cython/function.pxi          |  8 ++-
 python/tvm/ffi/cython/object.pxi            |  3 +-
 python/tvm/ffi/cython/string.pxi            | 14 -----
 src/node/reflection.cc                      |  3 +-
 src/runtime/c_runtime_api.cc                |  7 ++-
 src/runtime/object_internal.h               |  3 +-
 src/target/target.cc                        | 24 ++++----
 34 files changed, 398 insertions(+), 263 deletions(-)

diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt
index ab9a3fabc3..abdc4fed05 100644
--- a/ffi/CMakeLists.txt
+++ b/ffi/CMakeLists.txt
@@ -61,6 +61,7 @@ add_library(tvm_ffi_objs OBJECT
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback.cc"
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback_win.cc"
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/object.cc"
+  "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/error.cc"
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/function.cc"
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/ndarray.cc"
   "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/dtype.cc"
diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h
index f1f5f2f049..61738d1082 100644
--- a/ffi/include/tvm/ffi/c_api.h
+++ b/ffi/include/tvm/ffi/c_api.h
@@ -217,13 +217,13 @@ typedef struct {
  */
 typedef struct {
   /*! \brief The kind of the error. */
-  const char* kind;
+  TVMFFIByteArray kind;
   /*! \brief The message of the error. */
-  const char* message;
+  TVMFFIByteArray message;
   /*!
    * \brief The traceback of the error.
    */
-  const char* traceback;
+  TVMFFIByteArray traceback;
 } TVMFFIErrorCell;
 
 /*!
@@ -288,7 +288,7 @@ typedef int (*TVMFFIFieldSetter)(void* field, const 
TVMFFIAny* value);
  */
 typedef struct {
   /*! \brief The name of the field. */
-  const char* name;
+  TVMFFIByteArray name;
   /*!
    * \brief Records the static type kind of the field.
    *
@@ -326,7 +326,7 @@ typedef struct {
  */
 typedef struct {
   /*! \brief The name of the field. */
-  const char* name;
+  TVMFFIByteArray name;
   /*!
    * \brief The method wrapped as Function
    * \note The first argument to the method is always the self.
@@ -346,7 +346,7 @@ typedef struct {
   /*! \brief number of parent types in the type hierachy. */
   int32_t type_depth;
   /*! \brief the unique type key to identify the type. */
-  const char* type_key;
+  TVMFFIByteArray type_key;
   /*! \brief Cached hash value of the type key, used for consistent structural 
hashing. */
   uint64_t type_key_hash;
   /*!
@@ -383,7 +383,7 @@ TVM_FFI_DLL int TVMFFIObjectFree(TVMFFIObjectHandle obj);
  * \param out_tindex the corresponding type index.
  * \return 0 when success, nonzero when failure happens
  */
-TVM_FFI_DLL int TVMFFITypeKeyToIndex(const char* type_key, int32_t* 
out_tindex);
+TVM_FFI_DLL int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* 
out_tindex);
 
 //-----------------------------------------------------------------------
 // Section: Function calling APIs and support API for func implementation
@@ -432,7 +432,8 @@ TVM_FFI_DLL int TVMFFIFunctionCall(TVMFFIObjectHandle func, 
TVMFFIAny* args, int
  * \param override Whether allow override already registered function.
  * \return 0 when success, nonzero when failure happens
  */
-TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle 
f, int override);
+TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const TVMFFIByteArray* name, 
TVMFFIObjectHandle f,
+                                        int override);
 
 /*!
  * \brief Get a global function.
@@ -441,7 +442,7 @@ TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const char* name, 
TVMFFIObjectHandle f,
  * \param out the result function pointer, NULL if it does not exist.
  * \return 0 when success, nonzero when failure happens
  */
-TVM_FFI_DLL int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* 
out);
+TVM_FFI_DLL int TVMFFIFunctionGetGlobal(const TVMFFIByteArray* name, 
TVMFFIObjectHandle* out);
 
 /*!
  * \brief Move the last error from the environment to result.
@@ -474,18 +475,21 @@ TVM_FFI_DLL void TVMFFIErrorSetRaisedByCStr(const char* 
kind, const char* messag
  * \param kind The kind of the error.
  * \param message The error message.
  * \param traceback The traceback of the error.
- * \param out The output Error object handle.
- * \return 0 when success, nonzero when failure happens
+ * \return The created error object handle.
+ * \note This function is different from other functions as it is used in 
error handling loop.
+ *       So we do not follow normal error handling patterns via returning 
error code.
  */
-TVM_FFI_DLL int TVMFFIErrorCreate(const char* kind, const char* message, const 
char* traceback,
-                                  TVMFFIObjectHandle* out);
+TVM_FFI_DLL TVMFFIObjectHandle TVMFFIErrorCreate(const TVMFFIByteArray* kind,
+                                                 const TVMFFIByteArray* 
message,
+                                                 const TVMFFIByteArray* 
traceback);
 
 /*!
  * \brief Update the traceback of an Error object.
  * \param obj The error handle.
  * \param traceback The traceback to update.
  */
-TVM_FFI_DLL void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const 
char* traceback);
+TVM_FFI_DLL void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj,
+                                            const TVMFFIByteArray* traceback);
 
 /*!
  * \brief Check if there are any signals raised in the surrounding env.
@@ -500,7 +504,7 @@ TVM_FFI_DLL int TVMFFIEnvCheckSignals();
  * \param symbol The symbol to register.
  * \return 0 when success, nonzero when failure happens
  */
-TVM_FFI_DLL int TVMFFIEnvRegisterCAPI(const char* name, void* symbol);
+TVM_FFI_DLL int TVMFFIEnvRegisterCAPI(const TVMFFIByteArray* name, void* 
symbol);
 
 //------------------------------------------------------------
 // Section: Type reflection support APIs
@@ -568,7 +572,7 @@ TVM_FFI_DLL int 
TVMFFINDArrayToDLPackVersioned(TVMFFIObjectHandle from,
  * \param out The output DLDataType.
  * \return 0 when success, nonzero when failure happens
  */
-TVM_FFI_DLL int TVMFFIDataTypeFromString(const char* str, DLDataType* out);
+TVM_FFI_DLL int TVMFFIDataTypeFromString(const TVMFFIByteArray* str, 
DLDataType* out);
 
 /*!
  * \brief Convert a DLDataType to a string.
@@ -598,7 +602,8 @@ TVM_FFI_DLL int TVMFFIDataTypeToString(DLDataType dtype, 
TVMFFIObjectHandle* out
  * \note filename func and lino are only used as a backup info, most cases 
they are not needed.
  *  The return value is set to const char* to be more compatible across dll 
boundaries.
  */
-TVM_FFI_DLL const char* TVMFFITraceback(const char* filename, int lineno, 
const char* func);
+TVM_FFI_DLL const TVMFFIByteArray* TVMFFITraceback(const char* filename, int 
lineno,
+                                                   const char* func);
 
 /*!
  * \brief Initialize the type info during runtime.
@@ -619,8 +624,9 @@ TVM_FFI_DLL const char* TVMFFITraceback(const char* 
filename, int lineno, const
  *
  * \return 0 if success, -1 if error occured
  */
-TVM_FFI_DLL int32_t TVMFFIGetOrAllocTypeIndex(const char* type_key, int32_t 
static_type_index,
-                                              int32_t type_depth, int32_t 
num_child_slots,
+TVM_FFI_DLL int32_t TVMFFIGetOrAllocTypeIndex(const TVMFFIByteArray* type_key,
+                                              int32_t static_type_index, 
int32_t type_depth,
+                                              int32_t num_child_slots,
                                               int32_t child_slots_can_overflow,
                                               int32_t parent_type_index);
 
diff --git a/ffi/include/tvm/ffi/dtype.h b/ffi/include/tvm/ffi/dtype.h
index 7dfb12d02a..99eb227ee1 100644
--- a/ffi/include/tvm/ffi/dtype.h
+++ b/ffi/include/tvm/ffi/dtype.h
@@ -115,7 +115,7 @@ inline const char* DLDataTypeCodeAsCStr(DLDataTypeCode 
type_code) {  // NOLINT(*
 
 inline DLDataType StringToDLDataType(const String& str) {
   DLDataType out;
-  TVM_FFI_CHECK_SAFE_CALL(TVMFFIDataTypeFromString(str.c_str(), &out));
+  TVM_FFI_CHECK_SAFE_CALL(TVMFFIDataTypeFromString(str.get(), &out));
   return out;
 }
 
diff --git a/ffi/include/tvm/ffi/error.h b/ffi/include/tvm/ffi/error.h
index a07b66cd8d..4810754f17 100644
--- a/ffi/include/tvm/ffi/error.h
+++ b/ffi/include/tvm/ffi/error.h
@@ -33,6 +33,7 @@
 #include <memory>
 #include <sstream>
 #include <string>
+#include <string_view>
 #include <utility>
 
 /*!
@@ -84,11 +85,9 @@ class ErrorObj : public Object, public TVMFFIErrorCell {
    * \brief Update the traceback of the error object.
    * \param traceback The traceback to update.
    */
-  void UpdateTraceback(const char* traceback_str) {
-    this->traceback_data_ = traceback_str;
-    this->traceback = this->traceback_data_.c_str();
-    this->what_data_ = (std::string("Traceback (most recent call last):\n") + 
this->traceback +
-                        this->kind + ": " + this->message + '\n');
+  void UpdateTraceback(const TVMFFIByteArray* traceback_str) {
+    this->traceback_data_ = std::string(traceback_str->data, 
traceback_str->size);
+    this->traceback = TVMFFIByteArray{this->traceback_data_.data(), 
this->traceback_data_.length()};
   }
 
   static constexpr const int32_t _type_index = TypeIndex::kTVMFFIError;
@@ -101,7 +100,6 @@ class ErrorObj : public Object, public TVMFFIErrorCell {
   std::string kind_data_;
   std::string message_data_;
   std::string traceback_data_;
-  std::string what_data_;
 };
 
 /*!
@@ -115,15 +113,39 @@ class Error : public ObjectRef, public std::exception {
     n->kind_data_ = std::move(kind);
     n->message_data_ = std::move(message);
     n->traceback_data_ = std::move(traceback);
-    n->kind = n->kind_data_.c_str();
-    n->message = n->message_data_.c_str();
-    n->traceback = n->traceback_data_.c_str();
-    n->what_data_ = (std::string("Traceback (most recent call last):\n") + 
n->traceback + n->kind +
-                     ": " + n->message + '\n');
+    n->kind = TVMFFIByteArray{n->kind_data_.data(), n->kind_data_.length()};
+    n->message = TVMFFIByteArray{n->message_data_.data(), 
n->message_data_.length()};
+    n->traceback = TVMFFIByteArray{n->traceback_data_.data(), 
n->traceback_data_.length()};
     data_ = std::move(n);
   }
 
-  const char* what() const noexcept(true) override { return 
get()->what_data_.c_str(); }
+  Error(std::string kind, std::string message, const TVMFFIByteArray* 
traceback)
+      : Error(kind, message, std::string(traceback->data, traceback->size)) {}
+
+  std::string kind() const {
+    ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
+    return std::string(obj->kind.data, obj->kind.size);
+  }
+
+  std::string message() const {
+    ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
+    return std::string(obj->message.data, obj->message.size);
+  }
+
+  std::string traceback() const {
+    ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
+    return std::string(obj->traceback.data, obj->traceback.size);
+  }
+
+  const char* what() const noexcept(true) override {
+    thread_local std::string what_data;
+    ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
+    what_data = (std::string("Traceback (most recent call last):\n") +
+                 std::string(obj->traceback.data, obj->traceback.size) +
+                 std::string(obj->kind.data, obj->kind.size) + std::string(": 
") +
+                 std::string(obj->message.data, obj->message.size) + '\n');
+    return what_data.c_str();
+  }
 
   TVM_FFI_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(Error, ObjectRef, ErrorObj);
 };
@@ -135,6 +157,9 @@ class ErrorBuilder {
   explicit ErrorBuilder(std::string kind, std::string traceback, bool 
log_before_throw)
       : kind_(kind), traceback_(traceback), 
log_before_throw_(log_before_throw) {}
 
+  explicit ErrorBuilder(std::string kind, const TVMFFIByteArray* traceback, 
bool log_before_throw)
+      : ErrorBuilder(kind, std::string(traceback->data, traceback->size), 
log_before_throw) {}
+
 // MSVC disable warning in error builder as it is exepected
 #ifdef _MSC_VER
 #pragma disagnostic push
diff --git a/ffi/include/tvm/ffi/function.h b/ffi/include/tvm/ffi/function.h
index e4b67e4a76..d9f8986f5a 100644
--- a/ffi/include/tvm/ffi/function.h
+++ b/ffi/include/tvm/ffi/function.h
@@ -374,9 +374,10 @@ class Function : public ObjectRef {
    * \return The global function.
    * \note This function will return std::nullopt if the function is not found.
    */
-  static std::optional<Function> GetGlobal(const char* name) {
+  static std::optional<Function> GetGlobal(std::string_view name) {
     TVMFFIObjectHandle handle;
-    TVM_FFI_CHECK_SAFE_CALL(TVMFFIFunctionGetGlobal(name, &handle));
+    TVMFFIByteArray name_arr{name.data(), name.size()};
+    TVM_FFI_CHECK_SAFE_CALL(TVMFFIFunctionGetGlobal(&name_arr, &handle));
     if (handle != nullptr) {
       return Function(
           
details::ObjectUnsafe::ObjectPtrFromOwned<Object>(static_cast<Object*>(handle)));
@@ -386,18 +387,23 @@ class Function : public ObjectRef {
   }
 
   static std::optional<Function> GetGlobal(const std::string& name) {
-    return GetGlobal(name.c_str());
+    return GetGlobal(std::string_view(name.data(), name.length()));
   }
 
-  static std::optional<Function> GetGlobal(const String& name) { return 
GetGlobal(name.c_str()); }
+  static std::optional<Function> GetGlobal(const String& name) {
+    return GetGlobal(std::string_view(name.data(), name.length()));
+  }
 
+  static std::optional<Function> GetGlobal(const char* name) {
+    return GetGlobal(std::string_view(name));
+  }
   /*!
    * \brief Get global function by name and throw an error if it is not found.
    * \param name The name of the function
    * \return The global function
    * \note This function will throw an error if the function is not found.
    */
-  static Function GetGlobalRequired(const char* name) {
+  static Function GetGlobalRequired(std::string_view name) {
     std::optional<Function> res = GetGlobal(name);
     if (!res.has_value()) {
       TVM_FFI_THROW(ValueError) << "Function " << name << " not found";
@@ -405,21 +411,25 @@ class Function : public ObjectRef {
     return res.value();
   }
 
-  static Function GetGlobalRequired(const std::string& name) {
-    return GetGlobalRequired(name.c_str());
-  }
+  static Function GetGlobalRequired(const std::string& name) { return 
GetGlobalRequired(name); }
 
-  static Function GetGlobalRequired(const String& name) { return 
GetGlobalRequired(name.c_str()); }
+  static Function GetGlobalRequired(const String& name) {
+    return GetGlobalRequired(std::string_view(name.data(), name.length()));
+  }
 
+  static Function GetGlobalRequired(const char* name) {
+    return GetGlobalRequired(std::string_view(name));
+  }
   /*!
    * \brief Set global function by name
    * \param name The name of the function
    * \param func The function
    * \param override Whether to override when there is duplication.
    */
-  static void SetGlobal(const char* name, Function func, bool override = 
false) {
+  static void SetGlobal(std::string_view name, Function func, bool override = 
false) {
+    TVMFFIByteArray name_arr{name.data(), name.size()};
     TVM_FFI_CHECK_SAFE_CALL(
-        TVMFFIFunctionSetGlobal(name, 
details::ObjectUnsafe::GetHeader(func.get()), override));
+        TVMFFIFunctionSetGlobal(&name_arr, 
details::ObjectUnsafe::GetHeader(func.get()), override));
   }
   /*!
    * \brief List all global names
@@ -876,9 +886,10 @@ class Function::Registry {
 /*!
  * \brief helper function to get type index from key
  */
-inline int32_t TypeKeyToIndex(const char* type_key) {
+inline int32_t TypeKeyToIndex(std::string_view type_key) {
   int32_t type_index;
-  TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key, &type_index));
+  TVMFFIByteArray type_key_array = {type_key.data(), type_key.size()};
+  TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_array, &type_index));
   return type_index;
 }
 
diff --git a/ffi/include/tvm/ffi/object.h b/ffi/include/tvm/ffi/object.h
index 248912e44f..e86689ebe2 100644
--- a/ffi/include/tvm/ffi/object.h
+++ b/ffi/include/tvm/ffi/object.h
@@ -64,7 +64,8 @@ struct StaticTypeKey {
  * \return the type key
  */
 inline std::string TypeIndexToTypeKey(int32_t type_index) {
-  return TVMFFIGetTypeInfo(type_index)->type_key;
+  const TypeInfo* type_info = TVMFFIGetTypeInfo(type_index);
+  return std::string(type_info->type_key.data, type_info->type_key.size);
 }
 
 namespace details {
@@ -155,7 +156,7 @@ class Object {
   std::string GetTypeKey() const {
     // the function checks that the info exists
     const TypeInfo* type_info = TVMFFIGetTypeInfo(header_.type_index);
-    return type_info->type_key;
+    return std::string(type_info->type_key.data, type_info->type_key.size);
   }
 
   /*!
@@ -174,7 +175,7 @@ class Object {
    */
   static std::string TypeIndex2Key(int32_t tindex) {
     const TypeInfo* type_info = TVMFFIGetTypeInfo(tindex);
-    return type_info->type_key;
+    return std::string(type_info->type_key.data, type_info->type_key.size);
   }
 
   bool unique() const { return use_count() == 1; }
@@ -536,19 +537,20 @@ struct ObjectPtrEqual {
 };
 
 // If dynamic type is enabled, we still need to register the runtime type of 
parent
-#define TVM_FFI_REGISTER_STATIC_TYPE_INFO(TypeName, ParentType)                
             \
-  static constexpr int32_t _type_depth = ParentType::_type_depth + 1;          
             \
-  static int32_t _GetOrAllocRuntimeTypeIndex() {                               
             \
-    static_assert(!ParentType::_type_final, "ParentType marked as final");     
             \
-    static_assert(TypeName::_type_child_slots == 0 || 
ParentType::_type_child_slots == 0 || \
-                      TypeName::_type_child_slots < 
ParentType::_type_child_slots,          \
-                  "Need to set _type_child_slots when parent specifies it.");  
             \
-    static int32_t tindex = TVMFFIGetOrAllocTypeIndex(                         
             \
-        TypeName::_type_key, TypeName::_type_index, TypeName::_type_depth,     
             \
-        TypeName::_type_child_slots, TypeName::_type_child_slots_can_overflow, 
             \
-        ParentType::_GetOrAllocRuntimeTypeIndex());                            
             \
-    return tindex;                                                             
             \
-  }                                                                            
             \
+#define TVM_FFI_REGISTER_STATIC_TYPE_INFO(TypeName, ParentType)                
               \
+  static constexpr int32_t _type_depth = ParentType::_type_depth + 1;          
               \
+  static int32_t _GetOrAllocRuntimeTypeIndex() {                               
               \
+    static_assert(!ParentType::_type_final, "ParentType marked as final");     
               \
+    static_assert(TypeName::_type_child_slots == 0 || 
ParentType::_type_child_slots == 0 ||   \
+                      TypeName::_type_child_slots < 
ParentType::_type_child_slots,            \
+                  "Need to set _type_child_slots when parent specifies it.");  
               \
+    TVMFFIByteArray type_key{TypeName::_type_key,                              
               \
+                             
std::char_traits<char>::length(TypeName::_type_key)};            \
+    static int32_t tindex = TVMFFIGetOrAllocTypeIndex(                         
               \
+        &type_key, TypeName::_type_index, TypeName::_type_depth, 
TypeName::_type_child_slots, \
+        TypeName::_type_child_slots_can_overflow, 
ParentType::_GetOrAllocRuntimeTypeIndex()); \
+    return tindex;                                                             
               \
+  }                                                                            
               \
   static inline int32_t _register_type_index = _GetOrAllocRuntimeTypeIndex()
 
 /*!
@@ -572,8 +574,10 @@ struct ObjectPtrEqual {
     static_assert(TypeName::_type_child_slots == 0 || 
ParentType::_type_child_slots == 0 ||   \
                       TypeName::_type_child_slots < 
ParentType::_type_child_slots,            \
                   "Need to set _type_child_slots when parent specifies it.");  
               \
+    TVMFFIByteArray type_key{TypeName::_type_key,                              
               \
+                             
std::char_traits<char>::length(TypeName::_type_key)};            \
     static int32_t tindex = TVMFFIGetOrAllocTypeIndex(                         
               \
-        TypeName::_type_key, -1, TypeName::_type_depth, 
TypeName::_type_child_slots,          \
+        &type_key, -1, TypeName::_type_depth, TypeName::_type_child_slots,     
               \
         TypeName::_type_child_slots_can_overflow, 
ParentType::_GetOrAllocRuntimeTypeIndex()); \
     return tindex;                                                             
               \
   }                                                                            
               \
diff --git a/ffi/include/tvm/ffi/reflection/reflection.h 
b/ffi/include/tvm/ffi/reflection/reflection.h
index 8ce2d22ddd..034ff840d4 100644
--- a/ffi/include/tvm/ffi/reflection/reflection.h
+++ b/ffi/include/tvm/ffi/reflection/reflection.h
@@ -70,7 +70,7 @@ class ReflectionDef {
   template <typename Class, typename T>
   void RegisterField(const char* name, T Class::*field_ptr, bool readonly) {
     TVMFFIFieldInfo info;
-    info.name = name;
+    info.name = TVMFFIByteArray{name, std::char_traits<char>::length(name)};
     info.field_static_type_index = TypeToFieldStaticTypeIndex<T>::value;
     // store byte offset and setter, getter
     // so the same setter can be reused for all the same type
@@ -101,12 +101,14 @@ class ReflectionDef {
 /*!
  * \brief helper function to get reflection field info by type key and field 
name
  */
-inline const TVMFFIFieldInfo* GetReflectionFieldInfo(const char* type_key, 
const char* field_name) {
+inline const TVMFFIFieldInfo* GetReflectionFieldInfo(std::string_view type_key,
+                                                     const char* field_name) {
   int32_t type_index;
-  TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key, &type_index));
+  TVMFFIByteArray type_key_array = {type_key.data(), type_key.size()};
+  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::strcmp(info->fields[i].name, field_name) == 0) {
+    if (std::strncmp(info->fields[i].name.data, field_name, 
info->fields[i].name.size) == 0) {
       return &(info->fields[i]);
     }
   }
diff --git a/ffi/include/tvm/ffi/string.h b/ffi/include/tvm/ffi/string.h
index 2fbbb551a1..1c22f10892 100644
--- a/ffi/include/tvm/ffi/string.h
+++ b/ffi/include/tvm/ffi/string.h
@@ -74,6 +74,7 @@ class StringObj : public BytesObjBase {
 };
 
 namespace details {
+
 // String moved from std::string
 // without having to trigger a copy
 template <typename Base>
@@ -233,6 +234,14 @@ class String : public ObjectRef {
   String(const char* other)  // NOLINT(*)
       : ObjectRef(details::MakeInplaceBytes<StringObj>(other, 
std::strlen(other))) {}
 
+  /*!
+   * \brief constructor from raw string
+   *
+   * \param other a char array.
+   */
+  String(const char* other, size_t size)  // NOLINT(*)
+      : ObjectRef(details::MakeInplaceBytes<StringObj>(other, size)) {}
+
   /*!
    * \brief Construct a new string object
    * \param other The std::string object to be copied
@@ -383,6 +392,11 @@ class String : public ObjectRef {
   friend String operator+(const char* lhs, const String& rhs);
 };
 
+/*! \brief Convert TVMFFIByteArray to std::string_view */
+TVM_FFI_INLINE std::string_view ToStringView(TVMFFIByteArray str) {
+  return std::string_view(str.data, str.size);
+}
+
 // const char*, requirement: not nullable, do not retain ownership
 template <int N>
 struct TypeTraits<char[N]> : public TypeTraitsBase {
diff --git a/ffi/src/ffi/dtype.cc b/ffi/src/ffi/dtype.cc
index cad38b3240..7661ab4b97 100644
--- a/ffi/src/ffi/dtype.cc
+++ b/ffi/src/ffi/dtype.cc
@@ -314,9 +314,9 @@ inline DLDataType StringViewToDLDataType_(std::string_view 
str) {
 }  // namespace ffi
 }  // namespace tvm
 
-int TVMFFIDataTypeFromString(const char* str, DLDataType* out) {
+int TVMFFIDataTypeFromString(const TVMFFIByteArray* str, DLDataType* out) {
   TVM_FFI_SAFE_CALL_BEGIN();
-  *out = tvm::ffi::StringViewToDLDataType_(std::string_view(str));
+  *out = tvm::ffi::StringViewToDLDataType_(std::string_view(str->data, 
str->size));
   TVM_FFI_SAFE_CALL_END();
 }
 
diff --git a/ffi/src/ffi/error.cc b/ffi/src/ffi/error.cc
new file mode 100644
index 0000000000..4dcfb67714
--- /dev/null
+++ b/ffi/src/ffi/error.cc
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/error.cc
+ * \brief Error handling implementation
+ */
+#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/error.h>
+
+namespace tvm {
+namespace ffi {
+
+class SafeCallContext {
+ public:
+  void SetRaised(TVMFFIObjectHandle error) {
+    last_error_ =
+        
details::ObjectUnsafe::ObjectPtrFromUnowned<ErrorObj>(static_cast<TVMFFIObject*>(error));
+  }
+
+  void SetRaisedByCstr(const char* kind, const char* message, const 
TVMFFIByteArray* traceback) {
+    Error error(kind, message, traceback);
+    last_error_ = 
details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error));
+  }
+
+  void MoveFromRaised(TVMFFIObjectHandle* result) {
+    result[0] = 
details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(last_error_));
+  }
+
+  static SafeCallContext* ThreadLocal() {
+    static thread_local SafeCallContext ctx;
+    return &ctx;
+  }
+
+ private:
+  ObjectPtr<ErrorObj> last_error_;
+};
+
+}  // namespace ffi
+}  // namespace tvm
+
+void TVMFFIErrorSetRaisedByCStr(const char* kind, const char* message) {
+  // NOTE: run traceback here to simplify the depth of tracekback
+  tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(kind, message, 
TVM_FFI_TRACEBACK_HERE);
+}
+
+void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) {
+  tvm::ffi::SafeCallContext::ThreadLocal()->SetRaised(error);
+}
+
+void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) {
+  tvm::ffi::SafeCallContext::ThreadLocal()->MoveFromRaised(result);
+}
+
+void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const TVMFFIByteArray* 
traceback) {
+  TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
+  static_cast<tvm::ffi::ErrorObj*>(reinterpret_cast<tvm::ffi::Object*>(obj))
+      ->UpdateTraceback(traceback);
+  TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorUpdateTraceback);
+}
+
+TVMFFIObjectHandle TVMFFIErrorCreate(const TVMFFIByteArray* kind, const 
TVMFFIByteArray* message,
+                                     const TVMFFIByteArray* traceback) {
+  TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
+  tvm::ffi::Error error(std::string(kind->data, kind->size),
+                        std::string(message->data, message->size),
+                        std::string(traceback->data, traceback->size));
+  TVMFFIObjectHandle out =
+      
tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error));
+  return out;
+  TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorCreate);
+}
diff --git a/ffi/src/ffi/function.cc b/ffi/src/ffi/function.cc
index f442ceb248..ed10ea59c9 100644
--- a/ffi/src/ffi/function.cc
+++ b/ffi/src/ffi/function.cc
@@ -33,31 +33,6 @@
 namespace tvm {
 namespace ffi {
 
-class SafeCallContext {
- public:
-  void SetRaised(TVMFFIObjectHandle error) {
-    last_error_ =
-        
details::ObjectUnsafe::ObjectPtrFromUnowned<ErrorObj>(static_cast<TVMFFIObject*>(error));
-  }
-
-  void SetRaisedByCstr(const char* kind, const char* message, const char* 
traceback) {
-    Error error(kind, message, traceback);
-    last_error_ = 
details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error));
-  }
-
-  void MoveFromRaised(TVMFFIObjectHandle* result) {
-    result[0] = 
details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(last_error_));
-  }
-
-  static SafeCallContext* ThreadLocal() {
-    static thread_local SafeCallContext ctx;
-    return &ctx;
-  }
-
- private:
-  ObjectPtr<ErrorObj> last_error_;
-};
-
 /*!
  * \brief Global function table.
  *
@@ -241,18 +216,20 @@ int TVMFFIAnyViewToOwnedAny(const TVMFFIAny* any_view, 
TVMFFIAny* out) {
   TVM_FFI_SAFE_CALL_END();
 }
 
-int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, int 
override) {
+int TVMFFIFunctionSetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle f, 
int override) {
   using namespace tvm::ffi;
   TVM_FFI_SAFE_CALL_BEGIN();
-  GlobalFunctionTable::Global()->Update(name, 
GetRef<Function>(static_cast<FunctionObj*>(f)),
+  String name_str(name->data, name->size);
+  GlobalFunctionTable::Global()->Update(name_str, 
GetRef<Function>(static_cast<FunctionObj*>(f)),
                                         override != 0);
   TVM_FFI_SAFE_CALL_END();
 }
 
-int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* out) {
+int TVMFFIFunctionGetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle* 
out) {
   using namespace tvm::ffi;
   TVM_FFI_SAFE_CALL_BEGIN();
-  const Function* fp = GlobalFunctionTable::Global()->Get(name);
+  String name_str(name->data, name->size);
+  const Function* fp = GlobalFunctionTable::Global()->Get(name_str);
   if (fp != nullptr) {
     tvm::ffi::Function func(*fp);
     *out = 
tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(func));
@@ -269,32 +246,6 @@ int TVMFFIFunctionCall(TVMFFIObjectHandle func, TVMFFIAny* 
args, int32_t num_arg
   return reinterpret_cast<FunctionObj*>(func)->safe_call(func, args, num_args, 
result);
 }
 
-void TVMFFIErrorSetRaisedByCStr(const char* kind, const char* message) {
-  // NOTE: run traceback here to simplify the depth of tracekback
-  tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(kind, message, 
TVM_FFI_TRACEBACK_HERE);
-}
-
-void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) {
-  tvm::ffi::SafeCallContext::ThreadLocal()->SetRaised(error);
-}
-
-void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) {
-  tvm::ffi::SafeCallContext::ThreadLocal()->MoveFromRaised(result);
-}
-
-void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const char* traceback) 
{
-  static_cast<tvm::ffi::ErrorObj*>(reinterpret_cast<tvm::ffi::Object*>(obj))
-      ->UpdateTraceback(traceback);
-}
-
-int TVMFFIErrorCreate(const char* kind, const char* message, const char* 
traceback,
-                      TVMFFIObjectHandle* out) {
-  TVM_FFI_SAFE_CALL_BEGIN();
-  tvm::ffi::Error error(kind, message, traceback);
-  *out = 
tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error));
-  TVM_FFI_SAFE_CALL_END();
-}
-
 int TVMFFIEnvCheckSignals() { return 
tvm::ffi::EnvCAPIRegistry::Global()->EnvCheckSignals(); }
 
 /*!
@@ -303,9 +254,10 @@ int TVMFFIEnvCheckSignals() { return 
tvm::ffi::EnvCAPIRegistry::Global()->EnvChe
  * \param symbol The symbol to register.
  * \return 0 when success, nonzero when failure happens
  */
-int TVMFFIEnvRegisterCAPI(const char* name, void* symbol) {
+int TVMFFIEnvRegisterCAPI(const TVMFFIByteArray* name, void* symbol) {
   TVM_FFI_SAFE_CALL_BEGIN();
-  tvm::ffi::EnvCAPIRegistry::Global()->Register(name, symbol);
+  std::string s_name(name->data, name->size);
+  tvm::ffi::EnvCAPIRegistry::Global()->Register(s_name, symbol);
   TVM_FFI_SAFE_CALL_END();
 }
 
diff --git a/ffi/src/ffi/object.cc b/ffi/src/ffi/object.cc
index de3fd04523..63ec68790e 100644
--- a/ffi/src/ffi/object.cc
+++ b/ffi/src/ffi/object.cc
@@ -86,7 +86,7 @@ class TypeTable {
       // after this line
       this->type_index = type_index;
       this->type_depth = type_depth;
-      this->type_key = this->type_key_data.c_str();
+      this->type_key = TVMFFIByteArray{this->type_key_data.data(), 
this->type_key_data.length()};
       this->type_key_hash = std::hash<std::string>()(this->type_key_data);
       this->type_acenstors = type_acenstors_data.data();
       // initialize the reflection information
@@ -121,7 +121,7 @@ class TypeTable {
         TVM_FFI_ICHECK_LT(static_type_index, type_table_.size());
         TVM_FFI_ICHECK(type_table_[static_type_index] == nullptr)
             << "Conflicting static index " << static_type_index << " between "
-            << type_table_[static_type_index]->type_key << " and " << type_key;
+            << ToStringView(type_table_[static_type_index]->type_key) << " and 
" << type_key;
         return static_type_index;
       }
       TVM_FFI_ICHECK_NOTNULL(parent);
@@ -135,7 +135,7 @@ class TypeTable {
       }
       // Step 2: allocate from overflow
       TVM_FFI_ICHECK(parent->child_slots_can_overflow)
-          << "Reach maximum number of sub-classes for " << parent->type_key;
+          << "Reach maximum number of sub-classes for " << 
ToStringView(parent->type_key);
       // allocate new entries.
       int32_t allocated_tindex = type_counter_;
       type_counter_ += num_slots;
@@ -166,9 +166,10 @@ class TypeTable {
     return allocated_tindex;
   }
 
-  int32_t TypeKeyToIndex(const std::string& type_key) {
-    auto it = type_key2index_.find(type_key);
-    TVM_FFI_ICHECK(it != type_key2index_.end()) << "Cannot find type `" << 
type_key << "`";
+  int32_t TypeKeyToIndex(const TVMFFIByteArray* type_key) {
+    std::string type_key_str(type_key->data, type_key->size);
+    auto it = type_key2index_.find(type_key_str);
+    TVM_FFI_ICHECK(it != type_key2index_.end()) << "Cannot find type `" << 
type_key_str << "`";
     return it->second;
   }
 
@@ -211,10 +212,10 @@ class TypeTable {
 
     for (const auto& ptr : type_table_) {
       if (ptr != nullptr && num_children[ptr->type_index] >= 
min_children_count) {
-        std::cerr << '[' << ptr->type_index << "]\t" << ptr->type_key;
+        std::cerr << '[' << ptr->type_index << "]\t" << 
ToStringView(ptr->type_key);
         if (ptr->type_depth != 0) {
           int32_t parent_index = ptr->type_acenstors[ptr->type_depth - 1];
-          std::cerr << "\tparent=" << type_table_[parent_index]->type_key;
+          std::cerr << "\tparent=" << 
ToStringView(type_table_[parent_index]->type_key);
         } else {
           std::cerr << "\tparent=root";
         }
@@ -260,9 +261,9 @@ class TypeTable {
     this->GetOrAllocTypeIndex(type_key, static_type_index, 0, 0, false, -1);
   }
 
-  const char* CopyString(const char* c_str) {
-    std::unique_ptr<std::string> val = std::make_unique<std::string>(c_str);
-    const char* c_val = val->c_str();
+  TVMFFIByteArray CopyString(TVMFFIByteArray str) {
+    std::unique_ptr<std::string> val = std::make_unique<std::string>(str.data, 
str.size);
+    TVMFFIByteArray c_val{val->data(), val->length()};
     string_pool_.emplace_back(std::move(val));
     return c_val;
   }
@@ -281,7 +282,7 @@ int TVMFFIObjectFree(TVMFFIObjectHandle handle) {
   TVM_FFI_SAFE_CALL_END();
 }
 
-int TVMFFITypeKeyToIndex(const char* type_key, int32_t* out_tindex) {
+int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* out_tindex) 
{
   TVM_FFI_SAFE_CALL_BEGIN();
   out_tindex[0] = tvm::ffi::TypeTable::Global()->TypeKeyToIndex(type_key);
   TVM_FFI_SAFE_CALL_END();
@@ -293,12 +294,13 @@ int TVMFFIRegisterTypeField(int32_t type_index, const 
TVMFFIFieldInfo* info) {
   TVM_FFI_SAFE_CALL_END();
 }
 
-int32_t TVMFFIGetOrAllocTypeIndex(const char* type_key, int32_t 
static_type_index,
+int32_t TVMFFIGetOrAllocTypeIndex(const TVMFFIByteArray* type_key, int32_t 
static_type_index,
                                   int32_t type_depth, int32_t num_child_slots,
                                   int32_t child_slots_can_overflow, int32_t 
parent_type_index) {
   TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
+  std::string s_type_key = std::string(type_key->data, type_key->size);
   return tvm::ffi::TypeTable::Global()->GetOrAllocTypeIndex(
-      type_key, static_type_index, type_depth, num_child_slots, 
child_slots_can_overflow,
+      s_type_key, static_type_index, type_depth, num_child_slots, 
child_slots_can_overflow,
       parent_type_index);
   TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIGetOrAllocTypeIndex);
 }
diff --git a/ffi/src/ffi/traceback.cc b/ffi/src/ffi/traceback.cc
index 7cebc37774..4c7fb25427 100644
--- a/ffi/src/ffi/traceback.cc
+++ b/ffi/src/ffi/traceback.cc
@@ -149,20 +149,26 @@ __attribute__((constructor)) void 
install_signal_handler(void) {
 }  // namespace ffi
 }  // namespace tvm
 
-const char* TVMFFITraceback(const char*, int, const char*) {
+const TVMFFIByteArray* TVMFFITraceback(const char*, int, const char*) {
   static thread_local std::string traceback_str;
+  static thread_local TVMFFIByteArray traceback_array;
   traceback_str = ::tvm::ffi::Traceback();
-  return traceback_str.c_str();
+  traceback_array.data = traceback_str.data();
+  traceback_array.size = traceback_str.size();
+  return &traceback_array;
 }
 #else
 // fallback implementation simply print out the last trace
-const char* TVMFFITraceback(const char* filename, int lineno, const char* 
func) {
+const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func) {
   static thread_local std::string traceback_str;
+  static thread_local TVMFFIByteArray traceback_array;
   std::ostringstream traceback_stream;
   // python style backtrace
   traceback_stream << "  File \"" << filename << "\", line " << lineno << ", 
in " << func << '\n';
   traceback_str = traceback_stream.str();
-  return traceback_str.c_str();
+  traceback_array.data = traceback_str.data();
+  traceback_array.size = traceback_str.size();
+  return &traceback_array;
 }
 #endif  // TVM_FFI_USE_LIBBACKTRACE
 #endif  // _MSC_VER
diff --git a/ffi/src/ffi/traceback_win.cc b/ffi/src/ffi/traceback_win.cc
index d49f9e00af..0bdb536ae5 100644
--- a/ffi/src/ffi/traceback_win.cc
+++ b/ffi/src/ffi/traceback_win.cc
@@ -122,9 +122,12 @@ std::string Traceback() {
 }  // namespace ffi
 }  // namespace tvm
 
-const char* TVMFFITraceback(const char*, int, const char*) {
+const TVMFFIByteArray* TVMFFITraceback() {
   static thread_local std::string traceback_str;
+  static thread_local TVMFFIByteArray traceback_array;
   traceback_str = ::tvm::ffi::Traceback();
-  return traceback_str.c_str();
+  traceback_array.data = traceback_str.data();
+  traceback_array.size = traceback_str.size();
+  return &traceback_array;
 }
 #endif  // _MSC_VER
diff --git a/ffi/tests/cpp/test_any.cc b/ffi/tests/cpp/test_any.cc
index 496ae9469d..816ae28e0e 100644
--- a/ffi/tests/cpp/test_any.cc
+++ b/ffi/tests/cpp/test_any.cc
@@ -39,7 +39,7 @@ TEST(Any, Int) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<int>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to `int`"), 
std::string::npos);
           throw;
@@ -70,7 +70,7 @@ TEST(Any, bool) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<bool>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to `bool`"), 
std::string::npos);
           throw;
@@ -122,7 +122,7 @@ TEST(Any, Float) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<double>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to `float`"), 
std::string::npos);
           throw;
@@ -156,7 +156,7 @@ TEST(Any, Device) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<DLDevice>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to `Device`"), 
std::string::npos);
           throw;
@@ -189,7 +189,7 @@ TEST(Any, DLTensor) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<DLTensor*>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to 
`DLTensor*`"), std::string::npos);
           throw;
@@ -253,7 +253,7 @@ TEST(Any, Object) {
         try {
           [[maybe_unused]] auto v0 = view1.cast<TFloat>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           std::cout << what;
           EXPECT_NE(what.find("Cannot convert from type `test.Int` to 
`test.Float`"),
diff --git a/ffi/tests/cpp/test_array.cc b/ffi/tests/cpp/test_array.cc
index b268cf1039..bb0b062c32 100644
--- a/ffi/tests/cpp/test_array.cc
+++ b/ffi/tests/cpp/test_array.cc
@@ -239,7 +239,7 @@ TEST(Array, AnyConvertCheck) {
         try {
           [[maybe_unused]] auto arr2 = any1.cast<Array<int>>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `Array[index 0: 
float]` to `Array<int>`"),
                     std::string::npos);
@@ -258,7 +258,7 @@ TEST(Array, AnyConvertCheck) {
         try {
           [[maybe_unused]] auto arr2 = any1.cast<Array<Array<int>>>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("`Array[index 1: Array[index 0: test.Int]]` to 
`Array<Array<int>>`"),
                     std::string::npos);
diff --git a/ffi/tests/cpp/test_dtype.cc b/ffi/tests/cpp/test_dtype.cc
index 5dce997a9a..e31df8761d 100644
--- a/ffi/tests/cpp/test_dtype.cc
+++ b/ffi/tests/cpp/test_dtype.cc
@@ -86,7 +86,7 @@ TEST(DataType, AnyConversion) {
         try {
           [[maybe_unused]] auto v0 = view0.cast<DLDataType>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `None` to 
`DataType`"), std::string::npos);
           throw;
diff --git a/ffi/tests/cpp/test_error.cc b/ffi/tests/cpp/test_error.cc
index e6e17e0a91..9938603a47 100644
--- a/ffi/tests/cpp/test_error.cc
+++ b/ffi/tests/cpp/test_error.cc
@@ -33,8 +33,8 @@ TEST(Error, Traceback) {
         try {
           ThrowRuntimeError();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->message, "test0");
-          EXPECT_STREQ(error->kind, "RuntimeError");
+          EXPECT_EQ(error.message(), "test0");
+          EXPECT_EQ(error.kind(), "RuntimeError");
           std::string what = error.what();
           EXPECT_NE(what.find("line"), std::string::npos);
           EXPECT_NE(what.find("ThrowRuntimeError"), std::string::npos);
@@ -51,7 +51,7 @@ TEST(CheckError, Traceback) {
         try {
           TVM_FFI_ICHECK_GT(2, 3);
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "InternalError");
+          EXPECT_EQ(error.kind(), "InternalError");
           std::string what = error.what();
           EXPECT_NE(what.find("line"), std::string::npos);
           EXPECT_NE(what.find("2 > 3"), std::string::npos);
@@ -64,7 +64,7 @@ TEST(CheckError, Traceback) {
 TEST(Error, AnyConvert) {
   Any any = Error("TypeError", "here", "test0");
   Optional<Error> opt_err = any.as<Error>();
-  EXPECT_STREQ(opt_err.value()->kind, "TypeError");
-  EXPECT_STREQ(opt_err.value()->message, "here");
+  EXPECT_EQ(opt_err.value().kind(), "TypeError");
+  EXPECT_EQ(opt_err.value().message(), "here");
 }
 }  // namespace
diff --git a/ffi/tests/cpp/test_function.cc b/ffi/tests/cpp/test_function.cc
index d8895da934..fbdc580f3b 100644
--- a/ffi/tests/cpp/test_function.cc
+++ b/ffi/tests/cpp/test_function.cc
@@ -84,10 +84,10 @@ TEST(Func, FromUnpacked) {
         try {
           fadd1(1.1);
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched type on argument #0 when calling: `(0: int) 
-> int`. "
-                       "Expected `int` but got `float`");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched type on argument #0 when calling: `(0: int) -> 
int`. "
+                    "Expected `int` but got `float`");
           throw;
         }
       },
@@ -99,10 +99,10 @@ TEST(Func, FromUnpacked) {
         try {
           fadd1();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched number of arguments when calling: `(0: int) 
-> int`. "
-                       "Expected 1 but got 0 arguments");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched number of arguments when calling: `(0: int) -> 
int`. "
+                    "Expected 1 but got 0 arguments");
           throw;
         }
       },
@@ -128,11 +128,11 @@ TEST(Func, FromUnpacked) {
         try {
           fpass_and_return();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched number of arguments when calling: "
-                       "`fpass_and_return(0: test.Int, 1: int, 2: AnyView) -> 
object.Function`. "
-                       "Expected 3 but got 0 arguments");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched number of arguments when calling: "
+                    "`fpass_and_return(0: test.Int, 1: int, 2: AnyView) -> 
object.Function`. "
+                    "Expected 3 but got 0 arguments");
           throw;
         }
       },
@@ -225,9 +225,9 @@ TEST(Func, ObjectRefWithFallbackTraits) {
         try {
           freturn_primexpr(TInt(1));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(
-              error->message,
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(
+              error.message(),
               "Mismatched type on argument #0 when calling: `(0: 
test.PrimExpr) -> test.PrimExpr`. "
               "Expected `test.PrimExpr` but got `test.Int`");
           throw;
diff --git a/ffi/tests/cpp/test_map.cc b/ffi/tests/cpp/test_map.cc
index aa449141be..1c43230bbc 100644
--- a/ffi/tests/cpp/test_map.cc
+++ b/ffi/tests/cpp/test_map.cc
@@ -215,7 +215,7 @@ TEST(Map, AnyConvertCheck) {
         try {
           [[maybe_unused]] auto arr2 = any1.cast<WrongMap>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(
               what.find(
@@ -232,7 +232,7 @@ TEST(Map, AnyConvertCheck) {
         try {
           [[maybe_unused]] auto arr2 = any1.cast<WrongMap2>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           EXPECT_NE(what.find("Cannot convert from type `Map[some key is int, 
V]` to "
                               "`Map<test.Number, float>`"),
diff --git a/ffi/tests/cpp/test_optional.cc b/ffi/tests/cpp/test_optional.cc
index a45a391904..256a7da8b4 100644
--- a/ffi/tests/cpp/test_optional.cc
+++ b/ffi/tests/cpp/test_optional.cc
@@ -104,7 +104,7 @@ TEST(Optional, AnyConvert_Array) {
         try {
           [[maybe_unused]] auto arr2 = 
view0.cast<Optional<Array<Array<int>>>>();
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
+          EXPECT_EQ(error.kind(), "TypeError");
           std::string what = error.what();
           std::cout << what << std::endl;
           EXPECT_NE(what.find("to `Optional<Array<Array<int>>>`"), 
std::string::npos);
diff --git a/ffi/tests/cpp/test_rvalue_ref.cc b/ffi/tests/cpp/test_rvalue_ref.cc
index d3a82c7158..ac81208d48 100644
--- a/ffi/tests/cpp/test_rvalue_ref.cc
+++ b/ffi/tests/cpp/test_rvalue_ref.cc
@@ -56,10 +56,10 @@ TEST(RValueRef, ParamChecking) {
         try {
           fadd1(RValueRef(TInt(1)));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched type on argument #0 when calling: `(0: 
test.Int) -> int`. "
-                       "Expected `test.Int` but got `ObjectRValueRef`");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched type on argument #0 when calling: `(0: 
test.Int) -> int`. "
+                    "Expected `test.Int` but got `ObjectRValueRef`");
           throw;
         }
       },
@@ -76,9 +76,9 @@ TEST(RValueRef, ParamChecking) {
         try {
           fadd2(RValueRef(Array<Any>({1, 2.2})));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(
-              error->message,
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(
+              error.message(),
               "Mismatched type on argument #0 when calling: `(0: 
RValueRef<Array<int>>) -> int`. "
               "Expected `RValueRef<Array<int>>` but got `RValueRef<Array[index 
1: float]>`");
           throw;
diff --git a/ffi/tests/cpp/test_tuple.cc b/ffi/tests/cpp/test_tuple.cc
index 02a258522c..42c8e6aacc 100644
--- a/ffi/tests/cpp/test_tuple.cc
+++ b/ffi/tests/cpp/test_tuple.cc
@@ -101,11 +101,11 @@ TEST(Tuple, FromUnpacked) {
         try {
           fadd1(Array<Any>({1.1, 2}));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched type on argument #0 when calling: `(0: 
Tuple<int, "
-                       "test.PrimExpr>) -> int`. "
-                       "Expected `Tuple<int, test.PrimExpr>` but got 
`Array[index 0: float]`");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched type on argument #0 when calling: `(0: 
Tuple<int, "
+                    "test.PrimExpr>) -> int`. "
+                    "Expected `Tuple<int, test.PrimExpr>` but got `Array[index 
0: float]`");
           throw;
         }
       },
@@ -116,11 +116,11 @@ TEST(Tuple, FromUnpacked) {
         try {
           fadd1(Array<Any>({1.1}));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched type on argument #0 when calling: `(0: 
Tuple<int, "
-                       "test.PrimExpr>) -> int`. "
-                       "Expected `Tuple<int, test.PrimExpr>` but got 
`Array[size=1]`");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched type on argument #0 when calling: `(0: 
Tuple<int, "
+                    "test.PrimExpr>) -> int`. "
+                    "Expected `Tuple<int, test.PrimExpr>` but got 
`Array[size=1]`");
           throw;
         }
       },
diff --git a/ffi/tests/cpp/test_variant.cc b/ffi/tests/cpp/test_variant.cc
index db29bdac50..94cbcd491a 100644
--- a/ffi/tests/cpp/test_variant.cc
+++ b/ffi/tests/cpp/test_variant.cc
@@ -90,9 +90,9 @@ TEST(Variant, FromUnpacked) {
         try {
           fadd1(1.1);
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(
-              error->message,
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(
+              error.message(),
               "Mismatched type on argument #0 when calling: `(0: Variant<int, 
test.Int>) -> int`. "
               "Expected `Variant<int, test.Int>` but got `float`");
           throw;
@@ -116,11 +116,11 @@ TEST(Variant, FromUnpacked) {
         try {
           fadd2(Array<Any>({1, 1.1}));
         } catch (const Error& error) {
-          EXPECT_STREQ(error->kind, "TypeError");
-          EXPECT_STREQ(error->message,
-                       "Mismatched type on argument #0 when calling: `(0: 
Array<Variant<int, "
-                       "test.Int>>) -> int`. "
-                       "Expected `Array<Variant<int, test.Int>>` but got 
`Array[index 1: float]`");
+          EXPECT_EQ(error.kind(), "TypeError");
+          EXPECT_EQ(error.message(),
+                    "Mismatched type on argument #0 when calling: `(0: 
Array<Variant<int, "
+                    "test.Int>>) -> int`. "
+                    "Expected `Array<Variant<int, test.Int>>` but got 
`Array[index 1: float]`");
           throw;
         }
       },
diff --git a/python/tvm/ffi/cython/base.pxi b/python/tvm/ffi/cython/base.pxi
index 5c04e3316a..42db97809d 100644
--- a/python/tvm/ffi/cython/base.pxi
+++ b/python/tvm/ffi/cython/base.pxi
@@ -125,9 +125,9 @@ cdef extern from "tvm/ffi/c_api.h":
         size_t size
 
     ctypedef struct TVMFFIErrorCell:
-        const char* kind
-        const char* message
-        const char* traceback
+        TVMFFIByteArray kind
+        TVMFFIByteArray message
+        TVMFFIByteArray traceback
 
     ctypedef int (*TVMFFISafeCallType)(
         void* ctx, const TVMFFIAny* args, int32_t num_args,
@@ -140,19 +140,18 @@ cdef extern from "tvm/ffi/c_api.h":
     int TVMFFIFunctionCreate(void* self, TVMFFISafeCallType safe_call,
                          void (*deleter)(void*), TVMFFIObjectHandle* out) nogil
     int TVMFFIAnyViewToOwnedAny(const TVMFFIAny* any_view, TVMFFIAny* out) 
nogil
-    int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, int 
override) nogil
-    int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* out) 
nogil
+    int TVMFFIFunctionSetGlobal(TVMFFIByteArray* name, TVMFFIObjectHandle f, 
int override) nogil
+    int TVMFFIFunctionGetGlobal(TVMFFIByteArray* name, TVMFFIObjectHandle* 
out) nogil
     void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) nogil
     void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) nogil
-    void TVMFFIErrorSetRaisedCStr(const char* kind, const char* message) nogil
-    void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle error, const char* 
traceback) nogil
-    int TVMFFIErrorCreate(const char* kind, const char* message, const char* 
traceback,
-                          TVMFFIObjectHandle* out) nogil
-    int TVMFFIEnvRegisterCAPI(const char* name, void* ptr) nogil
-    int TVMFFITypeKeyToIndex(const char* type_key, int32_t* out_tindex) nogil
-    int TVMFFIDataTypeFromString(const char* str, DLDataType* out) nogil
+    void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle error, TVMFFIByteArray* 
traceback) nogil
+    TVMFFIObjectHandle TVMFFIErrorCreate(TVMFFIByteArray* kind, 
TVMFFIByteArray* message,
+                                         TVMFFIByteArray* traceback) nogil
+    int TVMFFIEnvRegisterCAPI(TVMFFIByteArray* name, void* ptr) nogil
+    int TVMFFITypeKeyToIndex(TVMFFIByteArray* type_key, int32_t* out_tindex) 
nogil
+    int TVMFFIDataTypeFromString(TVMFFIByteArray* str, DLDataType* out) nogil
     int TVMFFIDataTypeToString(DLDataType dtype, TVMFFIObjectHandle* out) nogil
-    const char* TVMFFITraceback(const char* filename, int lineno, const char* 
func) nogil;
+    const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, 
const char* func) nogil;
     int TVMFFINDArrayFromDLPack(DLManagedTensor* src, int32_t 
require_alignment,
                                 int32_t require_contiguous, 
TVMFFIObjectHandle* out) nogil
     int TVMFFINDArrayFromDLPackVersioned(DLManagedTensorVersioned* src,
@@ -169,6 +168,24 @@ cdef extern from "tvm/ffi/c_api.h":
     DLDevice TVMFFIDLDeviceFromIntPair(int32_t device_type, int32_t device_id) 
nogil
 
 
+cdef class ByteArrayArg:
+    cdef TVMFFIByteArray cdata
+    cdef object py_data
+
+    def __cinit__(self, py_data):
+        if isinstance(py_data, bytearray):
+            py_data = bytes(py_data)
+        cdef char* data
+        cdef Py_ssize_t size
+        self.py_data = py_data
+        PyBytes_AsStringAndSize(py_data, &data, &size)
+        self.cdata.data = data
+        self.cdata.size = size
+
+    cdef inline TVMFFIByteArray* cptr(self):
+        return &self.cdata
+
+
 cdef inline py_str(const char* x):
     """Convert a c_char_p to a python string
 
@@ -180,6 +197,10 @@ cdef inline py_str(const char* x):
     return x.decode("utf-8")
 
 
+cdef inline str bytearray_to_str(const TVMFFIByteArray* x):
+    return PyBytes_FromStringAndSize(x.data, x.size).decode("utf-8")
+
+
 cdef inline c_str(pystr):
     """Create ctypes char * from a python string
 
@@ -212,8 +233,11 @@ cdef _init_env_api():
     # Initialize env api for signal handling
     # Also registers the gil state release and ensure as PyErr_CheckSignals
     # function is called with gil released and we need to regrab the gil
-    CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyErr_CheckSignals"), 
<void*>PyErr_CheckSignals))
-    CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyGILState_Ensure"), 
<void*>PyGILState_Ensure))
-    CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyGILState_Release"), 
<void*>PyGILState_Release))
+    cdef ByteArrayArg pyerr_check_signals_arg = 
ByteArrayArg(c_str("PyErr_CheckSignals"))
+    cdef ByteArrayArg pygilstate_ensure_arg = 
ByteArrayArg(c_str("PyGILState_Ensure"))
+    cdef ByteArrayArg pygilstate_release_arg = 
ByteArrayArg(c_str("PyGILState_Release"))
+    CHECK_CALL(TVMFFIEnvRegisterCAPI(pyerr_check_signals_arg.cptr(), 
<void*>PyErr_CheckSignals))
+    CHECK_CALL(TVMFFIEnvRegisterCAPI(pygilstate_ensure_arg.cptr(), 
<void*>PyGILState_Ensure))
+    CHECK_CALL(TVMFFIEnvRegisterCAPI(pygilstate_release_arg.cptr(), 
<void*>PyGILState_Release))
 
 _init_env_api()
diff --git a/python/tvm/ffi/cython/dtype.pxi b/python/tvm/ffi/cython/dtype.pxi
index ef71ea4edd..30f9f274b4 100644
--- a/python/tvm/ffi/cython/dtype.pxi
+++ b/python/tvm/ffi/cython/dtype.pxi
@@ -44,7 +44,8 @@ cdef class DataType:
     cdef DLDataType cdtype
 
     def __init__(self, dtype_str):
-        CHECK_CALL(TVMFFIDataTypeFromString(c_str(dtype_str), &(self.cdtype)))
+        cdef ByteArrayArg dtype_str_arg = ByteArrayArg(c_str(dtype_str))
+        CHECK_CALL(TVMFFIDataTypeFromString(dtype_str_arg.cptr(), 
&(self.cdtype)))
 
     def __reduce__(self):
         cls = type(self)
diff --git a/python/tvm/ffi/cython/error.pxi b/python/tvm/ffi/cython/error.pxi
index ba1d930912..73aa86572d 100644
--- a/python/tvm/ffi/cython/error.pxi
+++ b/python/tvm/ffi/cython/error.pxi
@@ -73,10 +73,12 @@ cdef class Error(Object):
     """
 
     def __init__(self, kind, message, traceback):
-        CHECK_CALL(
-            TVMFFIErrorCreate(
-                c_str(kind), c_str(message), c_str(traceback),
-                &(<Object>self).chandle))
+        cdef ByteArrayArg kind_arg = ByteArrayArg(c_str(kind))
+        cdef ByteArrayArg message_arg = ByteArrayArg(c_str(message))
+        cdef ByteArrayArg traceback_arg = ByteArrayArg(c_str(traceback))
+        (<Object>self).chandle = TVMFFIErrorCreate(
+            kind_arg.cptr(), message_arg.cptr(), traceback_arg.cptr()
+        )
 
     def update_traceback(self, traceback):
         """Update the traceback of the error
@@ -86,7 +88,8 @@ cdef class Error(Object):
         traceback : str
             The traceback to update.
         """
-        TVMFFIErrorUpdateTraceback(self.chandle, c_str(traceback))
+        cdef ByteArrayArg traceback_arg = ByteArrayArg(c_str(traceback))
+        TVMFFIErrorUpdateTraceback(self.chandle, traceback_arg.cptr())
 
     def py_error(self):
         """
@@ -100,15 +103,15 @@ cdef class Error(Object):
 
     @property
     def kind(self):
-        return py_str(TVMFFIErrorGetCellPtr(self.chandle).kind)
+        return bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).kind))
 
     @property
     def message(self):
-        return py_str(TVMFFIErrorGetCellPtr(self.chandle).message)
+        return bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).message))
 
     @property
     def traceback(self):
-        return py_str(TVMFFIErrorGetCellPtr(self.chandle).traceback)
+        return 
bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).traceback))
 
 _register_object_by_index(kTVMFFIError, Error)
 
@@ -131,7 +134,7 @@ cdef inline int set_last_ffi_error(error) except -1:
     kind = ERROR_TYPE_TO_NAME.get(type(error), "RuntimeError")
     message = error.__str__()
     py_traceback = _TRACEBACK_TO_STR(error.__traceback__)
-    c_traceback = py_str(TVMFFITraceback("<unknown>", 0, "<unknown>"))
+    c_traceback = bytearray_to_str(TVMFFITraceback("<unknown>", 0, 
"<unknown>"))
 
     # error comes from an exception thrown from C++ side
     if hasattr(error, "__tvm_ffi_error__"):
diff --git a/python/tvm/ffi/cython/function.pxi 
b/python/tvm/ffi/cython/function.pxi
index 0c97c939e5..be80023c85 100644
--- a/python/tvm/ffi/cython/function.pxi
+++ b/python/tvm/ffi/cython/function.pxi
@@ -108,7 +108,7 @@ cdef inline int make_args(tuple py_args, TVMFFIAny* out, 
list temp_args) except
             arg = ByteArrayArg(arg)
             out[i].type_index = kTVMFFIByteArrayPtr
             out[i].v_int64 = 0
-            out[i].v_ptr = &((<ByteArrayArg>arg).cdata)
+            out[i].v_ptr = (<ByteArrayArg>arg).cptr()
             temp_args.append(arg)
         elif isinstance(arg, (list, tuple, dict, ObjectGeneric)):
             arg = _FUNC_CONVERT_TO_OBJECT(arg)
@@ -218,18 +218,20 @@ def _register_global_func(name, pyfunc, override):
     cdef TVMFFIObjectHandle chandle
     cdef int c_api_ret_code
     cdef int ioverride = override
+    cdef ByteArrayArg name_arg = ByteArrayArg(c_str(name))
 
     if not isinstance(pyfunc, Function):
         pyfunc = _convert_to_ffi_func(pyfunc)
 
-    CHECK_CALL(TVMFFIFunctionSetGlobal(c_str(name), (<Object>pyfunc).chandle, 
ioverride))
+    CHECK_CALL(TVMFFIFunctionSetGlobal(name_arg.cptr(), 
(<Object>pyfunc).chandle, ioverride))
     return pyfunc
 
 
 def _get_global_func(name, allow_missing):
     cdef TVMFFIObjectHandle chandle
+    cdef ByteArrayArg name_arg = ByteArrayArg(c_str(name))
 
-    CHECK_CALL(TVMFFIFunctionGetGlobal(c_str(name), &chandle))
+    CHECK_CALL(TVMFFIFunctionGetGlobal(name_arg.cptr(), &chandle))
     if chandle != NULL:
         ret = Function.__new__(Function)
         (<Object>ret).chandle = chandle
diff --git a/python/tvm/ffi/cython/object.pxi b/python/tvm/ffi/cython/object.pxi
index c258f578b0..f971ca8f5a 100644
--- a/python/tvm/ffi/cython/object.pxi
+++ b/python/tvm/ffi/cython/object.pxi
@@ -251,7 +251,8 @@ def _register_object_by_index(int index, object cls):
 def _object_type_key_to_index(str type_key):
     """get the type index of object class"""
     cdef int32_t tidx
-    if TVMFFITypeKeyToIndex(c_str(type_key), &tidx) == 0:
+    type_key_arg = ByteArrayArg(c_str(type_key))
+    if TVMFFITypeKeyToIndex(type_key_arg.cptr(), &tidx) == 0:
         return tidx
     return None
 
diff --git a/python/tvm/ffi/cython/string.pxi b/python/tvm/ffi/cython/string.pxi
index 733ea90301..512aa7bace 100644
--- a/python/tvm/ffi/cython/string.pxi
+++ b/python/tvm/ffi/cython/string.pxi
@@ -28,20 +28,6 @@ cdef inline bytes _bytes_obj_get_py_bytes(obj):
     return PyBytes_FromStringAndSize(bytes.data, bytes.size)
 
 
-cdef class ByteArrayArg:
-    cdef TVMFFIByteArray cdata
-    cdef object py_data
-
-    def __cinit__(self, py_data):
-        if isinstance(py_data, bytearray):
-            py_data = bytes(py_data)
-        cdef char* data
-        cdef Py_ssize_t size
-        self.py_data = py_data
-        PyBytes_AsStringAndSize(py_data, &data, &size)
-        self.cdata.data = data
-        self.cdata.size = size
-
 
 class String(str, PyNativeObject):
     __slots__ = ["__tvm_ffi_object__"]
diff --git a/src/node/reflection.cc b/src/node/reflection.cc
index b49440dce3..067f4abb20 100644
--- a/src/node/reflection.cc
+++ b/src/node/reflection.cc
@@ -168,7 +168,8 @@ ReflectionVTable* ReflectionVTable::Global() {
 ObjectPtr<Object> ReflectionVTable::CreateInitObject(const std::string& 
type_key,
                                                      const std::string& 
repr_bytes) const {
   int32_t tindex;
-  TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key.c_str(), &tindex));
+  TVMFFIByteArray type_key_arr{type_key.data(), type_key.length()};
+  TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_arr, &tindex));
   if (static_cast<size_t>(tindex) >= fcreate_.size() || fcreate_[tindex] == 
nullptr) {
     LOG(FATAL) << "TypeError: " << type_key << " is not registered via 
TVM_REGISTER_NODE_TYPE";
   }
diff --git a/src/runtime/c_runtime_api.cc b/src/runtime/c_runtime_api.cc
index 542179d08b..0482f4ab70 100644
--- a/src/runtime/c_runtime_api.cc
+++ b/src/runtime/c_runtime_api.cc
@@ -434,10 +434,13 @@ void* TVMGetLastPythonError() {
 
 const char* TVMGetLastBacktrace() {
   const auto& last_error = TVMAPIRuntimeStore::Get()->last_error;
+  static thread_local std::string traceback;
   if (const auto* wrapped = std::get_if<WrappedPythonError>(&last_error)) {
-    return (*wrapped)->traceback;
+    traceback = wrapped->traceback();
+    return traceback.c_str();
   } else if (const auto* wrapped = std::get_if<InternalError>(&last_error)) {
-    return (*wrapped)->traceback;
+    traceback = wrapped->traceback();
+    return traceback.c_str();
   } else {
     return nullptr;
   }
diff --git a/src/runtime/object_internal.h b/src/runtime/object_internal.h
index 662e67e693..40e4e2fb48 100644
--- a/src/runtime/object_internal.h
+++ b/src/runtime/object_internal.h
@@ -74,7 +74,8 @@ class ObjectInternal {
    */
   static uint32_t ObjectTypeKey2Index(const std::string& type_key) {
     int32_t type_index;
-    TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key.c_str(), 
&type_index));
+    TVMFFIByteArray type_key_arr{type_key.data(), type_key.length()};
+    TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_arr, &type_index));
     return static_cast<uint32_t>(type_index);
   }
   /*!
diff --git a/src/target/target.cc b/src/target/target.cc
index 143436541e..360c56642b 100644
--- a/src/target/target.cc
+++ b/src/target/target.cc
@@ -403,7 +403,7 @@ Any TargetInternal::ParseType(const std::string& str, const 
TargetKindNode::Valu
         result.push_back(parsed);
       } catch (const Error& e) {
         std::string index = "[" + std::to_string(result.size()) + "]";
-        throw Error(e->kind, std::string(e->message) + index, e->traceback);
+        throw Error(e.kind(), e.message() + index, e.traceback());
       }
     }
     return Array<ObjectRef>(result);
@@ -449,7 +449,7 @@ Any TargetInternal::ParseType(const Any& obj, const 
TargetKindNode::ValueTypeInf
         result.push_back(TargetInternal::ParseType(e, 
*info.key).cast<ObjectRef>());
       } catch (const Error& e) {
         std::string index = '[' + std::to_string(result.size()) + ']';
-        throw Error(e->kind, index + e->message, e->traceback);
+        throw Error(e.kind(), index + e.message(), e.traceback());
       }
     }
     return Array<ObjectRef>(result);
@@ -462,14 +462,14 @@ Any TargetInternal::ParseType(const Any& obj, const 
TargetKindNode::ValueTypeInf
       try {
         key = TargetInternal::ParseType(kv.first, *info.key);
       } catch (const Error& e) {
-        throw Error(e->kind, std::string(e->message) + ", during parse key of 
map", e->traceback);
+        throw Error(e.kind(), e.message() + ", during parse key of map", 
e.traceback());
       }
       try {
         val = TargetInternal::ParseType(kv.second, *info.val);
       } catch (const Error& e) {
         std::ostringstream os;
         os << ", during parseing value of map[\"" << key << "\"]";
-        throw Error(e->kind, std::string(e->message) + os.str(), e->traceback);
+        throw Error(e.kind(), e.message() + os.str(), e.traceback());
       }
       result[key] = val;
     }
@@ -577,7 +577,7 @@ Target::Target(const String& tag_or_config_or_target_str) {
   } catch (const Error& e) {
     std::ostringstream os;
     os << ". Target creation from string failed: " << 
tag_or_config_or_target_str;
-    throw Error("ValueError", std::string(e->message) + os.str(), 
e->traceback);
+    throw Error("ValueError", e.message() + os.str(), e.traceback());
   }
   data_ = std::move(target);
 }
@@ -589,7 +589,7 @@ Target::Target(const Map<String, ffi::Any>& config) {
   } catch (const Error& e) {
     std::ostringstream os;
     os << ". Target creation from config dict failed: " << config;
-    throw Error("ValueError", std::string(e->message) + os.str(), 
e->traceback);
+    throw Error("ValueError", std::string(e.message()) + os.str(), 
e.traceback());
   }
   data_ = std::move(target);
 }
@@ -820,8 +820,8 @@ ObjectPtr<Object> TargetInternal::FromRawString(const 
String& target_str) {
       std::string s_next = (iter + 1 < options.size()) ? options[iter + 1] : 
"";
       iter += ParseKVPair(RemovePrefixDashes(options[iter]), s_next, &key, 
&value);
     } catch (const Error& e) {
-      throw Error(e->kind, std::string(e->message) + ", during parsing target 
`" + target_str + "`",
-                  e->traceback);
+      throw Error(e.kind(), e.message() + ", during parsing target `" + 
target_str + "`",
+                  e.traceback());
     }
     try {
       // check if `key` has been used
@@ -830,8 +830,8 @@ ObjectPtr<Object> TargetInternal::FromRawString(const 
String& target_str) {
       }
       config[key] = TargetInternal::ParseType(value, 
TargetInternal::FindTypeInfo(kind, key));
     } catch (const Error& e) {
-      throw Error(e->kind, std::string(e->message) + ", during parsing 
target[\"" + key + "\"]",
-                  e->traceback);
+      throw Error(e.kind(), std::string(e.message()) + ", during parsing 
target[\"" + key + "\"]",
+                  e.traceback());
     }
   }
   return TargetInternal::FromConfig(config);
@@ -937,8 +937,8 @@ ObjectPtr<Object> TargetInternal::FromConfig(Map<String, 
ffi::Any> config) {
       const TargetKindNode::ValueTypeInfo& info = 
TargetInternal::FindTypeInfo(target->kind, key);
       attrs[key] = TargetInternal::ParseType(value, info);
     } catch (const Error& e) {
-      throw Error(e->kind, std::string(e->message) + ", during parsing 
target[\"" + key + "\"]",
-                  e->traceback);
+      throw Error(e.kind(), std::string(e.message()) + ", during parsing 
target[\"" + key + "\"]",
+                  e.traceback());
     }
   }
 

Reply via email to