Skip to content

Commit 5c56fde

Browse files
authored
add critical sections around bytearray reads (#1717)
1 parent c0f4a7f commit 5c56fde

File tree

1 file changed

+25
-19
lines changed

1 file changed

+25
-19
lines changed

src/serializers/infer.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,14 @@ pub(crate) fn infer_to_python_known(
140140
.into_py_any(py)?,
141141
ObType::Bytearray => {
142142
let py_byte_array = value.downcast::<PyByteArray>()?;
143-
// Safety: the GIL is held while bytes_to_string is running; it doesn't run
144-
// arbitrary Python code, so py_byte_array cannot be mutated.
145-
let bytes = unsafe { py_byte_array.as_bytes() };
146-
extra.config.bytes_mode.bytes_to_string(py, bytes)?.into_py_any(py)?
143+
pyo3::sync::with_critical_section(py_byte_array, || {
144+
// SAFETY: `py_byte_array` is protected by a critical section,
145+
// which guarantees no mutation, and `bytes_to_string` does not
146+
// run any code which could cause the critical section to be
147+
// released.
148+
let bytes = unsafe { py_byte_array.as_bytes() };
149+
extra.config.bytes_mode.bytes_to_string(py, bytes)?.into_py_any(py)
150+
})?
147151
}
148152
ObType::Tuple => {
149153
let elements = serialize_seq_filter!(PyTuple);
@@ -432,12 +436,14 @@ pub(crate) fn infer_serialize_known<S: Serializer>(
432436
}
433437
ObType::Bytearray => {
434438
let py_byte_array = value.downcast::<PyByteArray>().map_err(py_err_se_err)?;
435-
// Safety: the GIL is held while serialize_bytes is running; it doesn't run
436-
// arbitrary Python code, so py_byte_array cannot be mutated.
437-
extra
438-
.config
439-
.bytes_mode
440-
.serialize_bytes(unsafe { py_byte_array.as_bytes() }, serializer)
439+
pyo3::sync::with_critical_section(py_byte_array, || {
440+
// SAFETY: `py_byte_array` is protected by a critical section,
441+
// which guarantees no mutation, and `serialize_bytes` does not
442+
// run any code which could cause the critical section to be
443+
// released.
444+
let bytes = unsafe { py_byte_array.as_bytes() };
445+
extra.config.bytes_mode.serialize_bytes(bytes, serializer)
446+
})
441447
}
442448
ObType::Dict => {
443449
let dict = value.downcast::<PyDict>().map_err(py_err_se_err)?;
@@ -612,15 +618,15 @@ pub(crate) fn infer_json_key_known<'a>(
612618
.bytes_to_string(key.py(), key.downcast::<PyBytes>()?.as_bytes()),
613619
ObType::Bytearray => {
614620
let py_byte_array = key.downcast::<PyByteArray>()?;
615-
// Safety: the GIL is held while serialize_bytes is running; it doesn't run
616-
// arbitrary Python code, so py_byte_array cannot be mutated during the call.
617-
//
618-
// We copy the bytes into a new buffer immediately afterwards
619-
extra
620-
.config
621-
.bytes_mode
622-
.bytes_to_string(key.py(), unsafe { py_byte_array.as_bytes() })
623-
.map(|cow| Cow::Owned(cow.into_owned()))
621+
pyo3::sync::with_critical_section(py_byte_array, || {
622+
// SAFETY: `py_byte_array` is protected by a critical section,
623+
// which guarantees no mutation, and `bytes_to_string` does not
624+
// run any code which could cause the critical section to be
625+
// released.
626+
let bytes = unsafe { py_byte_array.as_bytes() };
627+
extra.config.bytes_mode.bytes_to_string(key.py(), bytes)
628+
})
629+
.map(|cow| Cow::Owned(cow.into_owned()))
624630
}
625631
ObType::Datetime => {
626632
let iso_dt = super::type_serializers::datetime_etc::datetime_to_string(key.downcast()?)?;

0 commit comments

Comments
 (0)