@@ -153,6 +153,7 @@ CBORDecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
153153 Py_INCREF (Py_None );
154154 self -> object_hook = Py_None ;
155155 self -> str_errors = PyBytes_FromString ("strict" );
156+ self -> max_depth = CBOR2_DEFAULT_MAX_DEPTH ;
156157 self -> immutable = false;
157158 self -> shared_index = -1 ;
158159 self -> decode_depth = 0 ;
@@ -170,19 +171,19 @@ CBORDecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
170171
171172
172173// CBORDecoder.__init__(self, fp=None, tag_hook=None, object_hook=None,
173- // str_errors='strict', read_size=1)
174+ // str_errors='strict', read_size=1, *, max_depth=100 )
174175int
175176CBORDecoder_init (CBORDecoderObject * self , PyObject * args , PyObject * kwargs )
176177{
177178 static char * keywords [] = {
178- "fp" , "tag_hook" , "object_hook" , "str_errors" , "read_size" , NULL
179+ "fp" , "tag_hook" , "object_hook" , "str_errors" , "read_size" , "max_depth" , NULL
179180 };
180181 PyObject * fp = NULL , * tag_hook = NULL , * object_hook = NULL ,
181182 * str_errors = NULL ;
182183 Py_ssize_t read_size = CBOR2_DEFAULT_READ_SIZE ;
183184
184- if (!PyArg_ParseTupleAndKeywords (args , kwargs , "O|OOOn " , keywords ,
185- & fp , & tag_hook , & object_hook , & str_errors , & read_size ))
185+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "O|OOOnn " , keywords ,
186+ & fp , & tag_hook , & object_hook , & str_errors , & read_size , & self -> max_depth ))
186187 return -1 ;
187188
188189 if (read_size < 1 ) {
@@ -2184,9 +2185,17 @@ decode(CBORDecoderObject *self, DecodeOptions options)
21842185 self -> shared_index = -1 ;
21852186 }
21862187
2188+ if (self -> decode_depth == self -> max_depth ) {
2189+ PyErr_Format (
2190+ _CBOR2_CBORDecodeError ,
2191+ "maximum container nesting depth (%u) exceeded" , self -> max_depth );
2192+ return NULL ;
2193+ }
2194+
21872195 if (Py_EnterRecursiveCall (" in CBORDecoder.decode" ))
21882196 return NULL ;
21892197
2198+ self -> decode_depth ++ ;
21902199 if (self -> fp_read (self , & lead .byte , 1 ) == 0 ) {
21912200 switch (lead .major ) {
21922201 case 0 : ret = decode_uint (self , lead .subtype ); break ;
@@ -2202,6 +2211,8 @@ decode(CBORDecoderObject *self, DecodeOptions options)
22022211 }
22032212
22042213 Py_LeaveRecursiveCall ();
2214+ self -> decode_depth -- ;
2215+
22052216 if (options & DECODE_IMMUTABLE )
22062217 self -> immutable = old_immutable ;
22072218 if (options & DECODE_UNSHARED )
@@ -2226,10 +2237,7 @@ PyObject *
22262237CBORDecoder_decode (CBORDecoderObject * self )
22272238{
22282239 PyObject * ret ;
2229- self -> decode_depth ++ ;
22302240 ret = decode (self , DECODE_NORMAL );
2231- self -> decode_depth -- ;
2232- assert (self -> decode_depth >= 0 );
22332241 if (self -> decode_depth == 0 ) {
22342242 clear_shareable_state (self );
22352243 }
@@ -2253,7 +2261,6 @@ CBORDecoder_decode_from_bytes(CBORDecoderObject *self, PyObject *data)
22532261 if (!buf )
22542262 return NULL ;
22552263
2256- self -> decode_depth ++ ;
22572264 save_read = self -> read ;
22582265 Py_INCREF (save_read ); // Keep alive while we use a different read method
22592266 save_read_pos = self -> read_pos ;
@@ -2273,7 +2280,6 @@ CBORDecoder_decode_from_bytes(CBORDecoderObject *self, PyObject *data)
22732280 }
22742281 Py_DECREF (save_read );
22752282 Py_DECREF (buf );
2276- self -> decode_depth -- ;
22772283 return NULL ;
22782284 }
22792285
@@ -2282,7 +2288,6 @@ CBORDecoder_decode_from_bytes(CBORDecoderObject *self, PyObject *data)
22822288 Py_XDECREF (self -> read ); // Decrement BytesIO read method
22832289 self -> read = save_read ; // Restore saved read (already has correct refcount)
22842290 Py_DECREF (buf );
2285- self -> decode_depth -- ;
22862291
22872292 if (is_nested ) {
22882293 PyMem_Free (self -> readahead );
@@ -2291,7 +2296,6 @@ CBORDecoder_decode_from_bytes(CBORDecoderObject *self, PyObject *data)
22912296 self -> read_pos = save_read_pos ;
22922297 self -> read_len = save_read_len ;
22932298
2294- assert (self -> decode_depth >= 0 );
22952299 if (self -> decode_depth == 0 ) {
22962300 clear_shareable_state (self );
22972301 }
0 commit comments