cyx-6 opened a new pull request, #709:
URL: https://github.com/apache/tvm-ffi/pull/709

   ## Motivation
   
   `Error.py_error()` attaches the FFI error object to the Python exception it 
raises:
   
   ```python
   py_error.__tvm_ffi_error__ = self
   ```
   
   `BaseException.__reduce__` includes the instance `__dict__`, so pickling an 
FFI-originated exception pickles that `Error` through `CObject.__getstate__` → 
`ToJSONGraph`. `ffi.Error` has no native creator and no `__ffi_new__` type 
attr, so this fails:
   
   ```
   TypeError: Type `ffi.Error` does not support ToJSONGraph
              (no native creator or __ffi_new__ type attr)
   ```
   
   Harnesses that ship exceptions across a process boundary lose the original 
error and report this instead. It was reported downstream against a CUDA IMA 
(error 700), where the replacement message made it look like tvm-ffi had 
suppressed a coredump — it had not; the coredump happens before the error is 
raised, and the only real defect is that the exception could not be pickled.
   
   `copy.deepcopy` hits the same path.
   
   ## Changes
   
   **`ffi.Error` now pickles by value.** An error is fully described by its 
`(kind, message, backtrace)` strings, so `Error.__reduce__` reconstructs it 
through `__init__` rather than the JSON graph. This mirrors `Device` and 
`DataType`, which already carry hand-written `__reduce__` implementations for 
the same reason.
   
   `extra_context` is intentionally dropped — it may hold arbitrary native 
payloads, and preserving it only when it happens to be serializable would make 
pickling an error depend on where the error came from.
   
   The attribute stays a live `Error` rather than degrading to `None`, because 
`set_last_ffi_error` calls `update_backtrace` on `__tvm_ffi_error__` when a 
restored exception propagates back through the FFI; a `None` there would fail 
on an unrelated `hasattr` check that is already in the code.
   
   **Clearer errors for the types that genuinely cannot pickle.** 
`ffi.Function`, `ffi.Module`, `ffi.Tensor`, and `ffi.OpaquePyObject` each wrap 
a live process resource — a code pointer, a `dlopen` handle, a device 
allocation, a `PyObject*` — and have no value representation. They are 
unchanged behaviorally, but previously surfaced the raw `ToJSONGraph` message, 
naming an internal serializer the user never called. That message is now 
translated at the `__getstate__` boundary, following CPython's own `cannot 
pickle 'X' object` convention:
   
   ```
   TypeError: cannot pickle `ffi.Function` object: it wraps a callable whose
   implementation lives in the current process
   ```
   
   Nested values name both types, since the failure is not obvious from the 
outer object (`arr[0]` returns the plain Python object, so the container looks 
picklable):
   
   ```
   TypeError: cannot pickle `ffi.OpaquePyObject` object contained in `Array`: it
   holds an opaque reference to a Python object; pickle the underlying object
   directly, or avoid storing non-FFI Python values in containers you intend to
   serialize
   ```
   
   A `TypeError` that is not the unsupported-type error propagates untouched.
   
   ## Not in scope
   
   Making `Function`/`Tensor`/`Module`/`OpaquePyObject` serializable. 
`OpaquePyObject` in particular should stay unpicklable: the only available 
encoding is embedded pickle bytes, which would make the JSON graph non-portable 
to C++ consumers, turn `from_json_graph_str` on untrusted input into arbitrary 
code execution, and break the identity guarantee (`out is foo`) that is the 
whole point of the type.
   
   ## Testing
   
   New tests in `tests/python/test_error.py` (exception and bare-`Error` pickle 
round trips, `deepcopy`, NULL handle, `extra_context` drop, and re-propagating 
a restored exception through an FFI call) and `tests/python/test_object.py` 
(message content for each unpicklable type, nested case, and a guard that the 
supported types still round-trip).
   
   Full Python suite: 2427 passed, 52 skipped, 2 xfailed. `pre-commit` clean on 
all changed files.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to