mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00
bpo-36389: Add _PyObject_CheckConsistency() function (GH-12803)
Add a new _PyObject_CheckConsistency() function which can be used to help debugging. The function is available in release mode. Add a 'check_content' parameter to _PyDict_CheckConsistency().
This commit is contained in:
parent
23a683adf8
commit
0fc91eef34
6 changed files with 160 additions and 116 deletions
|
@ -446,6 +446,21 @@ PyAPI_FUNC(void) _PyObject_AssertFailed(
|
||||||
int line,
|
int line,
|
||||||
const char *function);
|
const char *function);
|
||||||
|
|
||||||
|
/* Check if an object is consistent. For example, ensure that the reference
|
||||||
|
counter is greater than or equal to 1, and ensure that ob_type is not NULL.
|
||||||
|
|
||||||
|
Call _PyObject_AssertFailed() if the object is inconsistent.
|
||||||
|
|
||||||
|
If check_content is zero, only check header fields: reduce the overhead.
|
||||||
|
|
||||||
|
The function always return 1. The return value is just here to be able to
|
||||||
|
write:
|
||||||
|
|
||||||
|
assert(_PyObject_CheckConsistency(obj, 1)); */
|
||||||
|
PyAPI_FUNC(int) _PyObject_CheckConsistency(
|
||||||
|
PyObject *op,
|
||||||
|
int check_content);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,10 @@ extern "C" {
|
||||||
|
|
||||||
#include "pycore_pystate.h" /* _PyRuntime */
|
#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);
|
||||||
|
|
||||||
/* Tell the GC to track this object.
|
/* Tell the GC to track this object.
|
||||||
*
|
*
|
||||||
* NB: While the object is tracked by the collector, it must be safe to call the
|
* NB: While the object is tracked by the collector, it must be safe to call the
|
||||||
|
|
|
@ -449,77 +449,77 @@ static PyObject *empty_values[1] = { NULL };
|
||||||
/* Uncomment to check the dict content in _PyDict_CheckConsistency() */
|
/* Uncomment to check the dict content in _PyDict_CheckConsistency() */
|
||||||
/* #define DEBUG_PYDICT */
|
/* #define DEBUG_PYDICT */
|
||||||
|
|
||||||
|
#ifdef DEBUG_PYDICT
|
||||||
|
# define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 1))
|
||||||
|
#else
|
||||||
|
# define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 0))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static int
|
int
|
||||||
_PyDict_CheckConsistency(PyDictObject *mp)
|
_PyDict_CheckConsistency(PyObject *op, int check_content)
|
||||||
{
|
{
|
||||||
#define ASSERT(expr) _PyObject_ASSERT((PyObject *)mp, (expr))
|
_PyObject_ASSERT(op, PyDict_Check(op));
|
||||||
|
PyDictObject *mp = (PyDictObject *)op;
|
||||||
|
|
||||||
PyDictKeysObject *keys = mp->ma_keys;
|
PyDictKeysObject *keys = mp->ma_keys;
|
||||||
int splitted = _PyDict_HasSplitTable(mp);
|
int splitted = _PyDict_HasSplitTable(mp);
|
||||||
Py_ssize_t usable = USABLE_FRACTION(keys->dk_size);
|
Py_ssize_t usable = USABLE_FRACTION(keys->dk_size);
|
||||||
#ifdef DEBUG_PYDICT
|
|
||||||
PyDictKeyEntry *entries = DK_ENTRIES(keys);
|
|
||||||
Py_ssize_t i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ASSERT(0 <= mp->ma_used && mp->ma_used <= usable);
|
_PyObject_ASSERT(op, 0 <= mp->ma_used && mp->ma_used <= usable);
|
||||||
ASSERT(IS_POWER_OF_2(keys->dk_size));
|
_PyObject_ASSERT(op, IS_POWER_OF_2(keys->dk_size));
|
||||||
ASSERT(0 <= keys->dk_usable
|
_PyObject_ASSERT(op, 0 <= keys->dk_usable && keys->dk_usable <= usable);
|
||||||
&& keys->dk_usable <= usable);
|
_PyObject_ASSERT(op, 0 <= keys->dk_nentries && keys->dk_nentries <= usable);
|
||||||
ASSERT(0 <= keys->dk_nentries
|
_PyObject_ASSERT(op, keys->dk_usable + keys->dk_nentries <= usable);
|
||||||
&& keys->dk_nentries <= usable);
|
|
||||||
ASSERT(keys->dk_usable + keys->dk_nentries <= usable);
|
|
||||||
|
|
||||||
if (!splitted) {
|
if (!splitted) {
|
||||||
/* combined table */
|
/* combined table */
|
||||||
ASSERT(keys->dk_refcnt == 1);
|
_PyObject_ASSERT(op, keys->dk_refcnt == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_PYDICT
|
if (check_content) {
|
||||||
for (i=0; i < keys->dk_size; i++) {
|
PyDictKeyEntry *entries = DK_ENTRIES(keys);
|
||||||
Py_ssize_t ix = dictkeys_get_index(keys, i);
|
Py_ssize_t i;
|
||||||
ASSERT(DKIX_DUMMY <= ix && ix <= usable);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0; i < usable; i++) {
|
for (i=0; i < keys->dk_size; i++) {
|
||||||
PyDictKeyEntry *entry = &entries[i];
|
Py_ssize_t ix = dictkeys_get_index(keys, i);
|
||||||
PyObject *key = entry->me_key;
|
_PyObject_ASSERT(op, DKIX_DUMMY <= ix && ix <= usable);
|
||||||
|
}
|
||||||
|
|
||||||
if (key != NULL) {
|
for (i=0; i < usable; i++) {
|
||||||
if (PyUnicode_CheckExact(key)) {
|
PyDictKeyEntry *entry = &entries[i];
|
||||||
Py_hash_t hash = ((PyASCIIObject *)key)->hash;
|
PyObject *key = entry->me_key;
|
||||||
ASSERT(hash != -1);
|
|
||||||
ASSERT(entry->me_hash == hash);
|
if (key != NULL) {
|
||||||
|
if (PyUnicode_CheckExact(key)) {
|
||||||
|
Py_hash_t hash = ((PyASCIIObject *)key)->hash;
|
||||||
|
_PyObject_ASSERT(op, hash != -1);
|
||||||
|
_PyObject_ASSERT(op, entry->me_hash == hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* test_dict fails if PyObject_Hash() is called again */
|
||||||
|
_PyObject_ASSERT(op, entry->me_hash != -1);
|
||||||
|
}
|
||||||
|
if (!splitted) {
|
||||||
|
_PyObject_ASSERT(op, entry->me_value != NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* test_dict fails if PyObject_Hash() is called again */
|
if (splitted) {
|
||||||
ASSERT(entry->me_hash != -1);
|
_PyObject_ASSERT(op, entry->me_value == NULL);
|
||||||
}
|
|
||||||
if (!splitted) {
|
|
||||||
ASSERT(entry->me_value != NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splitted) {
|
if (splitted) {
|
||||||
ASSERT(entry->me_value == NULL);
|
/* splitted table */
|
||||||
|
for (i=0; i < mp->ma_used; i++) {
|
||||||
|
_PyObject_ASSERT(op, mp->ma_values[i] != NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splitted) {
|
|
||||||
/* splitted table */
|
|
||||||
for (i=0; i < mp->ma_used; i++) {
|
|
||||||
ASSERT(mp->ma_values[i] != NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#undef ASSERT
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static PyDictKeysObject *new_keys_object(Py_ssize_t size)
|
static PyDictKeysObject *new_keys_object(Py_ssize_t size)
|
||||||
|
@ -614,7 +614,7 @@ new_dict(PyDictKeysObject *keys, PyObject **values)
|
||||||
mp->ma_values = values;
|
mp->ma_values = values;
|
||||||
mp->ma_used = 0;
|
mp->ma_used = 0;
|
||||||
mp->ma_version_tag = DICT_NEXT_VERSION();
|
mp->ma_version_tag = DICT_NEXT_VERSION();
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
return (PyObject *)mp;
|
return (PyObject *)mp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,7 +675,7 @@ clone_combined_dict(PyDictObject *orig)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
new->ma_used = orig->ma_used;
|
new->ma_used = orig->ma_used;
|
||||||
assert(_PyDict_CheckConsistency(new));
|
ASSERT_CONSISTENT(new);
|
||||||
if (_PyObject_GC_IS_TRACKED(orig)) {
|
if (_PyObject_GC_IS_TRACKED(orig)) {
|
||||||
/* Maintain tracking. */
|
/* Maintain tracking. */
|
||||||
_PyObject_GC_TRACK(new);
|
_PyObject_GC_TRACK(new);
|
||||||
|
@ -1075,7 +1075,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
|
||||||
mp->ma_keys->dk_usable--;
|
mp->ma_keys->dk_usable--;
|
||||||
mp->ma_keys->dk_nentries++;
|
mp->ma_keys->dk_nentries++;
|
||||||
assert(mp->ma_keys->dk_usable >= 0);
|
assert(mp->ma_keys->dk_usable >= 0);
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1094,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
|
||||||
|
|
||||||
mp->ma_version_tag = DICT_NEXT_VERSION();
|
mp->ma_version_tag = DICT_NEXT_VERSION();
|
||||||
Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
|
Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1582,7 +1582,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
|
||||||
Py_DECREF(old_key);
|
Py_DECREF(old_key);
|
||||||
Py_DECREF(old_value);
|
Py_DECREF(old_value);
|
||||||
|
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1722,7 +1722,7 @@ PyDict_Clear(PyObject *op)
|
||||||
assert(oldkeys->dk_refcnt == 1);
|
assert(oldkeys->dk_refcnt == 1);
|
||||||
dictkeys_decref(oldkeys);
|
dictkeys_decref(oldkeys);
|
||||||
}
|
}
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal version of PyDict_Next that returns a hash value in addition
|
/* Internal version of PyDict_Next that returns a hash value in addition
|
||||||
|
@ -1852,7 +1852,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d
|
||||||
ep->me_value = NULL;
|
ep->me_value = NULL;
|
||||||
Py_DECREF(old_key);
|
Py_DECREF(old_key);
|
||||||
|
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2434,7 +2434,7 @@ PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
assert(_PyDict_CheckConsistency((PyDictObject *)d));
|
ASSERT_CONSISTENT(d);
|
||||||
goto Return;
|
goto Return;
|
||||||
Fail:
|
Fail:
|
||||||
Py_XDECREF(item);
|
Py_XDECREF(item);
|
||||||
|
@ -2586,7 +2586,7 @@ dict_merge(PyObject *a, PyObject *b, int override)
|
||||||
/* Iterator completed, via error */
|
/* Iterator completed, via error */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
assert(_PyDict_CheckConsistency((PyDictObject *)a));
|
ASSERT_CONSISTENT(a);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2950,7 +2950,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
|
||||||
mp->ma_version_tag = DICT_NEXT_VERSION();
|
mp->ma_version_tag = DICT_NEXT_VERSION();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
ASSERT_CONSISTENT(mp);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3069,7 +3069,7 @@ dict_popitem_impl(PyDictObject *self)
|
||||||
self->ma_keys->dk_nentries = i;
|
self->ma_keys->dk_nentries = i;
|
||||||
self->ma_used--;
|
self->ma_used--;
|
||||||
self->ma_version_tag = DICT_NEXT_VERSION();
|
self->ma_version_tag = DICT_NEXT_VERSION();
|
||||||
assert(_PyDict_CheckConsistency(self));
|
ASSERT_CONSISTENT(self);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3275,7 +3275,7 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
assert(_PyDict_CheckConsistency(d));
|
ASSERT_CONSISTENT(d);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/* Generic object operations; and implementation of None */
|
/* Generic object operations; and implementation of None */
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "pycore_object.h"
|
||||||
#include "pycore_pystate.h"
|
#include "pycore_pystate.h"
|
||||||
#include "pycore_context.h"
|
#include "pycore_context.h"
|
||||||
#include "frameobject.h"
|
#include "frameobject.h"
|
||||||
|
@ -19,6 +20,28 @@ _Py_IDENTIFIER(__bytes__);
|
||||||
_Py_IDENTIFIER(__dir__);
|
_Py_IDENTIFIER(__dir__);
|
||||||
_Py_IDENTIFIER(__isabstractmethod__);
|
_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
|
#ifdef Py_REF_DEBUG
|
||||||
Py_ssize_t _Py_RefTotal;
|
Py_ssize_t _Py_RefTotal;
|
||||||
|
|
||||||
|
@ -2136,7 +2159,13 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg,
|
||||||
else if (_PyObject_IsFreed(obj)) {
|
else if (_PyObject_IsFreed(obj)) {
|
||||||
/* It seems like the object memory has been freed:
|
/* It seems like the object memory has been freed:
|
||||||
don't access it to prevent a segmentation fault. */
|
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));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Diplay the traceback where the object has been allocated.
|
/* Diplay the traceback where the object has been allocated.
|
||||||
|
|
|
@ -131,8 +131,7 @@ skip_signature(const char *doc)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
int
|
||||||
static int
|
|
||||||
_PyType_CheckConsistency(PyTypeObject *type)
|
_PyType_CheckConsistency(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
#define ASSERT(expr) _PyObject_ASSERT((PyObject *)type, (expr))
|
#define ASSERT(expr) _PyObject_ASSERT((PyObject *)type, (expr))
|
||||||
|
@ -142,14 +141,16 @@ _PyType_CheckConsistency(PyTypeObject *type)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(!(type->tp_flags & Py_TPFLAGS_READYING));
|
ASSERT(!_PyObject_IsFreed((PyObject *)type));
|
||||||
ASSERT(type->tp_mro != NULL && PyTuple_Check(type->tp_mro));
|
ASSERT(Py_REFCNT(type) >= 1);
|
||||||
ASSERT(type->tp_dict != NULL);
|
ASSERT(PyType_Check(type));
|
||||||
return 1;
|
|
||||||
|
|
||||||
|
ASSERT(!(type->tp_flags & Py_TPFLAGS_READYING));
|
||||||
|
ASSERT(type->tp_dict != NULL);
|
||||||
|
|
||||||
|
return 1;
|
||||||
#undef ASSERT
|
#undef ASSERT
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
_PyType_DocWithoutSignature(const char *name, const char *internal_doc)
|
_PyType_DocWithoutSignature(const char *name, const char *internal_doc)
|
||||||
|
|
|
@ -401,23 +401,20 @@ PyUnicode_GetMax(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Py_DEBUG
|
|
||||||
int
|
int
|
||||||
_PyUnicode_CheckConsistency(PyObject *op, int check_content)
|
_PyUnicode_CheckConsistency(PyObject *op, int check_content)
|
||||||
{
|
{
|
||||||
#define ASSERT(expr) _PyObject_ASSERT(op, (expr))
|
|
||||||
|
|
||||||
PyASCIIObject *ascii;
|
PyASCIIObject *ascii;
|
||||||
unsigned int kind;
|
unsigned int kind;
|
||||||
|
|
||||||
ASSERT(PyUnicode_Check(op));
|
_PyObject_ASSERT(op, PyUnicode_Check(op));
|
||||||
|
|
||||||
ascii = (PyASCIIObject *)op;
|
ascii = (PyASCIIObject *)op;
|
||||||
kind = ascii->state.kind;
|
kind = ascii->state.kind;
|
||||||
|
|
||||||
if (ascii->state.ascii == 1 && ascii->state.compact == 1) {
|
if (ascii->state.ascii == 1 && ascii->state.compact == 1) {
|
||||||
ASSERT(kind == PyUnicode_1BYTE_KIND);
|
_PyObject_ASSERT(op, kind == PyUnicode_1BYTE_KIND);
|
||||||
ASSERT(ascii->state.ready == 1);
|
_PyObject_ASSERT(op, ascii->state.ready == 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyCompactUnicodeObject *compact = (PyCompactUnicodeObject *)op;
|
PyCompactUnicodeObject *compact = (PyCompactUnicodeObject *)op;
|
||||||
|
@ -425,41 +422,41 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
|
||||||
|
|
||||||
if (ascii->state.compact == 1) {
|
if (ascii->state.compact == 1) {
|
||||||
data = compact + 1;
|
data = compact + 1;
|
||||||
ASSERT(kind == PyUnicode_1BYTE_KIND
|
_PyObject_ASSERT(op, kind == PyUnicode_1BYTE_KIND
|
||||||
|| kind == PyUnicode_2BYTE_KIND
|
|| kind == PyUnicode_2BYTE_KIND
|
||||||
|| kind == PyUnicode_4BYTE_KIND);
|
|| kind == PyUnicode_4BYTE_KIND);
|
||||||
ASSERT(ascii->state.ascii == 0);
|
_PyObject_ASSERT(op, ascii->state.ascii == 0);
|
||||||
ASSERT(ascii->state.ready == 1);
|
_PyObject_ASSERT(op, ascii->state.ready == 1);
|
||||||
ASSERT (compact->utf8 != data);
|
_PyObject_ASSERT(op, compact->utf8 != data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyUnicodeObject *unicode = (PyUnicodeObject *)op;
|
PyUnicodeObject *unicode = (PyUnicodeObject *)op;
|
||||||
|
|
||||||
data = unicode->data.any;
|
data = unicode->data.any;
|
||||||
if (kind == PyUnicode_WCHAR_KIND) {
|
if (kind == PyUnicode_WCHAR_KIND) {
|
||||||
ASSERT(ascii->length == 0);
|
_PyObject_ASSERT(op, ascii->length == 0);
|
||||||
ASSERT(ascii->hash == -1);
|
_PyObject_ASSERT(op, ascii->hash == -1);
|
||||||
ASSERT(ascii->state.compact == 0);
|
_PyObject_ASSERT(op, ascii->state.compact == 0);
|
||||||
ASSERT(ascii->state.ascii == 0);
|
_PyObject_ASSERT(op, ascii->state.ascii == 0);
|
||||||
ASSERT(ascii->state.ready == 0);
|
_PyObject_ASSERT(op, ascii->state.ready == 0);
|
||||||
ASSERT(ascii->state.interned == SSTATE_NOT_INTERNED);
|
_PyObject_ASSERT(op, ascii->state.interned == SSTATE_NOT_INTERNED);
|
||||||
ASSERT(ascii->wstr != NULL);
|
_PyObject_ASSERT(op, ascii->wstr != NULL);
|
||||||
ASSERT(data == NULL);
|
_PyObject_ASSERT(op, data == NULL);
|
||||||
ASSERT(compact->utf8 == NULL);
|
_PyObject_ASSERT(op, compact->utf8 == NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ASSERT(kind == PyUnicode_1BYTE_KIND
|
_PyObject_ASSERT(op, kind == PyUnicode_1BYTE_KIND
|
||||||
|| kind == PyUnicode_2BYTE_KIND
|
|| kind == PyUnicode_2BYTE_KIND
|
||||||
|| kind == PyUnicode_4BYTE_KIND);
|
|| kind == PyUnicode_4BYTE_KIND);
|
||||||
ASSERT(ascii->state.compact == 0);
|
_PyObject_ASSERT(op, ascii->state.compact == 0);
|
||||||
ASSERT(ascii->state.ready == 1);
|
_PyObject_ASSERT(op, ascii->state.ready == 1);
|
||||||
ASSERT(data != NULL);
|
_PyObject_ASSERT(op, data != NULL);
|
||||||
if (ascii->state.ascii) {
|
if (ascii->state.ascii) {
|
||||||
ASSERT (compact->utf8 == data);
|
_PyObject_ASSERT(op, compact->utf8 == data);
|
||||||
ASSERT (compact->utf8_length == ascii->length);
|
_PyObject_ASSERT(op, compact->utf8_length == ascii->length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ASSERT (compact->utf8 != data);
|
_PyObject_ASSERT(op, compact->utf8 != data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (kind != PyUnicode_WCHAR_KIND) {
|
if (kind != PyUnicode_WCHAR_KIND) {
|
||||||
|
@ -471,20 +468,20 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ASSERT(ascii->wstr == data);
|
_PyObject_ASSERT(op, ascii->wstr == data);
|
||||||
ASSERT(compact->wstr_length == ascii->length);
|
_PyObject_ASSERT(op, compact->wstr_length == ascii->length);
|
||||||
} else
|
} else
|
||||||
ASSERT(ascii->wstr != data);
|
_PyObject_ASSERT(op, ascii->wstr != data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compact->utf8 == NULL)
|
if (compact->utf8 == NULL)
|
||||||
ASSERT(compact->utf8_length == 0);
|
_PyObject_ASSERT(op, compact->utf8_length == 0);
|
||||||
if (ascii->wstr == NULL)
|
if (ascii->wstr == NULL)
|
||||||
ASSERT(compact->wstr_length == 0);
|
_PyObject_ASSERT(op, compact->wstr_length == 0);
|
||||||
}
|
}
|
||||||
/* check that the best kind is used */
|
|
||||||
if (check_content && kind != PyUnicode_WCHAR_KIND)
|
/* check that the best kind is used: O(n) operation */
|
||||||
{
|
if (check_content && kind != PyUnicode_WCHAR_KIND) {
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
Py_UCS4 maxchar = 0;
|
Py_UCS4 maxchar = 0;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -499,27 +496,25 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
|
||||||
}
|
}
|
||||||
if (kind == PyUnicode_1BYTE_KIND) {
|
if (kind == PyUnicode_1BYTE_KIND) {
|
||||||
if (ascii->state.ascii == 0) {
|
if (ascii->state.ascii == 0) {
|
||||||
ASSERT(maxchar >= 128);
|
_PyObject_ASSERT(op, maxchar >= 128);
|
||||||
ASSERT(maxchar <= 255);
|
_PyObject_ASSERT(op, maxchar <= 255);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ASSERT(maxchar < 128);
|
_PyObject_ASSERT(op, maxchar < 128);
|
||||||
}
|
}
|
||||||
else if (kind == PyUnicode_2BYTE_KIND) {
|
else if (kind == PyUnicode_2BYTE_KIND) {
|
||||||
ASSERT(maxchar >= 0x100);
|
_PyObject_ASSERT(op, maxchar >= 0x100);
|
||||||
ASSERT(maxchar <= 0xFFFF);
|
_PyObject_ASSERT(op, maxchar <= 0xFFFF);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ASSERT(maxchar >= 0x10000);
|
_PyObject_ASSERT(op, maxchar >= 0x10000);
|
||||||
ASSERT(maxchar <= MAX_UNICODE);
|
_PyObject_ASSERT(op, maxchar <= MAX_UNICODE);
|
||||||
}
|
}
|
||||||
ASSERT(PyUnicode_READ(kind, data, ascii->length) == 0);
|
_PyObject_ASSERT(op, PyUnicode_READ(kind, data, ascii->length) == 0);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#undef ASSERT
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
unicode_result_wchar(PyObject *unicode)
|
unicode_result_wchar(PyObject *unicode)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue