-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-36389: Add _PyObject_CheckConsistency() function #12803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,10 @@ extern "C" { | |
|
||
#include "pycore_pystate.h" /* _PyRuntime */ | ||
|
||
PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type); | ||
PyAPI_FUNC(int) _PyUnicode_CheckConsistency(PyObject *op, int check_content); | ||
PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have a |
||
|
||
/* Tell the GC to track this object. | ||
* | ||
* NB: While the object is tracked by the collector, it must be safe to call the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
/* Generic object operations; and implementation of None */ | ||
|
||
#include "Python.h" | ||
#include "pycore_object.h" | ||
#include "pycore_pystate.h" | ||
#include "pycore_context.h" | ||
#include "frameobject.h" | ||
|
@@ -19,6 +20,28 @@ _Py_IDENTIFIER(__bytes__); | |
_Py_IDENTIFIER(__dir__); | ||
_Py_IDENTIFIER(__isabstractmethod__); | ||
|
||
|
||
int | ||
_PyObject_CheckConsistency(PyObject *op, int check_content) | ||
{ | ||
_PyObject_ASSERT(op, op != NULL); | ||
_PyObject_ASSERT(op, !_PyObject_IsFreed(op)); | ||
_PyObject_ASSERT(op, Py_REFCNT(op) >= 1); | ||
|
||
PyTypeObject *type = op->ob_type; | ||
_PyObject_ASSERT(op, type != NULL); | ||
_PyType_CheckConsistency(type); | ||
|
||
if (PyUnicode_Check(op)) { | ||
_PyUnicode_CheckConsistency(op, check_content); | ||
} | ||
else if (PyDict_Check(op)) { | ||
_PyDict_CheckConsistency(op, check_content); | ||
} | ||
return 1; | ||
} | ||
|
||
|
||
#ifdef Py_REF_DEBUG | ||
Py_ssize_t _Py_RefTotal; | ||
|
||
|
@@ -2136,7 +2159,13 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg, | |
else if (_PyObject_IsFreed(obj)) { | ||
/* It seems like the object memory has been freed: | ||
don't access it to prevent a segmentation fault. */ | ||
fprintf(stderr, "<Freed object>\n"); | ||
fprintf(stderr, "<object: freed>\n"); | ||
} | ||
else if (Py_TYPE(obj) == NULL) { | ||
fprintf(stderr, "<object: ob_type=NULL>\n"); | ||
} | ||
else if (_PyObject_IsFreed((PyObject *)Py_TYPE(obj))) { | ||
fprintf(stderr, "<object: freed type %p>\n", Py_TYPE(obj)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
else { | ||
/* Diplay the traceback where the object has been allocated. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would you write
assert(_PyObject_CheckConsistency)
if it always returns 1? Wouldn't it be better off being namedAssertConsistent
if it's going to do the assert itself?It looks like the other functions like this return 1 or 0 and the caller does the assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a practical solution to add checks in debug mode which are omitted in release mode. It's shorter than:
or
By the way, I recall that someone reported an issue when Py_DEBUG is build without assertions (with NDEBUG defined).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, got it, that makes sense. But if this is internal, why not just offer a macro that is defined to blank?
On Windows,
Py_DEBUG
is inferred from_DEBUG
, which is the opposite ofNDEBUG
by default (but I'm not totally sure which one modifiesassert
). We should definitely usePy_DEBUG
within the codebase for our own checks like this, and probably people should not set it directly? Or maybe we need to add some extra validation inPC/pyconfig.h
to fail the build if it's inconsistent. (Let's worry about this when someone files a bug, rather than here :) )