@@ -3329,18 +3329,22 @@ PyBytes_ConcatAndDel(PyObject **pv, PyObject *w)
33293329//
33303330// Usage: assert(_PyBytes_IsMutable(obj)).
33313331int
3332- _PyBytes_IsMutable (PyObject * v )
3332+ _PyBytes_IsMutable (PyObject * self )
33333333{
3334- // Singleton objects must never be modified
3335- assert (!_Py_IsImmortal (v ));
3334+ assert (PyBytes_Check (self ));
3335+ // Do not use _PyObject_IsUniquelyReferenced(): this function is called
3336+ // by bytearray and PyBytesWriter which can be used by multiple threads.
3337+ assert (Py_REFCNT (self ) == 1 );
3338+ assert (!_Py_IsImmortal (self ));
33363339
3337- Py_ssize_t size = PyBytes_GET_SIZE (v );
3340+ // Check that the object is not a singleton
3341+ Py_ssize_t size = PyBytes_GET_SIZE (self );
33383342 if (size == 0 ) {
3339- assert (v != bytes_get_empty ());
3343+ assert (self != bytes_get_empty ());
33403344 }
33413345 else if (size == 1 ) {
3342- unsigned char ch = PyBytes_AS_STRING (v )[0 ];
3343- assert (v != (PyObject * )CHARACTER (ch ));
3346+ unsigned char ch = PyBytes_AS_STRING (self )[0 ];
3347+ assert (self != (PyObject * )CHARACTER (ch ));
33443348 }
33453349 return 1 ;
33463350}
@@ -3675,20 +3679,6 @@ byteswriter_allocated(PyBytesWriter *writer)
36753679
36763680
36773681#ifdef Py_DEBUG
3678- static void
3679- byteswriter_check_canary_byte (PyBytesWriter * writer )
3680- {
3681- const unsigned char * data = (const unsigned char * )byteswriter_data (writer );
3682- unsigned char canary = data [writer -> size ];
3683- if (canary != PyBytesWriter_CANARY_BYTE ) {
3684- _Py_FatalErrorFormat (__func__ ,
3685- "Buffer overflow detected in PyBytesWriter %p "
3686- "at position %zd" ,
3687- writer , writer -> size );
3688- }
3689- }
3690-
3691-
36923682static void
36933683byteswriter_write_canary_byte (PyBytesWriter * writer )
36943684{
@@ -3710,6 +3700,45 @@ byteswriter_reset_trailing_byte(PyBytesWriter *writer)
37103700#endif
37113701
37123702
3703+ #ifndef NDEBUG
3704+ static int
3705+ byteswriter_check_consistency (PyBytesWriter * writer )
3706+ {
3707+ PyObject * obj = writer -> obj ;
3708+ if (obj != NULL ) {
3709+ if (writer -> use_bytearray ) {
3710+ assert (PyByteArray_CheckExact (obj ));
3711+ // Do not use _PyObject_IsUniquelyReferenced(): the caller can have
3712+ // its own lock to prevent a writer from being used by two threads
3713+ // at the same time.
3714+ assert (Py_REFCNT (obj ) == 1 );
3715+ PyByteArrayObject * bytearray = (PyByteArrayObject * )obj ;
3716+ obj = bytearray -> ob_bytes_object ;
3717+ assert (obj != NULL );
3718+ }
3719+
3720+ // Code adapted from _PyBytes_IsMutable()
3721+ assert (PyBytes_CheckExact (obj ));
3722+ assert (_PyBytes_IsMutable (obj ));
3723+ // -1 since the last small buffer byte is used as the canary byte
3724+ assert ((size_t )PyBytes_GET_SIZE (obj ) > (sizeof (writer -> small_buffer ) - 1 ));
3725+ }
3726+
3727+ #ifdef Py_DEBUG
3728+ const unsigned char * data = (const unsigned char * )byteswriter_data (writer );
3729+ unsigned char canary = data [writer -> size ];
3730+ if (canary != PyBytesWriter_CANARY_BYTE ) {
3731+ _Py_FatalErrorFormat (__func__ ,
3732+ "Buffer overflow detected in PyBytesWriter %p "
3733+ "at position %zd" ,
3734+ writer , writer -> size );
3735+ }
3736+ #endif
3737+ return 1 ;
3738+ }
3739+ #endif
3740+
3741+
37133742#ifdef MS_WINDOWS
37143743 /* On Windows, overallocate by 50% is the best factor */
37153744# define OVERALLOCATE_FACTOR 2
@@ -3743,13 +3772,15 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t new_size, int resize)
37433772 // bytearray can override the canary byte on error
37443773 byteswriter_write_canary_byte (writer );
37453774#endif
3775+ assert (byteswriter_check_consistency (writer ));
37463776 return -1 ;
37473777 }
37483778 }
37493779 else {
37503780 // Can raise MemoryError or OverflowError
37513781 if (_PyBytes_ResizeKeepOnError (& writer -> obj , alloc )) {
37523782 assert (writer -> obj != NULL );
3783+ assert (byteswriter_check_consistency (writer ));
37533784 return -1 ;
37543785 }
37553786 assert (_PyBytes_IsMutable (writer -> obj ));
@@ -3821,7 +3852,7 @@ byteswriter_create(Py_ssize_t size, int use_bytearray)
38213852 if (size >= 1 ) {
38223853 if (byteswriter_resize (writer , size , 0 ) < 0 ) {
38233854#ifdef Py_DEBUG
3824- // Write the canary byte so byteswriter_check_canary_byte ()
3855+ // Write the canary byte so byteswriter_check_consistency ()
38253856 // doesn't fail in PyBytesWriter_Discard()
38263857 byteswriter_write_canary_byte (writer );
38273858#endif
@@ -3835,6 +3866,7 @@ byteswriter_create(Py_ssize_t size, int use_bytearray)
38353866 byteswriter_allocated (writer ));
38363867 byteswriter_write_canary_byte (writer );
38373868#endif
3869+ assert (byteswriter_check_consistency (writer ));
38383870 return writer ;
38393871}
38403872
@@ -3858,8 +3890,8 @@ PyBytesWriter_Discard(PyBytesWriter *writer)
38583890 return ;
38593891 }
38603892
3893+ assert (byteswriter_check_consistency (writer ));
38613894#ifdef Py_DEBUG
3862- byteswriter_check_canary_byte (writer );
38633895 if (writer -> obj != NULL ) {
38643896 byteswriter_reset_trailing_byte (writer );
38653897 }
@@ -3873,6 +3905,8 @@ PyBytesWriter_Discard(PyBytesWriter *writer)
38733905PyObject *
38743906PyBytesWriter_FinishWithSize (PyBytesWriter * writer , Py_ssize_t size )
38753907{
3908+ assert (byteswriter_check_consistency (writer ));
3909+
38763910 // Check for negative size here to raise ValueError in all cases, rather
38773911 // than having a different exception depending on the code path. For
38783912 // example, _PyBytes_Resize() raises SystemError on negative size.
@@ -3886,10 +3920,6 @@ PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size)
38863920 goto error ;
38873921 }
38883922
3889- #ifdef Py_DEBUG
3890- byteswriter_check_canary_byte (writer );
3891- #endif
3892-
38933923 PyObject * result ;
38943924 if (size == 0 ) {
38953925 result = bytes_get_empty ();
@@ -3938,7 +3968,7 @@ PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size)
39383968 }
39393969
39403970#ifdef Py_DEBUG
3941- // Reset the writer, so byteswriter_check_canary_byte () doesn't fail
3971+ // Reset the writer, so byteswriter_check_consistency () doesn't fail
39423972 // in PyBytesWriter_Discard().
39433973 writer -> size = 0 ;
39443974 byteswriter_write_canary_byte (writer );
@@ -3970,9 +4000,7 @@ PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf)
39704000void *
39714001PyBytesWriter_GetData (PyBytesWriter * writer )
39724002{
3973- #ifdef Py_DEBUG
3974- byteswriter_check_canary_byte (writer );
3975- #endif
4003+ assert (byteswriter_check_consistency (writer ));
39764004
39774005 return byteswriter_data (writer );
39784006}
@@ -3981,9 +4009,7 @@ PyBytesWriter_GetData(PyBytesWriter *writer)
39814009Py_ssize_t
39824010PyBytesWriter_GetSize (PyBytesWriter * writer )
39834011{
3984- #ifdef Py_DEBUG
3985- byteswriter_check_canary_byte (writer );
3986- #endif
4012+ assert (byteswriter_check_consistency (writer ));
39874013
39884014 return _PyBytesWriter_GetSize (writer );
39894015}
@@ -3992,9 +4018,7 @@ PyBytesWriter_GetSize(PyBytesWriter *writer)
39924018int
39934019PyBytesWriter_Resize (PyBytesWriter * writer , Py_ssize_t new_size )
39944020{
3995- #ifdef Py_DEBUG
3996- byteswriter_check_canary_byte (writer );
3997- #endif
4021+ assert (byteswriter_check_consistency (writer ));
39984022
39994023 if (new_size < 0 ) {
40004024 PyErr_SetString (PyExc_ValueError , "size must be >= 0" );
@@ -4012,6 +4036,7 @@ PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t new_size)
40124036#ifdef Py_DEBUG
40134037 byteswriter_write_canary_byte (writer );
40144038#endif
4039+ assert (byteswriter_check_consistency (writer ));
40154040 return 0 ;
40164041}
40174042
@@ -4031,9 +4056,7 @@ _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size,
40314056int
40324057PyBytesWriter_Grow (PyBytesWriter * writer , Py_ssize_t grow )
40334058{
4034- #ifdef Py_DEBUG
4035- byteswriter_check_canary_byte (writer );
4036- #endif
4059+ assert (byteswriter_check_consistency (writer ));
40374060
40384061 if (grow == 0 ) {
40394062 // Nothing to do
@@ -4064,6 +4087,7 @@ PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow)
40644087#ifdef Py_DEBUG
40654088 byteswriter_write_canary_byte (writer );
40664089#endif
4090+ assert (byteswriter_check_consistency (writer ));
40674091 return 0 ;
40684092}
40694093
@@ -4099,6 +4123,8 @@ PyBytesWriter_WriteBytes(PyBytesWriter *writer,
40994123 }
41004124 char * buf = byteswriter_data (writer );
41014125 memcpy (buf + pos , bytes , size );
4126+
4127+ assert (byteswriter_check_consistency (writer ));
41024128 return 0 ;
41034129}
41044130
@@ -4127,14 +4153,12 @@ PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...)
41274153static Py_ssize_t
41284154_PyBytesWriter_ResizeToAllocated (PyBytesWriter * writer )
41294155{
4130- #ifdef Py_DEBUG
4131- byteswriter_check_canary_byte (writer );
4132- #endif
4133-
41344156 Py_ssize_t allocated = byteswriter_allocated (writer );
41354157 writer -> size = allocated ;
41364158#ifdef Py_DEBUG
41374159 byteswriter_write_canary_byte (writer );
41384160#endif
4161+
4162+ assert (byteswriter_check_consistency (writer ));
41394163 return allocated ;
41404164}
0 commit comments