@@ -338,15 +338,23 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy
338
338
}
339
339
340
340
PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr (JSObjectProxy *self) {
341
- Py_ssize_t i = Py_ReprEnter ((PyObject *)self);
341
+ // Detect cyclic objects
342
+ PyObject *objPtr = PyLong_FromVoidPtr (self->jsObject ->get ());
343
+ // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject.
344
+ // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256.
345
+ // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject.
346
+ PyObject *tsDict = PyThreadState_GetDict ();
347
+ PyObject *cyclicKey = PyDict_SetDefault (tsDict, /* key*/ objPtr, /* value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr)
348
+ int i = Py_ReprEnter (cyclicKey);
342
349
if (i != 0 ) {
343
350
return i > 0 ? PyUnicode_FromString (" {...}" ) : NULL ;
344
351
}
345
352
346
353
Py_ssize_t selfLength = JSObjectProxy_length (self);
347
354
348
355
if (selfLength == 0 ) {
349
- Py_ReprLeave ((PyObject *)self);
356
+ Py_ReprLeave (cyclicKey);
357
+ PyDict_DelItem (tsDict, cyclicKey);
350
358
return PyUnicode_FromString (" {}" );
351
359
}
352
360
@@ -417,15 +425,24 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self
417
425
value = pyTypeFactory (GLOBAL_CX, elementVal);
418
426
}
419
427
420
- s = PyObject_Repr (value);
421
- if (s == NULL ) {
422
- goto error;
423
- }
428
+ if (value != NULL ) {
429
+ s = PyObject_Repr (value);
430
+ if (s == NULL ) {
431
+ goto error;
432
+ }
424
433
425
- res = _PyUnicodeWriter_WriteStr (&writer, s);
426
- Py_DECREF (s);
427
- if (res < 0 ) {
428
- goto error;
434
+ res = _PyUnicodeWriter_WriteStr (&writer, s);
435
+ Py_DECREF (s);
436
+ if (res < 0 ) {
437
+ goto error;
438
+ }
439
+ } else {
440
+ // clear any exception that was just set
441
+ PyErr_Clear ();
442
+
443
+ if (_PyUnicodeWriter_WriteASCIIString (&writer, " <cannot repr type>" , 19 ) < 0 ) {
444
+ goto error;
445
+ }
429
446
}
430
447
431
448
Py_CLEAR (key);
@@ -437,11 +454,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self
437
454
goto error;
438
455
}
439
456
440
- Py_ReprLeave ((PyObject *)self);
457
+ Py_ReprLeave (cyclicKey);
458
+ PyDict_DelItem (tsDict, cyclicKey);
441
459
return _PyUnicodeWriter_Finish (&writer);
442
460
443
461
error:
444
- Py_ReprLeave ((PyObject *)self);
462
+ Py_ReprLeave (cyclicKey);
463
+ PyDict_DelItem (tsDict, cyclicKey);
445
464
_PyUnicodeWriter_Dealloc (&writer);
446
465
Py_XDECREF (key);
447
466
Py_XDECREF (value);
0 commit comments