Coverage Report

Created: 2025-08-26 06:26

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