Coverage Report

Created: 2025-07-04 06:49

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