" i...">

[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 *

`