@@ -105,15 +105,24 @@ fn string_new_bound<'py>(py: Python<'py>, s: &[u8]) -> Bound<'py, PyString> {
105105 }
106106}
107107
108-
109108fn decode_dag_cbor_to_pyobject < R : Read + Seek > (
110109 py : Python ,
111110 r : & mut R ,
112- deep : usize ,
111+ depth : usize ,
113112) -> Result < PyObject > {
113+ unsafe {
114+ if depth > ffi:: Py_GetRecursionLimit ( ) as usize {
115+ PyErr :: new :: < pyo3:: exceptions:: PyRecursionError , _ > (
116+ "RecursionError: maximum recursion depth exceeded in DAG-CBOR decoding" ,
117+ ) . restore ( py) ;
118+
119+ return Err ( anyhow ! ( "Maximum recursion depth exceeded" ) ) ;
120+ }
121+ }
122+
114123 let major = decode:: read_major ( r) ?;
115124 Ok ( match major. kind ( ) {
116- MajorKind :: UnsignedInt => ( decode:: read_uint ( r, major) ?) . to_object ( py) ,
125+ MajorKind :: UnsignedInt => decode:: read_uint ( r, major) ?. to_object ( py) ,
117126 MajorKind :: NegativeInt => ( -1 - decode:: read_uint ( r, major) ? as i64 ) . to_object ( py) ,
118127 MajorKind :: ByteString => {
119128 let len = decode:: read_uint ( r, major) ?;
@@ -130,7 +139,7 @@ fn decode_dag_cbor_to_pyobject<R: Read + Seek>(
130139 let ptr = ffi:: PyList_New ( len) ;
131140
132141 for i in 0 ..len {
133- ffi:: PyList_SET_ITEM ( ptr, i, decode_dag_cbor_to_pyobject ( py, r, deep + 1 ) ?. into_ptr ( ) ) ;
142+ ffi:: PyList_SET_ITEM ( ptr, i, decode_dag_cbor_to_pyobject ( py, r, depth + 1 ) ?. into_ptr ( ) ) ;
134143 }
135144
136145 let list: Bound < ' _ , PyList > = Bound :: from_owned_ptr ( py, ptr) . downcast_into_unchecked ( ) ;
@@ -162,8 +171,8 @@ fn decode_dag_cbor_to_pyobject<R: Read + Seek>(
162171 let key_py = string_new_bound ( py, key. as_slice ( ) ) . to_object ( py) ;
163172 prev_key = Some ( key) ;
164173
165- let value = decode_dag_cbor_to_pyobject ( py, r, deep + 1 ) ?;
166- dict. set_item ( key_py, value ) . unwrap ( ) ;
174+ let value_py = decode_dag_cbor_to_pyobject ( py, r, depth + 1 ) ?;
175+ dict. set_item ( key_py, value_py ) ? ;
167176 }
168177
169178 dict. to_object ( py)
@@ -184,7 +193,7 @@ fn decode_dag_cbor_to_pyobject<R: Read + Seek>(
184193 cbor:: NULL => py. None ( ) ,
185194 cbor:: F32 => decode:: read_f32 ( r) ?. to_object ( py) ,
186195 cbor:: F64 => decode:: read_f64 ( r) ?. to_object ( py) ,
187- _ => return Err ( anyhow ! ( format! ( "Unsupported major type" ) ) ) ,
196+ _ => return Err ( anyhow ! ( "Unsupported major type" . to_string ( ) ) ) ,
188197 } ,
189198 } )
190199}
@@ -456,10 +465,20 @@ pub fn decode_dag_cbor(py: Python, data: &[u8]) -> PyResult<PyObject> {
456465 if let Ok ( py_object) = py_object {
457466 Ok ( py_object)
458467 } else {
459- Err ( get_err (
468+ let err = get_err (
460469 "Failed to decode DAG-CBOR" ,
461470 py_object. unwrap_err ( ) . to_string ( ) ,
462- ) )
471+ ) ;
472+
473+ if let Some ( py_err) = PyErr :: take ( py) {
474+ py_err. set_cause ( py, Option :: from ( err) ) ;
475+ // in case something set global interpreter’s error,
476+ // for example C FFI function, we should return it
477+ // the real case: RecursionError (set by Py_EnterRecursiveCall)
478+ Err ( py_err)
479+ } else {
480+ Err ( err)
481+ }
463482 }
464483}
465484
0 commit comments