[3.7] bpo-9263: _PyObject_Dump() detects freed memory (GH-10061) (GH-… · python/cpython@95036ea (original) (raw)
`@@ -411,34 +411,71 @@ _Py_BreakPoint(void)
`
411
411
`}
`
412
412
``
413
413
``
``
414
`+
/* Heuristic checking if the object memory has been deallocated.
`
``
415
`+
Rely on the debug hooks on Python memory allocators which fills the memory
`
``
416
`+
with DEADBYTE (0xDB) when memory is deallocated.
`
``
417
+
``
418
`+
The function can be used to prevent segmentation fault on dereferencing
`
``
419
`+
pointers like 0xdbdbdbdbdbdbdbdb. Such pointer is very unlikely to be mapped
`
``
420
`+
in memory. */
`
``
421
`+
int
`
``
422
`+
_PyObject_IsFreed(PyObject *op)
`
``
423
`+
{
`
``
424
`+
uintptr_t ptr = (uintptr_t)op;
`
``
425
`+
if (_PyMem_IsFreed(&ptr, sizeof(ptr))) {
`
``
426
`+
return 1;
`
``
427
`+
}
`
``
428
`+
int freed = _PyMem_IsFreed(&op->ob_type, sizeof(op->ob_type));
`
``
429
`+
/* ignore op->ob_ref: the value can have be modified
`
``
430
`+
by Py_INCREF() and Py_DECREF(). */
`
``
431
`+
#ifdef Py_TRACE_REFS
`
``
432
`+
freed &= _PyMem_IsFreed(&op->_ob_next, sizeof(op->_ob_next));
`
``
433
`+
freed &= _PyMem_IsFreed(&op->_ob_prev, sizeof(op->_ob_prev));
`
``
434
`+
#endif
`
``
435
`+
return freed;
`
``
436
`+
}
`
``
437
+
``
438
+
414
439
`/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */
`
415
440
`void
`
416
441
`_PyObject_Dump(PyObject* op)
`
417
442
`{
`
418
``
`-
if (op == NULL)
`
419
``
`-
fprintf(stderr, "NULL\n");
`
420
``
`-
else {
`
421
``
`-
PyGILState_STATE gil;
`
422
``
`-
PyObject *error_type, *error_value, *error_traceback;
`
423
``
-
424
``
`-
fprintf(stderr, "object : ");
`
425
``
`-
gil = PyGILState_Ensure();
`
426
``
-
427
``
`-
PyErr_Fetch(&error_type, &error_value, &error_traceback);
`
428
``
`-
(void)PyObject_Print(op, stderr, 0);
`
429
``
`-
PyErr_Restore(error_type, error_value, error_traceback);
`
430
``
-
431
``
`-
PyGILState_Release(gil);
`
432
``
`-
/* XXX(twouters) cast refcount to long until %zd is
`
433
``
`-
universally available */
`
434
``
`-
fprintf(stderr, "\n"
`
435
``
`-
"type : %s\n"
`
436
``
`-
"refcount: %ld\n"
`
437
``
`-
"address : %p\n",
`
438
``
`-
Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
`
439
``
`-
(long)op->ob_refcnt,
`
440
``
`-
op);
`
``
443
`+
if (op == NULL) {
`
``
444
`+
fprintf(stderr, "\n");
`
``
445
`+
fflush(stderr);
`
``
446
`+
return;
`
``
447
`+
}
`
``
448
+
``
449
`+
if (_PyObject_IsFreed(op)) {
`
``
450
`+
/* It seems like the object memory has been freed:
`
``
451
`+
don't access it to prevent a segmentation fault. */
`
``
452
`+
fprintf(stderr, "\n");
`
``
453
`+
return;
`
441
454
` }
`
``
455
+
``
456
`+
PyGILState_STATE gil;
`
``
457
`+
PyObject *error_type, *error_value, *error_traceback;
`
``
458
+
``
459
`+
fprintf(stderr, "object : ");
`
``
460
`+
fflush(stderr);
`
``
461
`+
gil = PyGILState_Ensure();
`
``
462
+
``
463
`+
PyErr_Fetch(&error_type, &error_value, &error_traceback);
`
``
464
`+
(void)PyObject_Print(op, stderr, 0);
`
``
465
`+
fflush(stderr);
`
``
466
`+
PyErr_Restore(error_type, error_value, error_traceback);
`
``
467
+
``
468
`+
PyGILState_Release(gil);
`
``
469
`+
/* XXX(twouters) cast refcount to long until %zd is
`
``
470
`+
universally available */
`
``
471
`+
fprintf(stderr, "\n"
`
``
472
`+
"type : %s\n"
`
``
473
`+
"refcount: %ld\n"
`
``
474
`+
"address : %p\n",
`
``
475
`+
Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
`
``
476
`+
(long)op->ob_refcnt,
`
``
477
`+
op);
`
``
478
`+
fflush(stderr);
`
442
479
`}
`
443
480
``
444
481
`PyObject *
`