@@ -235,6 +235,36 @@ def test_linecol(self):
235235 self .assertEqual (str (err ),
236236 'Expecting value: line %s column %d (char %d)' %
237237 (line , col , idx ))
238+
239+ def test_reentrant_jsondecodeerror_does_not_crash (self ):
240+ import json
241+
242+ orig_json_error = json .JSONDecodeError
243+ orig_decoder_error = json .decoder .JSONDecodeError
244+
245+ class Trigger :
246+ def __call__ (self , * args ):
247+ import json as mod
248+ # Remove JSONDecodeError during construction to trigger re-entrancy
249+ if hasattr (mod , "JSONDecodeError" ):
250+ del mod .JSONDecodeError
251+ if hasattr (mod .decoder , "JSONDecodeError" ):
252+ del mod .decoder .JSONDecodeError
253+ return ValueError ("boom" )
254+
255+ hook = Trigger ()
256+ try :
257+ json .JSONDecodeError = hook
258+ json .decoder .JSONDecodeError = hook
259+
260+ # The exact exception type is not important here; the test
261+ # only verifies that we do not crash or trigger a SystemError.
262+ with self .assertRaises (Exception ):
263+ self .loads ('"\\ uZZZZ"' )
264+
265+ finally :
266+ json .JSONDecodeError = orig_json_error
267+ json .decoder .JSONDecodeError = orig_decoder_error
238268
239269class TestPyFail (TestFail , PyTest ): pass
240270class TestCFail (TestFail , CTest ): pass
0 commit comments