Coverage Report

Created: 2026-10-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Modules/_io/bytesio.c
Line
Count
Source
1
#include "Python.h"
2
#include "pycore_bytesobject.h"       // _PyBytes_ResizeKeepOnError()
3
#include "pycore_critical_section.h"  // Py_BEGIN_CRITICAL_SECTION()
4
#include "pycore_list.h"              // _PyList_AppendTakeRef()
5
#include "pycore_object.h"
6
#include "pycore_pyatomic_ft_wrappers.h"
7
#include "pycore_sysmodule.h"         // _PySys_GetSizeOf()
8
#include "pycore_weakref.h"           // FT_CLEAR_WEAKREFS()
9
10
#include <stddef.h>                   // offsetof()
11
#include "_iomodule.h"
12
13
/*[clinic input]
14
module _io
15
class _io.BytesIO "bytesio *" "clinic_state()->PyBytesIO_Type"
16
[clinic start generated code]*/
17
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=48ede2f330f847c3]*/
18
19
typedef struct {
20
    PyObject_HEAD
21
    PyObject *buf;
22
    Py_ssize_t pos;
23
    Py_ssize_t string_size;
24
    PyObject *dict;
25
    PyObject *weakreflist;
26
    Py_ssize_t exports;
27
#ifdef Py_GIL_DISABLED
28
    int buf_shared;
29
#endif
30
} bytesio;
31
32
61.2k
#define bytesio_CAST(op)    ((bytesio *)(op))
33
34
typedef struct {
35
    PyObject_HEAD
36
    bytesio *source;
37
} bytesiobuf;
38
39
0
#define bytesiobuf_CAST(op) ((bytesiobuf *)(op))
40
41
/* The bytesio object can be in three states:
42
  * Py_REFCNT(buf) == 1, exports == 0.
43
  * Py_REFCNT(buf) > 1.  exports == 0,
44
    first modification or export causes the internal buffer copying.
45
  * exports > 0.  Any modifications are forbidden.  Every exported buffer
46
    keeps a reference to buf, so it outlives closing of the bytesio object.
47
*/
48
49
static int
50
check_closed(bytesio *self)
51
19.9M
{
52
19.9M
    if (self->buf == NULL) {
53
0
        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
54
0
        return 1;
55
0
    }
56
19.9M
    return 0;
57
19.9M
}
58
59
static int
60
check_exports(bytesio *self)
61
72.3k
{
62
72.3k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
63
0
        PyErr_SetString(PyExc_BufferError,
64
0
                        "Existing exports of data: object cannot be re-sized");
65
0
        return 1;
66
0
    }
67
72.3k
    return 0;
68
72.3k
}
69
70
#define CHECK_CLOSED(self)                                  \
71
19.8M
    if (check_closed(self)) {                               \
72
0
        return NULL;                                        \
73
0
    }
74
75
#define CHECK_EXPORTS(self) \
76
0
    if (check_exports(self)) { \
77
0
        return NULL; \
78
0
    }
79
80
#ifdef Py_GIL_DISABLED
81
#define SHARED_BUF(self) ((self)->buf_shared || !_PyObject_IsUniquelyReferenced((self)->buf))
82
#else
83
51.5k
#define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf))
84
#endif
85
86
static inline void
87
set_shared_buf(bytesio *self)
88
25.0k
{
89
#ifdef Py_GIL_DISABLED
90
    self->buf_shared = 1;
91
#endif
92
25.0k
}
93
94
static inline void
95
clear_shared_buf(bytesio *self)
96
72.2k
{
97
#ifdef Py_GIL_DISABLED
98
    self->buf_shared = 0;
99
#endif
100
72.2k
}
101
102
static int
103
resize_unshared_buffer_lock_held(bytesio *self, Py_ssize_t size)
104
20.6k
{
105
20.6k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
106
107
#ifdef Py_GIL_DISABLED
108
    /* If the internal bytes object escaped via a zero-copy getvalue(), read(),
109
       or peek(), resizing it would mutate an object visible to Python code.
110
       Callers must detach first. */
111
    assert(!self->buf_shared);
112
#endif
113
20.6k
    int ret = _PyBytes_ResizeKeepOnError(&self->buf, size);
114
20.6k
    if (ret == 0) {
115
20.6k
        clear_shared_buf(self);
116
20.6k
    }
117
20.6k
    return ret;
118
20.6k
}
119
120
121
/* Internal routine to get a line from the buffer of a BytesIO
122
   object. Returns the length between the current position to the
123
   next newline character. */
124
static Py_ssize_t
125
scan_eol_lock_held(bytesio *self, Py_ssize_t len)
126
125k
{
127
125k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
128
129
125k
    const char *start, *n;
130
125k
    Py_ssize_t maxlen;
131
132
125k
    assert(self->buf != NULL);
133
125k
    assert(self->pos >= 0);
134
135
125k
    if (self->pos >= self->string_size)
136
8.70k
        return 0;
137
138
    /* Move to the end of the line, up to the end of the string, s. */
139
116k
    maxlen = self->string_size - self->pos;
140
116k
    if (len < 0 || len > maxlen)
141
100k
        len = maxlen;
142
143
116k
    if (len) {
144
116k
        start = PyBytes_AS_STRING(self->buf) + self->pos;
145
116k
        n = memchr(start, '\n', len);
146
116k
        if (n)
147
            /* Get the length from the current position to the end of
148
               the line. */
149
107k
            len = n - start + 1;
150
116k
    }
151
116k
    assert(len >= 0);
152
116k
    assert(self->pos < PY_SSIZE_T_MAX - len);
153
154
116k
    return len;
155
125k
}
156
157
/* Internal routine for detaching the shared buffer of BytesIO objects.
158
   The caller should ensure that the 'size' argument is non-negative and
159
   not lesser than self->string_size.  Returns 0 on success, -1 otherwise. */
160
static int
161
unshare_buffer_lock_held(bytesio *self, size_t size)
162
4.72k
{
163
4.72k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
164
165
4.72k
    PyObject *new_buf;
166
4.72k
    assert(SHARED_BUF(self));
167
4.72k
    assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
168
4.72k
    assert(size >= (size_t)self->string_size);
169
4.72k
    new_buf = PyBytes_FromStringAndSize(NULL, size);
170
4.72k
    if (new_buf == NULL)
171
0
        return -1;
172
4.72k
    memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf),
173
4.72k
           self->string_size);
174
4.72k
    Py_SETREF(self->buf, new_buf);
175
4.72k
    clear_shared_buf(self);
176
4.72k
    return 0;
177
4.72k
}
178
179
/* Internal routine for changing the size of the buffer of BytesIO objects.
180
   The caller should ensure that the 'size' argument is non-negative.  Returns
181
   0 on success, -1 otherwise. */
182
static int
183
resize_buffer_lock_held(bytesio *self, size_t size)
184
24.8k
{
185
24.8k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
186
187
24.8k
    assert(self->buf != NULL);
188
24.8k
    assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
189
190
    /* Here, unsigned types are used to avoid dealing with signed integer
191
       overflow, which is undefined in C. */
192
24.8k
    size_t alloc = PyBytes_GET_SIZE(self->buf);
193
194
    /* For simplicity, stay in the range of the signed type. Anyway, Python
195
       doesn't allow strings to be longer than this. */
196
24.8k
    if (size > PY_SSIZE_T_MAX)
197
0
        goto overflow;
198
199
24.8k
    if (size < alloc / 2) {
200
        /* Major downsize; resize down to exact size. */
201
0
        alloc = size + 1;
202
0
    }
203
24.8k
    else if (size < alloc) {
204
        /* Within allocated size; quick exit */
205
0
        return 0;
206
0
    }
207
24.8k
    else if (size <= alloc * 1.125) {
208
        /* Moderate upsize; overallocate similar to list_resize() */
209
10.5k
        alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
210
10.5k
    }
211
14.2k
    else {
212
        /* Major upsize; resize up to exact size */
213
14.2k
        alloc = size + 1;
214
14.2k
    }
215
216
24.8k
    if (SHARED_BUF(self)) {
217
4.72k
        if (unshare_buffer_lock_held(self, alloc) < 0)
218
0
            return -1;
219
4.72k
    }
220
20.1k
    else {
221
20.1k
        if (resize_unshared_buffer_lock_held(self, alloc) < 0)
222
0
            return -1;
223
20.1k
    }
224
225
24.8k
    return 0;
226
227
0
  overflow:
228
0
    PyErr_SetString(PyExc_OverflowError,
229
0
                    "new buffer size too large");
230
0
    return -1;
231
24.8k
}
232
233
/* Internal routine for writing a string of bytes to the buffer of a BytesIO
234
   object. Returns the number of bytes written, or -1 on error.
235
   Inlining is disabled because it's significantly decreases performance
236
   of writelines() in PGO build. */
237
Py_NO_INLINE static Py_ssize_t
238
write_bytes_lock_held(bytesio *self, PyObject *b)
239
72.3k
{
240
72.3k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
241
242
72.3k
    Py_buffer buf;
243
72.3k
    Py_ssize_t len;
244
72.3k
    if (PyObject_GetBuffer(b, &buf, PyBUF_CONTIG_RO) < 0) {
245
0
        return -1;
246
0
    }
247
248
72.3k
    if (check_closed(self) || check_exports(self)) {
249
0
        len = -1;
250
0
        goto done;
251
0
    }
252
253
72.3k
    len = buf.len;
254
72.3k
    if (len == 0) {
255
21.4k
        goto done;
256
21.4k
    }
257
258
72.3k
    assert(self->pos >= 0);
259
50.9k
    size_t endpos = (size_t)self->pos + len;
260
50.9k
    if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) {
261
24.8k
        if (resize_buffer_lock_held(self, endpos) < 0) {
262
0
            len = -1;
263
0
            goto done;
264
0
        }
265
24.8k
    }
266
26.1k
    else if (SHARED_BUF(self)) {
267
0
        if (unshare_buffer_lock_held(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) {
268
0
            len = -1;
269
0
            goto done;
270
0
        }
271
0
    }
272
273
50.9k
    if (self->pos > self->string_size) {
274
        /* In case of overseek, pad with null bytes the buffer region between
275
           the end of stream and the current position.
276
277
          0   lo      string_size                           hi
278
          |   |<---used--->|<----------available----------->|
279
          |   |            <--to pad-->|<---to write--->    |
280
          0   buf                   position
281
        */
282
0
        memset(PyBytes_AS_STRING(self->buf) + self->string_size, '\0',
283
0
               (self->pos - self->string_size) * sizeof(char));
284
0
    }
285
286
    /* Copy the data to the internal buffer, overwriting some of the existing
287
       data if self->pos < self->string_size. */
288
50.9k
    memcpy(PyBytes_AS_STRING(self->buf) + self->pos, buf.buf, len);
289
50.9k
    self->pos = endpos;
290
291
    /* Set the new length of the internal string if it has changed. */
292
50.9k
    if ((size_t)self->string_size < endpos) {
293
43.3k
        self->string_size = endpos;
294
43.3k
    }
295
296
72.3k
  done:
297
72.3k
    PyBuffer_Release(&buf);
298
72.3k
    return len;
299
50.9k
}
300
301
/*[clinic input]
302
@critical_section
303
@getter
304
_io.BytesIO.closed -> bool
305
306
True if the file is closed.
307
[clinic start generated code]*/
308
309
static int
310
_io_BytesIO_closed_get_impl(bytesio *self)
311
/*[clinic end generated code: output=7cdc647cc7a71683 input=0687f923344225ee]*/
312
0
{
313
0
    return self->buf == NULL;
314
0
}
315
316
/*[clinic input]
317
@critical_section
318
_io.BytesIO.readable
319
320
Returns True if the IO object can be read.
321
[clinic start generated code]*/
322
323
static PyObject *
324
_io_BytesIO_readable_impl(bytesio *self)
325
/*[clinic end generated code: output=4e93822ad5b62263 input=ab7816facef48bfd]*/
326
0
{
327
0
    CHECK_CLOSED(self);
328
0
    Py_RETURN_TRUE;
329
0
}
330
331
/*[clinic input]
332
@critical_section
333
_io.BytesIO.writable
334
335
Returns True if the IO object can be written.
336
[clinic start generated code]*/
337
338
static PyObject *
339
_io_BytesIO_writable_impl(bytesio *self)
340
/*[clinic end generated code: output=64ff6a254b1150b8 input=4f35d49d26dab024]*/
341
0
{
342
0
    CHECK_CLOSED(self);
343
0
    Py_RETURN_TRUE;
344
0
}
345
346
/*[clinic input]
347
@critical_section
348
_io.BytesIO.seekable
349
350
Returns True if the IO object can be seeked.
351
[clinic start generated code]*/
352
353
static PyObject *
354
_io_BytesIO_seekable_impl(bytesio *self)
355
/*[clinic end generated code: output=6b417f46dcc09b56 input=9cc78d15aa1deaa3]*/
356
18.6k
{
357
18.6k
    CHECK_CLOSED(self);
358
18.6k
    Py_RETURN_TRUE;
359
18.6k
}
360
361
/*[clinic input]
362
@critical_section
363
_io.BytesIO.flush
364
365
Does nothing.
366
[clinic start generated code]*/
367
368
static PyObject *
369
_io_BytesIO_flush_impl(bytesio *self)
370
/*[clinic end generated code: output=187e3d781ca134a0 input=c60842743910b381]*/
371
11.9k
{
372
11.9k
    CHECK_CLOSED(self);
373
11.9k
    Py_RETURN_NONE;
374
11.9k
}
375
376
/*[clinic input]
377
@critical_section
378
_io.BytesIO.getbuffer
379
380
    cls: defining_class
381
    /
382
383
Get a read-write view over the contents of the BytesIO object.
384
[clinic start generated code]*/
385
386
static PyObject *
387
_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
388
/*[clinic end generated code: output=045091d7ce87fe4e input=8295764061be77fd]*/
389
0
{
390
0
    _PyIO_State *state = get_io_state_by_cls(cls);
391
0
    PyTypeObject *type = state->PyBytesIOBuffer_Type;
392
0
    bytesiobuf *buf;
393
0
    PyObject *view;
394
395
0
    CHECK_CLOSED(self);
396
397
0
    buf = (bytesiobuf *) type->tp_alloc(type, 0);
398
0
    if (buf == NULL)
399
0
        return NULL;
400
0
    buf->source = (bytesio*)Py_NewRef(self);
401
0
    view = PyMemoryView_FromObject((PyObject *) buf);
402
0
    Py_DECREF(buf);
403
0
    return view;
404
0
}
405
406
/*[clinic input]
407
@critical_section
408
_io.BytesIO.getvalue
409
410
Retrieve the entire contents of the BytesIO object.
411
[clinic start generated code]*/
412
413
static PyObject *
414
_io_BytesIO_getvalue_impl(bytesio *self)
415
/*[clinic end generated code: output=b3f6a3233c8fd628 input=c91bff398df0c352]*/
416
552
{
417
552
    CHECK_CLOSED(self);
418
552
    if (self->string_size <= 1 || FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0)
419
0
        return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf),
420
0
                                         self->string_size);
421
422
552
    if (self->string_size != PyBytes_GET_SIZE(self->buf)) {
423
551
        if (SHARED_BUF(self)) {
424
0
            if (unshare_buffer_lock_held(self, self->string_size) < 0)
425
0
                return NULL;
426
0
        }
427
551
        else {
428
551
            if (resize_unshared_buffer_lock_held(self, self->string_size) < 0)
429
0
                return NULL;
430
551
        }
431
551
    }
432
552
    set_shared_buf(self);
433
552
    return Py_NewRef(self->buf);
434
552
}
435
436
/*[clinic input]
437
@critical_section
438
_io.BytesIO.isatty
439
440
Always returns False.
441
442
BytesIO objects are not connected to a TTY-like device.
443
[clinic start generated code]*/
444
445
static PyObject *
446
_io_BytesIO_isatty_impl(bytesio *self)
447
/*[clinic end generated code: output=df67712e669f6c8f input=50487b74dc5ae8a9]*/
448
0
{
449
0
    CHECK_CLOSED(self);
450
0
    Py_RETURN_FALSE;
451
0
}
452
453
/*[clinic input]
454
@critical_section
455
_io.BytesIO.tell
456
457
Current file position, an integer.
458
[clinic start generated code]*/
459
460
static PyObject *
461
_io_BytesIO_tell_impl(bytesio *self)
462
/*[clinic end generated code: output=b54b0f93cd0e5e1d input=2c7b0e8f82e05c4d]*/
463
116k
{
464
116k
    CHECK_CLOSED(self);
465
116k
    return PyLong_FromSsize_t(self->pos);
466
116k
}
467
468
/* Read without advancing position. */
469
static PyObject *
470
peek_bytes_lock_held(bytesio *self, Py_ssize_t size)
471
19.5M
{
472
19.5M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
473
474
19.5M
    const char *output;
475
476
19.5M
    assert(self->buf != NULL);
477
19.5M
    assert(size <= self->string_size);
478
19.5M
    if (size > 1 &&
479
16.4M
        self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
480
24.5k
        FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
481
24.5k
        set_shared_buf(self);
482
24.5k
        return Py_NewRef(self->buf);
483
24.5k
    }
484
485
    /* gh-141311: Avoid undefined behavior when self->pos (limit PY_SSIZE_T_MAX)
486
       is beyond the size of self->buf. Assert above validates size is always in
487
       bounds. When self->pos is out of bounds calling code sets size to 0. */
488
19.5M
    if (size == 0) {
489
905k
        return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
490
905k
    }
491
492
18.6M
    output = PyBytes_AS_STRING(self->buf) + self->pos;
493
18.6M
    return PyBytes_FromStringAndSize(output, size);
494
19.5M
}
495
496
static PyObject *
497
read_bytes_lock_held(bytesio *self, Py_ssize_t size)
498
19.5M
{
499
19.5M
    PyObject *bytes = peek_bytes_lock_held(self, size);
500
19.5M
    if (bytes != NULL) {
501
19.5M
        assert(PyBytes_GET_SIZE(bytes) == size);
502
19.5M
        self->pos += size;
503
19.5M
    }
504
19.5M
    return bytes;
505
19.5M
}
506
507
/*[clinic input]
508
@critical_section
509
_io.BytesIO.read
510
    size: Py_ssize_t(accept={int, NoneType}) = -1
511
    /
512
513
Read at most size bytes, returned as a bytes object.
514
515
If the size argument is negative, read until EOF is reached.
516
Return an empty bytes object at EOF.
517
[clinic start generated code]*/
518
519
static PyObject *
520
_io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
521
/*[clinic end generated code: output=9cc025f21c75bdd2 input=9e2f7ff3075fdd39]*/
522
19.4M
{
523
19.4M
    Py_ssize_t n;
524
525
19.4M
    CHECK_CLOSED(self);
526
527
    /* adjust invalid sizes */
528
19.4M
    n = self->string_size - self->pos;
529
19.4M
    if (size < 0 || size > n) {
530
63.5k
        size = n;
531
63.5k
        if (size < 0)
532
1.58k
            size = 0;
533
63.5k
    }
534
535
19.4M
    return read_bytes_lock_held(self, size);
536
19.4M
}
537
538
539
/*[clinic input]
540
@critical_section
541
_io.BytesIO.read1
542
    size: Py_ssize_t(accept={int, NoneType}) = -1
543
    /
544
545
Read at most size bytes, returned as a bytes object.
546
547
If the size argument is negative or omitted, read until EOF is
548
reached.  Return an empty bytes object at EOF.
549
[clinic start generated code]*/
550
551
static PyObject *
552
_io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size)
553
/*[clinic end generated code: output=d0f843285aa95f1c input=796ff4e0efccc4d9]*/
554
0
{
555
0
    return _io_BytesIO_read_impl(self, size);
556
0
}
557
558
559
/*[clinic input]
560
@critical_section
561
_io.BytesIO.peek
562
    size: Py_ssize_t = 0
563
    /
564
565
Return bytes from the stream without advancing the position.
566
567
Return an empty bytes object at EOF.
568
[clinic start generated code]*/
569
570
static PyObject *
571
_io_BytesIO_peek_impl(bytesio *self, Py_ssize_t size)
572
/*[clinic end generated code: output=fa4d8ce28b35db9b input=2ce74234b10aec3e]*/
573
0
{
574
0
    CHECK_CLOSED(self);
575
576
0
    if (size < 1) {
577
0
        size = DEFAULT_BUFFER_SIZE;
578
0
    }
579
580
    /* adjust invalid sizes */
581
0
    Py_ssize_t n = self->string_size - self->pos;
582
0
    if (size > n) {
583
0
        size = n;
584
        /* n can be negative after truncate() or seek() */
585
0
        if (size < 0) {
586
0
            size = 0;
587
0
        }
588
0
    }
589
0
    return peek_bytes_lock_held(self, size);
590
0
}
591
592
593
/*[clinic input]
594
@critical_section
595
_io.BytesIO.readline
596
    size: Py_ssize_t(accept={int, NoneType}) = -1
597
    /
598
599
Next line from the file, as a bytes object.
600
601
Retain newline.  A non-negative size argument limits the maximum
602
number of bytes to return (an incomplete line may be returned then).
603
Return an empty bytes object at EOF.
604
[clinic start generated code]*/
605
606
static PyObject *
607
_io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size)
608
/*[clinic end generated code: output=4bff3c251df8ffcd input=db09d47e23cf2c9e]*/
609
125k
{
610
125k
    Py_ssize_t n;
611
612
125k
    CHECK_CLOSED(self);
613
614
125k
    n = scan_eol_lock_held(self, size);
615
616
125k
    return read_bytes_lock_held(self, n);
617
125k
}
618
619
/*[clinic input]
620
@critical_section
621
_io.BytesIO.readlines
622
    size as arg: object = None
623
    /
624
625
List of bytes objects, each a line from the file.
626
627
Call readline() repeatedly and return a list of the lines so read.
628
The optional size argument, if given, is an approximate bound on the
629
total number of bytes in the lines returned.
630
[clinic start generated code]*/
631
632
static PyObject *
633
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
634
/*[clinic end generated code: output=09b8e34c880808ff input=5c57d7d78e409985]*/
635
0
{
636
0
    Py_ssize_t maxsize, size, n;
637
0
    PyObject *result, *line;
638
0
    const char *output;
639
640
0
    CHECK_CLOSED(self);
641
642
0
    if (PyLong_Check(arg)) {
643
0
        maxsize = PyLong_AsSsize_t(arg);
644
0
        if (maxsize == -1 && PyErr_Occurred())
645
0
            return NULL;
646
0
    }
647
0
    else if (arg == Py_None) {
648
        /* No size limit, by default. */
649
0
        maxsize = -1;
650
0
    }
651
0
    else {
652
0
        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
653
0
                     Py_TYPE(arg)->tp_name);
654
0
        return NULL;
655
0
    }
656
657
0
    size = 0;
658
0
    result = PyList_New(0);
659
0
    if (!result)
660
0
        return NULL;
661
662
0
    output = PyBytes_AS_STRING(self->buf) + self->pos;
663
0
    while ((n = scan_eol_lock_held(self, -1)) != 0) {
664
0
        self->pos += n;
665
0
        line = PyBytes_FromStringAndSize(output, n);
666
0
        if (!line)
667
0
            goto on_error;
668
0
        if (_PyList_AppendTakeRef((PyListObject *)result, line) < 0) {
669
0
            goto on_error;
670
0
        }
671
0
        size += n;
672
0
        if (maxsize > 0 && size >= maxsize)
673
0
            break;
674
0
        output += n;
675
0
    }
676
0
    return result;
677
678
0
  on_error:
679
0
    Py_DECREF(result);
680
0
    return NULL;
681
0
}
682
683
/*[clinic input]
684
@critical_section
685
_io.BytesIO.readinto
686
    buffer: Py_buffer(accept={rwbuffer})
687
    /
688
689
Read bytes into buffer.
690
691
Returns number of bytes read (0 for EOF), or None if the object
692
is set not to block and has no data to read.
693
[clinic start generated code]*/
694
695
static PyObject *
696
_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
697
/*[clinic end generated code: output=a5d407217dcf0639 input=093a8d330de3fcd1]*/
698
0
{
699
0
    Py_ssize_t len, n;
700
701
0
    CHECK_CLOSED(self);
702
703
    /* adjust invalid sizes */
704
0
    len = buffer->len;
705
0
    n = self->string_size - self->pos;
706
0
    if (len > n) {
707
0
        len = n;
708
0
        if (len < 0) {
709
            /* gh-141311: Avoid undefined behavior when self->pos (limit
710
               PY_SSIZE_T_MAX) points beyond the size of self->buf. */
711
0
            return PyLong_FromSsize_t(0);
712
0
        }
713
0
    }
714
715
0
    assert(self->pos + len <= PY_SSIZE_T_MAX);
716
0
    assert(len >= 0);
717
0
    memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
718
0
    self->pos += len;
719
720
0
    return PyLong_FromSsize_t(len);
721
0
}
722
723
/*[clinic input]
724
@critical_section
725
_io.BytesIO.truncate
726
    size: object = None
727
    /
728
729
Truncate the file to at most size bytes.
730
731
Size defaults to the current file position, as returned by tell().
732
The current file position is unchanged.  Returns the new size.
733
[clinic start generated code]*/
734
735
static PyObject *
736
_io_BytesIO_truncate_impl(bytesio *self, PyObject *size)
737
/*[clinic end generated code: output=ab42491b4824f384 input=b4acb5f80481c053]*/
738
0
{
739
0
    CHECK_CLOSED(self);
740
0
    CHECK_EXPORTS(self);
741
742
0
    Py_ssize_t new_size;
743
744
0
    if (size == Py_None) {
745
0
        new_size = self->pos;
746
0
    }
747
0
    else {
748
0
        new_size = PyLong_AsLong(size);
749
0
        if (new_size == -1 && PyErr_Occurred()) {
750
0
            return NULL;
751
0
        }
752
0
        if (new_size < 0) {
753
0
            PyErr_Format(PyExc_ValueError,
754
0
                         "negative size value %zd", new_size);
755
0
            return NULL;
756
0
        }
757
0
    }
758
759
0
    if (new_size < self->string_size) {
760
0
        Py_ssize_t old_string_size = self->string_size;
761
0
        self->string_size = new_size;
762
0
        if (resize_buffer_lock_held(self, new_size) < 0) {
763
0
            self->string_size = old_string_size;
764
0
            return NULL;
765
0
        }
766
0
    }
767
768
0
    return PyLong_FromSsize_t(new_size);
769
0
}
770
771
static PyObject *
772
bytesio_iternext_lock_held(PyObject *op)
773
0
{
774
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
775
776
0
    Py_ssize_t n;
777
0
    bytesio *self = bytesio_CAST(op);
778
779
0
    CHECK_CLOSED(self);
780
781
0
    n = scan_eol_lock_held(self, -1);
782
783
0
    if (n == 0)
784
0
        return NULL;
785
786
0
    return read_bytes_lock_held(self, n);
787
0
}
788
789
static PyObject *
790
bytesio_iternext(PyObject *op)
791
0
{
792
0
    PyObject *ret;
793
0
    Py_BEGIN_CRITICAL_SECTION(op);
794
0
    ret = bytesio_iternext_lock_held(op);
795
0
    Py_END_CRITICAL_SECTION();
796
0
    return ret;
797
0
}
798
799
/*[clinic input]
800
@critical_section
801
_io.BytesIO.seek
802
    pos: Py_ssize_t
803
    whence: int = 0
804
    /
805
806
Change stream position.
807
808
Seek to byte offset pos relative to position indicated by whence:
809
     0  Start of stream (the default).  pos should be >= 0;
810
     1  Current position - pos may be negative;
811
     2  End of stream - pos usually negative.
812
Returns the new absolute position.
813
[clinic start generated code]*/
814
815
static PyObject *
816
_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
817
/*[clinic end generated code: output=c26204a68e9190e4 input=20f05ddf659255df]*/
818
168k
{
819
168k
    CHECK_CLOSED(self);
820
821
168k
    if (pos < 0 && whence == 0) {
822
684
        PyErr_Format(PyExc_ValueError,
823
684
                     "negative seek value %zd", pos);
824
684
        return NULL;
825
684
    }
826
827
    /* whence = 0: offset relative to beginning of the string.
828
       whence = 1: offset relative to current position.
829
       whence = 2: offset relative the end of the string. */
830
168k
    if (whence == 1) {
831
3.28k
        if (pos > PY_SSIZE_T_MAX - self->pos) {
832
0
            PyErr_SetString(PyExc_OverflowError,
833
0
                            "new position too large");
834
0
            return NULL;
835
0
        }
836
3.28k
        pos += self->pos;
837
3.28k
    }
838
164k
    else if (whence == 2) {
839
18.9k
        if (pos > PY_SSIZE_T_MAX - self->string_size) {
840
0
            PyErr_SetString(PyExc_OverflowError,
841
0
                            "new position too large");
842
0
            return NULL;
843
0
        }
844
18.9k
        pos += self->string_size;
845
18.9k
    }
846
145k
    else if (whence != 0) {
847
0
        PyErr_Format(PyExc_ValueError,
848
0
                     "invalid whence (%i, should be 0, 1 or 2)", whence);
849
0
        return NULL;
850
0
    }
851
852
168k
    if (pos < 0)
853
1.72k
        pos = 0;
854
168k
    self->pos = pos;
855
856
168k
    return PyLong_FromSsize_t(self->pos);
857
168k
}
858
859
/*[clinic input]
860
@critical_section
861
_io.BytesIO.write
862
    b: object
863
    /
864
865
Write bytes to file.
866
867
Return the number of bytes written.
868
[clinic start generated code]*/
869
870
static PyObject *
871
_io_BytesIO_write_impl(bytesio *self, PyObject *b)
872
/*[clinic end generated code: output=d3e46bcec8d9e21c input=46c0c17eac7474a4]*/
873
72.3k
{
874
72.3k
    Py_ssize_t n = write_bytes_lock_held(self, b);
875
72.3k
    return n >= 0 ? PyLong_FromSsize_t(n) : NULL;
876
72.3k
}
877
878
/*[clinic input]
879
@critical_section
880
_io.BytesIO.writelines
881
    lines: object
882
    /
883
884
Write lines to the file.
885
886
Note that newlines are not added.  lines can be any iterable object
887
producing bytes-like objects.  This is equivalent to calling write()
888
for each element.
889
[clinic start generated code]*/
890
891
static PyObject *
892
_io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
893
/*[clinic end generated code: output=03a43a75773bc397 input=d265f76533b058e7]*/
894
0
{
895
0
    PyObject *it, *item;
896
897
0
    CHECK_CLOSED(self);
898
899
0
    it = PyObject_GetIter(lines);
900
0
    if (it == NULL)
901
0
        return NULL;
902
903
0
    while ((item = PyIter_Next(it)) != NULL) {
904
0
        Py_ssize_t ret = write_bytes_lock_held(self, item);
905
0
        Py_DECREF(item);
906
0
        if (ret < 0) {
907
0
            Py_DECREF(it);
908
0
            return NULL;
909
0
        }
910
0
    }
911
0
    Py_DECREF(it);
912
913
    /* See if PyIter_Next failed */
914
0
    if (PyErr_Occurred())
915
0
        return NULL;
916
917
0
    Py_RETURN_NONE;
918
0
}
919
920
/*[clinic input]
921
@critical_section
922
_io.BytesIO.close
923
924
Disable all I/O operations.
925
[clinic start generated code]*/
926
927
static PyObject *
928
_io_BytesIO_close_impl(bytesio *self)
929
/*[clinic end generated code: output=1471bb9411af84a0 input=34ce76d8bd17a23b]*/
930
9.40k
{
931
    /* The exported buffers keep the internal buffer alive. */
932
9.40k
    Py_CLEAR(self->buf);
933
9.40k
    Py_RETURN_NONE;
934
9.40k
}
935
936
/* Pickling support.
937
938
   Note that only pickle protocol 2 and onward are supported since we use
939
   extended __reduce__ API of PEP 307 to make BytesIO instances picklable.
940
941
   Providing support for protocol < 2 would require the __reduce_ex__ method
942
   which is notably long-winded when defined properly.
943
944
   For BytesIO, the implementation would similar to one coded for
945
   object.__reduce_ex__, but slightly less general. To be more specific, we
946
   could call bytesio_getstate directly and avoid checking for the presence of
947
   a fallback __reduce__ method. However, we would still need a __newobj__
948
   function to use the efficient instance representation of PEP 307.
949
 */
950
951
952
/*[clinic input]
953
@critical_section
954
_io.BytesIO.__getstate__
955
[clinic start generated code]*/
956
957
static PyObject *
958
_io_BytesIO___getstate___impl(bytesio *self)
959
/*[clinic end generated code: output=4a776270c8443b85 input=f41e5bc9731475c4]*/
960
0
{
961
0
    PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
962
0
    PyObject *dict;
963
0
    PyObject *state;
964
965
0
    if (initvalue == NULL)
966
0
        return NULL;
967
0
    if (self->dict == NULL) {
968
0
        dict = Py_NewRef(Py_None);
969
0
    }
970
0
    else {
971
0
        dict = PyDict_Copy(self->dict);
972
0
        if (dict == NULL) {
973
0
            Py_DECREF(initvalue);
974
0
            return NULL;
975
0
        }
976
0
    }
977
978
0
    state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
979
0
    Py_DECREF(initvalue);
980
0
    return state;
981
0
}
982
983
984
/*[clinic input]
985
@critical_section
986
_io.BytesIO.__setstate__
987
988
    state: object
989
    /
990
[clinic start generated code]*/
991
992
static PyObject *
993
_io_BytesIO___setstate___impl(bytesio *self, PyObject *state)
994
/*[clinic end generated code: output=3605abdec171bb98 input=82a189599ba75083]*/
995
0
{
996
0
    PyObject *result;
997
0
    PyObject *position_obj;
998
0
    PyObject *dict;
999
0
    Py_ssize_t pos;
1000
1001
0
    assert(state != NULL);
1002
1003
    /* We allow the state tuple to be longer than 3, because we may need
1004
       someday to extend the object's state without breaking
1005
       backward-compatibility. */
1006
0
    if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) < 3) {
1007
0
        PyErr_Format(PyExc_TypeError,
1008
0
                     "%.200s.__setstate__ argument should be 3-tuple, got %.200s",
1009
0
                     Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
1010
0
        return NULL;
1011
0
    }
1012
0
    CHECK_EXPORTS(self);
1013
    /* Reset the object to its default state. This is only needed to handle
1014
       the case of repeated calls to __setstate__. */
1015
0
    self->string_size = 0;
1016
0
    self->pos = 0;
1017
1018
    /* Set the value of the internal buffer. If state[0] does not support the
1019
       buffer protocol, bytesio_write will raise the appropriate TypeError. */
1020
0
    result = _io_BytesIO_write_impl(self, PyTuple_GET_ITEM(state, 0));
1021
0
    if (result == NULL)
1022
0
        return NULL;
1023
0
    Py_DECREF(result);
1024
1025
    /* Set carefully the position value. Alternatively, we could use the seek
1026
       method instead of modifying self->pos directly to better protect the
1027
       object internal state against erroneous (or malicious) inputs. */
1028
0
    position_obj = PyTuple_GET_ITEM(state, 1);
1029
0
    if (!PyLong_Check(position_obj)) {
1030
0
        PyErr_Format(PyExc_TypeError,
1031
0
                     "second item of state must be an integer, not %.200s",
1032
0
                     Py_TYPE(position_obj)->tp_name);
1033
0
        return NULL;
1034
0
    }
1035
0
    pos = PyLong_AsSsize_t(position_obj);
1036
0
    if (pos == -1 && PyErr_Occurred())
1037
0
        return NULL;
1038
0
    if (pos < 0) {
1039
0
        PyErr_SetString(PyExc_ValueError,
1040
0
                        "position value cannot be negative");
1041
0
        return NULL;
1042
0
    }
1043
0
    self->pos = pos;
1044
1045
    /* Set the dictionary of the instance variables. */
1046
0
    dict = PyTuple_GET_ITEM(state, 2);
1047
0
    if (dict != Py_None) {
1048
0
        if (!PyDict_Check(dict)) {
1049
0
            PyErr_Format(PyExc_TypeError,
1050
0
                         "third item of state should be a dict, got a %.200s",
1051
0
                         Py_TYPE(dict)->tp_name);
1052
0
            return NULL;
1053
0
        }
1054
0
        if (self->dict) {
1055
            /* Alternatively, we could replace the internal dictionary
1056
               completely. However, it seems more practical to just update it. */
1057
0
            if (PyDict_Update(self->dict, dict) < 0)
1058
0
                return NULL;
1059
0
        }
1060
0
        else {
1061
            /* The LOAD_ATTR specializations read the dict slot lock-free
1062
               with an acquire load, so pair it with a release store. */
1063
0
            FT_ATOMIC_STORE_PTR_RELEASE(self->dict, Py_NewRef(dict));
1064
0
        }
1065
0
    }
1066
1067
0
    Py_RETURN_NONE;
1068
0
}
1069
1070
static void
1071
bytesio_dealloc(PyObject *op)
1072
52.6k
{
1073
52.6k
    bytesio *self = bytesio_CAST(op);
1074
52.6k
    PyTypeObject *tp = Py_TYPE(self);
1075
52.6k
    _PyObject_GC_UNTRACK(self);
1076
52.6k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
1077
0
        PyErr_SetString(PyExc_SystemError,
1078
0
                        "deallocated BytesIO object has exported buffers");
1079
0
        PyErr_Print();
1080
0
    }
1081
52.6k
    Py_CLEAR(self->buf);
1082
52.6k
    Py_CLEAR(self->dict);
1083
52.6k
    FT_CLEAR_WEAKREFS(op, self->weakreflist);
1084
52.6k
    tp->tp_free(self);
1085
52.6k
    Py_DECREF(tp);
1086
52.6k
}
1087
1088
static PyObject *
1089
bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1090
52.6k
{
1091
52.6k
    bytesio *self;
1092
1093
52.6k
    assert(type != NULL && type->tp_alloc != NULL);
1094
52.6k
    self = (bytesio *)type->tp_alloc(type, 0);
1095
52.6k
    if (self == NULL)
1096
0
        return NULL;
1097
1098
    /* tp_alloc initializes all the fields to zero. So we don't have to
1099
       initialize them here. */
1100
1101
52.6k
    self->buf = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
1102
52.6k
    if (self->buf == NULL) {
1103
0
        Py_DECREF(self);
1104
0
        return PyErr_NoMemory();
1105
0
    }
1106
1107
52.6k
    return (PyObject *)self;
1108
52.6k
}
1109
1110
/*[clinic input]
1111
@critical_section
1112
_io.BytesIO.__init__
1113
    initial_bytes as initvalue: object(c_default="NULL") = b''
1114
1115
Buffered I/O implementation using an in-memory bytes buffer.
1116
[clinic start generated code]*/
1117
1118
static int
1119
_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
1120
/*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/
1121
52.6k
{
1122
52.6k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
1123
0
        PyErr_SetString(PyExc_BufferError,
1124
0
                        "Existing exports of data: object cannot be re-sized");
1125
0
        return -1;
1126
0
    }
1127
1128
    /* In case, __init__ is called multiple times. */
1129
52.6k
    self->string_size = 0;
1130
52.6k
    self->pos = 0;
1131
1132
52.6k
    if (initvalue && initvalue != Py_None) {
1133
46.8k
        if (PyBytes_CheckExact(initvalue)) {
1134
46.8k
            Py_XSETREF(self->buf, Py_NewRef(initvalue));
1135
46.8k
            clear_shared_buf(self);
1136
46.8k
            self->string_size = PyBytes_GET_SIZE(initvalue);
1137
46.8k
        }
1138
0
        else {
1139
0
            PyObject *res;
1140
0
            res = _io_BytesIO_write_impl(self, initvalue);
1141
0
            if (res == NULL)
1142
0
                return -1;
1143
0
            Py_DECREF(res);
1144
0
            self->pos = 0;
1145
0
        }
1146
46.8k
    }
1147
1148
52.6k
    return 0;
1149
52.6k
}
1150
1151
1152
/*[clinic input]
1153
@critical_section
1154
_io.BytesIO.__sizeof__
1155
1156
Size of object in memory, in bytes.
1157
[clinic start generated code]*/
1158
1159
static PyObject *
1160
_io_BytesIO___sizeof___impl(bytesio *self)
1161
/*[clinic end generated code: output=f61b601bd055c4de input=6f01c36e6ff64c17]*/
1162
0
{
1163
0
    size_t res = _PyObject_SIZE(Py_TYPE(self));
1164
0
    if (self->buf && !SHARED_BUF(self)) {
1165
0
        size_t s = _PySys_GetSizeOf(self->buf);
1166
0
        if (s == (size_t)-1) {
1167
0
            return NULL;
1168
0
        }
1169
0
        res += s;
1170
0
    }
1171
0
    return PyLong_FromSize_t(res);
1172
0
}
1173
1174
static int
1175
bytesio_traverse(PyObject *op, visitproc visit, void *arg)
1176
8.61k
{
1177
8.61k
    bytesio *self = bytesio_CAST(op);
1178
8.61k
    Py_VISIT(Py_TYPE(self));
1179
8.61k
    Py_VISIT(self->dict);
1180
8.61k
    Py_VISIT(self->buf);
1181
8.61k
    return 0;
1182
8.61k
}
1183
1184
static int
1185
bytesio_clear(PyObject *op)
1186
0
{
1187
0
    bytesio *self = bytesio_CAST(op);
1188
0
    Py_CLEAR(self->dict);
1189
0
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
1190
0
        Py_CLEAR(self->buf);
1191
0
    }
1192
0
    return 0;
1193
0
}
1194
1195
1196
#define clinic_state() (find_io_state_by_def(Py_TYPE(self)))
1197
#include "clinic/bytesio.c.h"
1198
#undef clinic_state
1199
1200
static PyGetSetDef bytesio_getsetlist[] = {
1201
    _IO_BYTESIO_CLOSED_GETSETDEF
1202
    {NULL},            /* sentinel */
1203
};
1204
1205
static struct PyMethodDef bytesio_methods[] = {
1206
    _IO_BYTESIO_READABLE_METHODDEF
1207
    _IO_BYTESIO_SEEKABLE_METHODDEF
1208
    _IO_BYTESIO_WRITABLE_METHODDEF
1209
    _IO_BYTESIO_CLOSE_METHODDEF
1210
    _IO_BYTESIO_FLUSH_METHODDEF
1211
    _IO_BYTESIO_ISATTY_METHODDEF
1212
    _IO_BYTESIO_TELL_METHODDEF
1213
    _IO_BYTESIO_WRITE_METHODDEF
1214
    _IO_BYTESIO_WRITELINES_METHODDEF
1215
    _IO_BYTESIO_READ1_METHODDEF
1216
    _IO_BYTESIO_READINTO_METHODDEF
1217
    _IO_BYTESIO_READLINE_METHODDEF
1218
    _IO_BYTESIO_READLINES_METHODDEF
1219
    _IO_BYTESIO_READ_METHODDEF
1220
    _IO_BYTESIO_PEEK_METHODDEF
1221
    _IO_BYTESIO_GETBUFFER_METHODDEF
1222
    _IO_BYTESIO_GETVALUE_METHODDEF
1223
    _IO_BYTESIO_SEEK_METHODDEF
1224
    _IO_BYTESIO_TRUNCATE_METHODDEF
1225
    _IO_BYTESIO___GETSTATE___METHODDEF
1226
    _IO_BYTESIO___SETSTATE___METHODDEF
1227
    _IO_BYTESIO___SIZEOF___METHODDEF
1228
    {NULL, NULL}        /* sentinel */
1229
};
1230
1231
static PyMemberDef bytesio_members[] = {
1232
    {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(bytesio, weakreflist), Py_READONLY},
1233
    {"__dictoffset__", Py_T_PYSSIZET, offsetof(bytesio, dict), Py_READONLY},
1234
    {NULL}
1235
};
1236
1237
static PyType_Slot bytesio_slots[] = {
1238
    {Py_tp_dealloc, bytesio_dealloc},
1239
    {Py_tp_doc, (void *)_io_BytesIO___init____doc__},
1240
    {Py_tp_traverse, bytesio_traverse},
1241
    {Py_tp_clear, bytesio_clear},
1242
    {Py_tp_iter, PyObject_SelfIter},
1243
    {Py_tp_iternext, bytesio_iternext},
1244
    {Py_tp_methods, bytesio_methods},
1245
    {Py_tp_members, bytesio_members},
1246
    {Py_tp_getset, bytesio_getsetlist},
1247
    {Py_tp_init, _io_BytesIO___init__},
1248
    {Py_tp_new, bytesio_new},
1249
    {0, NULL},
1250
};
1251
1252
PyType_Spec _Py_bytesio_spec = {
1253
    .name = "_io.BytesIO",
1254
    .basicsize = sizeof(bytesio),
1255
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1256
              Py_TPFLAGS_IMMUTABLETYPE),
1257
    .slots = bytesio_slots,
1258
};
1259
1260
/*
1261
 * Implementation of the small intermediate object used by getbuffer().
1262
 * getbuffer() returns a memoryview over this object, which should make it
1263
 * invisible from Python code.
1264
 */
1265
1266
static int
1267
bytesiobuf_getbuffer_lock_held(PyObject *op, Py_buffer *view, int flags)
1268
0
{
1269
0
    bytesiobuf *obj = bytesiobuf_CAST(op);
1270
0
    bytesio *b = bytesio_CAST(obj->source);
1271
1272
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(b);
1273
1274
0
    if (check_closed(b)) {
1275
0
        return -1;
1276
0
    }
1277
0
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(b->exports) == 0 && SHARED_BUF(b)) {
1278
0
        if (unshare_buffer_lock_held(b, b->string_size) < 0)
1279
0
            return -1;
1280
0
    }
1281
1282
    /* cannot fail if view != NULL and readonly == 0 */
1283
0
    (void)PyBuffer_FillInfo(view, op,
1284
0
                            PyBytes_AS_STRING(b->buf), b->string_size,
1285
0
                            0, flags);
1286
    /* Keep the internal buffer alive: the bytesio object can be closed
1287
       while the buffer is exported. */
1288
0
    view->internal = Py_NewRef(b->buf);
1289
0
    FT_ATOMIC_ADD_SSIZE(b->exports, 1);
1290
0
    return 0;
1291
0
}
1292
1293
static int
1294
bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
1295
0
{
1296
0
    if (view == NULL) {
1297
0
        PyErr_SetString(PyExc_BufferError,
1298
0
            "bytesiobuf_getbuffer: view==NULL argument is obsolete");
1299
0
        return -1;
1300
0
    }
1301
1302
0
    int ret;
1303
0
    Py_BEGIN_CRITICAL_SECTION(bytesiobuf_CAST(op)->source);
1304
0
    ret = bytesiobuf_getbuffer_lock_held(op, view, flags);
1305
0
    Py_END_CRITICAL_SECTION();
1306
0
    return ret;
1307
0
}
1308
1309
static void
1310
bytesiobuf_releasebuffer(PyObject *op, Py_buffer *view)
1311
0
{
1312
0
    bytesiobuf *obj = bytesiobuf_CAST(op);
1313
0
    bytesio *b = bytesio_CAST(obj->source);
1314
0
    FT_ATOMIC_ADD_SSIZE(b->exports, -1);
1315
0
    Py_CLEAR(view->internal);
1316
0
}
1317
1318
static int
1319
bytesiobuf_traverse(PyObject *op, visitproc visit, void *arg)
1320
0
{
1321
0
    bytesiobuf *self = bytesiobuf_CAST(op);
1322
0
    Py_VISIT(Py_TYPE(self));
1323
0
    Py_VISIT(self->source);
1324
0
    return 0;
1325
0
}
1326
1327
static void
1328
bytesiobuf_dealloc(PyObject *op)
1329
0
{
1330
0
    bytesiobuf *self = bytesiobuf_CAST(op);
1331
0
    PyTypeObject *tp = Py_TYPE(self);
1332
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1333
0
    PyObject_GC_UnTrack(op);
1334
0
    Py_CLEAR(self->source);
1335
0
    tp->tp_free(self);
1336
0
    Py_DECREF(tp);
1337
0
}
1338
1339
static PyType_Slot bytesiobuf_slots[] = {
1340
    {Py_tp_dealloc, bytesiobuf_dealloc},
1341
    {Py_tp_traverse, bytesiobuf_traverse},
1342
1343
    // Buffer protocol
1344
    {Py_bf_getbuffer, bytesiobuf_getbuffer},
1345
    {Py_bf_releasebuffer, bytesiobuf_releasebuffer},
1346
    {0, NULL},
1347
};
1348
1349
PyType_Spec _Py_bytesiobuf_spec = {
1350
    .name = "_io._BytesIOBuffer",
1351
    .basicsize = sizeof(bytesiobuf),
1352
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1353
              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
1354
    .slots = bytesiobuf_slots,
1355
};