Coverage Report

Created: 2026-07-14 06:16

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