diff --git a/capnp/helpers/capabilityHelper.cpp b/capnp/helpers/capabilityHelper.cpp index 43a4c2c..5a0a3db 100644 --- a/capnp/helpers/capabilityHelper.cpp +++ b/capnp/helpers/capabilityHelper.cpp @@ -16,6 +16,9 @@ void c_reraise_kj_exception() { } catch (kj::Exception& exn) { auto obj = wrap_kj_exception_for_reraise(exn); + if (obj == nullptr) { + return; + } PyErr_SetObject((PyObject*)obj->ob_type, obj); Py_DECREF(obj); } diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index a6eddb0..538c46f 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -288,8 +288,8 @@ cdef api object wrap_kj_exception(capnp.Exception & exception) with gil: cdef api object wrap_kj_exception_for_reraise(capnp.Exception & exception) with gil: + PyErr_Clear() wrapper = _KjExceptionWrapper()._init(exception) - ret = KjException(wrapper=wrapper) return ret diff --git a/test/test_serialization.py b/test/test_serialization.py index 6c4bfa5..285edcf 100644 --- a/test/test_serialization.py +++ b/test/test_serialization.py @@ -252,3 +252,22 @@ def test_from_bytes_packed_traversal_limit(all_types): msg = all_types.TestAllTypes.from_bytes_packed(data, traversal_limit_in_words=2**62) for i in range(0, size): assert msg.structList[i].uInt8Field == 0 + +def test_malformed_text_field_reraise(): + SCHEMA = "@0xdbb9ad1f14bf0b36;\nstruct Person { name @0 :Text; age @1 :UInt32; }\n" + with tempfile.NamedTemporaryFile(suffix=".capnp", mode="w", delete=False) as f: + f.write(SCHEMA) + + Person = capnp.load(f.name).Person + + # Create valid payload and corrupt the NUL terminator + buf = bytearray(Person.new_message(name="alice", age=30).to_bytes()) + buf[37] ^= 0xFF + + # The process should raise an exception, not SIGSEGV + try: + with Person.from_bytes(bytes(buf), traversal_limit_in_words=2**20) as r: + _ = str(r.name) + except Exception as e: + # Success: We caught an exception cleanly + pass