Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Modules/_io/stringio.c
Line
Count
Source
1
#include "Python.h"
2
#include <stddef.h>               // offsetof()
3
#include "pycore_object.h"
4
#include "pycore_weakref.h"       // FT_CLEAR_WEAKREFS()
5
#include "_iomodule.h"
6
7
/* Implementation note: the buffer is always at least one character longer
8
   than the enclosed string, for proper functioning of _PyIO_find_line_ending.
9
*/
10
11
26.7M
#define STATE_REALIZED 1
12
230k
#define STATE_ACCUMULATING 2
13
14
/*[clinic input]
15
module _io
16
class _io.StringIO "stringio *" "clinic_state()->PyStringIO_Type"
17
[clinic start generated code]*/
18
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2693eada0658d470]*/
19
20
typedef struct {
21
    PyObject_HEAD
22
    Py_UCS4 *buf;
23
    Py_ssize_t pos;
24
    Py_ssize_t string_size;
25
    size_t buf_size;
26
27
    /* The stringio object can be in two states: accumulating or realized.
28
       In accumulating state, the internal buffer contains nothing and
29
       the contents are given by the embedded _PyUnicodeWriter structure.
30
       In realized state, the internal buffer is meaningful and the
31
       _PyUnicodeWriter is destroyed.
32
    */
33
    int state;
34
    PyUnicodeWriter *writer;
35
36
    char ok; /* initialized? */
37
    char closed;
38
    char readuniversal;
39
    char readtranslate;
40
    PyObject *decoder;
41
    PyObject *readnl;
42
    PyObject *writenl;
43
44
    PyObject *dict;
45
    PyObject *weakreflist;
46
    _PyIO_State *module_state;
47
} stringio;
48
49
91.0k
#define stringio_CAST(op)   ((stringio *)(op))
50
51
#define clinic_state() (find_io_state_by_def(Py_TYPE(self)))
52
#include "clinic/stringio.c.h"
53
#undef clinic_state
54
55
static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs);
56
57
#define CHECK_INITIALIZED(self) \
58
26.8M
    if (self->ok <= 0) { \
59
0
        PyErr_SetString(PyExc_ValueError, \
60
0
            "I/O operation on uninitialized object"); \
61
0
        return NULL; \
62
0
    }
63
64
#define CHECK_CLOSED(self) \
65
26.8M
    if (self->closed) { \
66
0
        PyErr_SetString(PyExc_ValueError, \
67
0
            "I/O operation on closed file"); \
68
0
        return NULL; \
69
0
    }
70
71
#define CHECK_INITIALIZED_INT(self) \
72
45.2k
    if (self->ok <= 0) { \
73
0
        PyErr_SetString(PyExc_ValueError, \
74
0
            "I/O operation on uninitialized object"); \
75
0
        return -1; \
76
0
    }
77
78
#define CHECK_CLOSED_INT(self) \
79
0
    if (self->closed) { \
80
0
        PyErr_SetString(PyExc_ValueError, \
81
0
            "I/O operation on closed file"); \
82
0
        return -1; \
83
0
    }
84
85
#define ENSURE_REALIZED(self) \
86
26.7M
    if (realize(self) < 0) { \
87
0
        return NULL; \
88
0
    }
89
90
91
/* Internal routine for changing the size, in terms of characters, of the
92
   buffer of StringIO objects.  The caller should ensure that the 'size'
93
   argument is non-negative.  Returns 0 on success, -1 otherwise. */
94
static int
95
resize_buffer(stringio *self, size_t size)
96
159k
{
97
    /* Here, unsigned types are used to avoid dealing with signed integer
98
       overflow, which is undefined in C. */
99
159k
    size_t alloc = self->buf_size;
100
159k
    Py_UCS4 *new_buf = NULL;
101
102
159k
    assert(self->buf != NULL);
103
104
    /* Reserve one more char for line ending detection. */
105
159k
    size = size + 1;
106
    /* For simplicity, stay in the range of the signed type. Anyway, Python
107
       doesn't allow strings to be longer than this. */
108
159k
    if (size > PY_SSIZE_T_MAX)
109
0
        goto overflow;
110
111
159k
    if (size < alloc / 2) {
112
        /* Major downsize; resize down to exact size. */
113
38.8k
        alloc = size + 1;
114
38.8k
    }
115
121k
    else if (size < alloc) {
116
        /* Within allocated size; quick exit */
117
2.58k
        return 0;
118
2.58k
    }
119
118k
    else if (size <= alloc * 1.125) {
120
        /* Moderate upsize; overallocate similar to list_resize() */
121
4.99k
        alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
122
4.99k
    }
123
113k
    else {
124
        /* Major upsize; resize up to exact size */
125
113k
        alloc = size + 1;
126
113k
    }
127
128
157k
    if (alloc > SIZE_MAX / sizeof(Py_UCS4))
129
0
        goto overflow;
130
157k
    new_buf = (Py_UCS4 *)PyMem_Realloc(self->buf, alloc * sizeof(Py_UCS4));
131
157k
    if (new_buf == NULL) {
132
0
        PyErr_NoMemory();
133
0
        return -1;
134
0
    }
135
157k
    self->buf_size = alloc;
136
157k
    self->buf = new_buf;
137
138
157k
    return 0;
139
140
0
  overflow:
141
0
    PyErr_SetString(PyExc_OverflowError,
142
0
                    "new buffer size too large");
143
0
    return -1;
144
157k
}
145
146
static PyObject *
147
make_intermediate(stringio *self)
148
27
{
149
27
    PyObject *intermediate = PyUnicodeWriter_Finish(self->writer);
150
27
    self->writer = NULL;
151
27
    self->state = STATE_REALIZED;
152
27
    if (intermediate == NULL)
153
0
        return NULL;
154
155
27
    self->writer = PyUnicodeWriter_Create(0);
156
27
    if (self->writer == NULL) {
157
0
        Py_DECREF(intermediate);
158
0
        return NULL;
159
0
    }
160
27
    if (PyUnicodeWriter_WriteStr(self->writer, intermediate)) {
161
0
        Py_DECREF(intermediate);
162
0
        return NULL;
163
0
    }
164
27
    self->state = STATE_ACCUMULATING;
165
27
    return intermediate;
166
27
}
167
168
static int
169
realize(stringio *self)
170
26.7M
{
171
26.7M
    Py_ssize_t len;
172
26.7M
    PyObject *intermediate;
173
174
26.7M
    if (self->state == STATE_REALIZED)
175
26.6M
        return 0;
176
26.7M
    assert(self->state == STATE_ACCUMULATING);
177
16.5k
    self->state = STATE_REALIZED;
178
179
16.5k
    intermediate = PyUnicodeWriter_Finish(self->writer);
180
16.5k
    self->writer = NULL;
181
16.5k
    if (intermediate == NULL)
182
0
        return -1;
183
184
    /* Append the intermediate string to the internal buffer.
185
       The length should be equal to the current cursor position.
186
     */
187
16.5k
    len = PyUnicode_GET_LENGTH(intermediate);
188
16.5k
    if (resize_buffer(self, len) < 0) {
189
0
        Py_DECREF(intermediate);
190
0
        return -1;
191
0
    }
192
16.5k
    if (!PyUnicode_AsUCS4(intermediate, self->buf, len, 0)) {
193
0
        Py_DECREF(intermediate);
194
0
        return -1;
195
0
    }
196
197
16.5k
    Py_DECREF(intermediate);
198
16.5k
    return 0;
199
16.5k
}
200
201
/* Internal routine for writing a whole PyUnicode object to the buffer of a
202
   StringIO object. Returns 0 on success, or -1 on error. */
203
static Py_ssize_t
204
write_str(stringio *self, PyObject *obj)
205
89.9k
{
206
89.9k
    Py_ssize_t len;
207
89.9k
    PyObject *decoded = NULL;
208
209
89.9k
    assert(self->buf != NULL);
210
89.9k
    assert(self->pos >= 0);
211
212
89.9k
    if (self->decoder != NULL) {
213
67.5k
        decoded = _PyIncrementalNewlineDecoder_decode(
214
67.5k
            self->decoder, obj, 1 /* always final */);
215
67.5k
    }
216
22.3k
    else {
217
22.3k
        decoded = Py_NewRef(obj);
218
22.3k
    }
219
89.9k
    if (self->writenl) {
220
0
        PyObject *translated = PyUnicode_Replace(
221
0
            decoded, _Py_LATIN1_CHR('\n'), self->writenl, -1);
222
0
        Py_SETREF(decoded, translated);
223
0
    }
224
89.9k
    if (decoded == NULL)
225
0
        return -1;
226
227
89.9k
    assert(PyUnicode_Check(decoded));
228
89.9k
    len = PyUnicode_GET_LENGTH(decoded);
229
89.9k
    assert(len >= 0);
230
231
    /* This overflow check is not strictly necessary. However, it avoids us to
232
       deal with funky things like comparing an unsigned and a signed
233
       integer. */
234
89.9k
    if (self->pos > PY_SSIZE_T_MAX - len) {
235
0
        PyErr_SetString(PyExc_OverflowError,
236
0
                        "new position too large");
237
0
        goto fail;
238
0
    }
239
240
89.9k
    if (self->state == STATE_ACCUMULATING) {
241
24.3k
        if (self->string_size == self->pos) {
242
            // gh-149046: Avoid PyUnicodeWriter_WriteStr() which calls str(obj)
243
            // on str subclasses
244
24.3k
            if (_PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)self->writer, decoded))
245
0
                goto fail;
246
24.3k
            goto success;
247
24.3k
        }
248
0
        if (realize(self))
249
0
            goto fail;
250
0
    }
251
252
65.5k
    if (self->pos + len > self->string_size) {
253
65.5k
        if (resize_buffer(self, self->pos + len) < 0)
254
0
            goto fail;
255
65.5k
    }
256
257
65.5k
    if (self->pos > self->string_size) {
258
        /* In case of overseek, pad with null bytes the buffer region between
259
           the end of stream and the current position.
260
261
          0   lo      string_size                           hi
262
          |   |<---used--->|<----------available----------->|
263
          |   |            <--to pad-->|<---to write--->    |
264
          0   buf                   position
265
266
        */
267
0
        memset(self->buf + self->string_size, '\0',
268
0
               (self->pos - self->string_size) * sizeof(Py_UCS4));
269
0
    }
270
271
    /* Copy the data to the internal buffer, overwriting some of the
272
       existing data if self->pos < self->string_size. */
273
65.5k
    if (!PyUnicode_AsUCS4(decoded,
274
65.5k
                          self->buf + self->pos,
275
65.5k
                          self->buf_size - self->pos,
276
65.5k
                          0))
277
0
        goto fail;
278
279
89.9k
success:
280
    /* Set the new length of the internal string if it has changed. */
281
89.9k
    self->pos += len;
282
89.9k
    if (self->string_size < self->pos)
283
89.9k
        self->string_size = self->pos;
284
285
89.9k
    Py_DECREF(decoded);
286
89.9k
    return 0;
287
288
0
fail:
289
0
    Py_XDECREF(decoded);
290
0
    return -1;
291
65.5k
}
292
293
/*[clinic input]
294
@critical_section
295
_io.StringIO.getvalue
296
297
Retrieve the entire contents of the object.
298
[clinic start generated code]*/
299
300
static PyObject *
301
_io_StringIO_getvalue_impl(stringio *self)
302
/*[clinic end generated code: output=27b6a7bfeaebce01 input=fb5dee06b8d467f3]*/
303
0
{
304
0
    CHECK_INITIALIZED(self);
305
0
    CHECK_CLOSED(self);
306
0
    if (self->state == STATE_ACCUMULATING)
307
0
        return make_intermediate(self);
308
0
    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, self->buf,
309
0
                                     self->string_size);
310
0
}
311
312
/*[clinic input]
313
@critical_section
314
_io.StringIO.tell
315
316
Tell the current file position.
317
[clinic start generated code]*/
318
319
static PyObject *
320
_io_StringIO_tell_impl(stringio *self)
321
/*[clinic end generated code: output=2e87ac67b116c77b input=98a08f3e2dae3550]*/
322
0
{
323
0
    CHECK_INITIALIZED(self);
324
0
    CHECK_CLOSED(self);
325
0
    return PyLong_FromSsize_t(self->pos);
326
0
}
327
328
/*[clinic input]
329
@critical_section
330
_io.StringIO.read
331
    size: Py_ssize_t(accept={int, NoneType}) = -1
332
    /
333
334
Read at most size characters, returned as a string.
335
336
If the argument is negative or omitted, read until EOF
337
is reached. Return an empty string at EOF.
338
[clinic start generated code]*/
339
340
static PyObject *
341
_io_StringIO_read_impl(stringio *self, Py_ssize_t size)
342
/*[clinic end generated code: output=ae8cf6002f71626c input=9fbef45d8aece8e7]*/
343
62.1k
{
344
62.1k
    Py_ssize_t n;
345
62.1k
    Py_UCS4 *output;
346
347
62.1k
    CHECK_INITIALIZED(self);
348
62.1k
    CHECK_CLOSED(self);
349
350
    /* adjust invalid sizes */
351
62.1k
    n = self->string_size - self->pos;
352
62.1k
    if (size < 0 || size > n) {
353
32.7k
        size = n;
354
32.7k
        if (size < 0)
355
0
            size = 0;
356
32.7k
    }
357
358
    /* Optimization for seek(0); read() */
359
62.1k
    if (self->state == STATE_ACCUMULATING && self->pos == 0 && size == n) {
360
27
        PyObject *result = make_intermediate(self);
361
27
        self->pos = self->string_size;
362
27
        return result;
363
27
    }
364
365
62.0k
    ENSURE_REALIZED(self);
366
62.0k
    output = self->buf + self->pos;
367
62.0k
    self->pos += size;
368
62.0k
    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output, size);
369
62.0k
}
370
371
/* Internal helper, used by stringio_readline and stringio_iternext */
372
static PyObject *
373
_stringio_readline(stringio *self, Py_ssize_t limit)
374
26.6M
{
375
26.6M
    Py_UCS4 *start, *end, old_char;
376
26.6M
    Py_ssize_t len, consumed;
377
378
    /* In case of overseek, return the empty string */
379
26.6M
    if (self->pos >= self->string_size)
380
43.3k
        return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
381
382
26.5M
    start = self->buf + self->pos;
383
26.5M
    if (limit < 0 || limit > self->string_size - self->pos)
384
26.5M
        limit = self->string_size - self->pos;
385
386
26.5M
    end = start + limit;
387
26.5M
    old_char = *end;
388
26.5M
    *end = '\0';
389
26.5M
    len = _PyIO_find_line_ending(
390
26.5M
        self->readtranslate, self->readuniversal, self->readnl,
391
26.5M
        PyUnicode_4BYTE_KIND, (char*)start, (char*)end, &consumed);
392
26.5M
    *end = old_char;
393
    /* If we haven't found any line ending, we just return everything
394
       (`consumed` is ignored). */
395
26.5M
    if (len < 0)
396
37.9k
        len = limit;
397
26.5M
    self->pos += len;
398
26.5M
    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len);
399
26.6M
}
400
401
/*[clinic input]
402
@critical_section
403
_io.StringIO.readline
404
    size: Py_ssize_t(accept={int, NoneType}) = -1
405
    /
406
407
Read until newline or EOF.
408
409
Returns an empty string if EOF is hit immediately.
410
[clinic start generated code]*/
411
412
static PyObject *
413
_io_StringIO_readline_impl(stringio *self, Py_ssize_t size)
414
/*[clinic end generated code: output=cabd6452f1b7e85d input=4d14b8495dea1d98]*/
415
68
{
416
68
    CHECK_INITIALIZED(self);
417
68
    CHECK_CLOSED(self);
418
68
    ENSURE_REALIZED(self);
419
420
68
    return _stringio_readline(self, size);
421
68
}
422
423
/*[clinic input]
424
@critical_section
425
_io.StringIO.__next__ as stringio_iternext
426
[clinic start generated code]*/
427
428
static PyObject *
429
stringio_iternext_impl(stringio *self)
430
/*[clinic end generated code: output=51eb3991b1c79c41 input=b6cf3e73fab6b42e]*/
431
26.6M
{
432
26.6M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
433
434
26.6M
    PyObject *line;
435
436
26.6M
    CHECK_INITIALIZED(self);
437
26.6M
    CHECK_CLOSED(self);
438
26.6M
    ENSURE_REALIZED(self);
439
440
26.6M
    if (Py_IS_TYPE(self, self->module_state->PyStringIO_Type)) {
441
        /* Skip method call overhead for speed */
442
26.6M
        line = _stringio_readline(self, -1);
443
26.6M
    }
444
0
    else {
445
        /* XXX is subclassing StringIO really supported? */
446
0
        line = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(readline));
447
0
        if (line && !PyUnicode_Check(line)) {
448
0
            PyErr_Format(PyExc_OSError,
449
0
                         "readline() should have returned a str object, "
450
0
                         "not '%.200s'", Py_TYPE(line)->tp_name);
451
0
            Py_DECREF(line);
452
0
            return NULL;
453
0
        }
454
0
    }
455
456
26.6M
    if (line == NULL)
457
0
        return NULL;
458
459
26.6M
    if (PyUnicode_GET_LENGTH(line) == 0) {
460
        /* Reached EOF */
461
43.2k
        Py_DECREF(line);
462
43.2k
        return NULL;
463
43.2k
    }
464
465
26.5M
    return line;
466
26.6M
}
467
468
/*[clinic input]
469
@critical_section
470
_io.StringIO.truncate
471
    pos: object = None
472
    /
473
474
Truncate size to pos.
475
476
The pos argument defaults to the current file position, as
477
returned by tell().  The current file position is unchanged.
478
Returns the new absolute position.
479
[clinic start generated code]*/
480
481
static PyObject *
482
_io_StringIO_truncate_impl(stringio *self, PyObject *pos)
483
/*[clinic end generated code: output=c76c43b5ecfaf4e2 input=d59fd2ee49757ae6]*/
484
39.3k
{
485
39.3k
    CHECK_INITIALIZED(self);
486
39.3k
    CHECK_CLOSED(self);
487
488
39.3k
    Py_ssize_t size;
489
39.3k
    if (pos == Py_None) {
490
39.3k
        size = self->pos;
491
39.3k
    }
492
0
    else {
493
0
        size = PyNumber_AsSsize_t(pos, PyExc_OverflowError);
494
0
        if (size == -1 && PyErr_Occurred()) {
495
0
            return NULL;
496
0
        }
497
0
        if (size < 0) {
498
0
            PyErr_Format(PyExc_ValueError,
499
0
                         "negative pos value %zd", size);
500
0
            return NULL;
501
0
        }
502
        /* __index__ may have closed or reinitialized the stream. */
503
0
        CHECK_INITIALIZED(self);
504
0
        CHECK_CLOSED(self);
505
0
    }
506
507
39.3k
    if (size < self->string_size) {
508
38.8k
        ENSURE_REALIZED(self);
509
38.8k
        if (resize_buffer(self, size) < 0)
510
0
            return NULL;
511
38.8k
        self->string_size = size;
512
38.8k
    }
513
514
39.3k
    return PyLong_FromSsize_t(size);
515
39.3k
}
516
517
/*[clinic input]
518
@critical_section
519
_io.StringIO.seek
520
    pos: Py_ssize_t
521
    whence: int = 0
522
    /
523
524
Change stream position.
525
526
Seek to character offset pos relative to position indicated by
527
whence:
528
    0  Start of stream (the default).  pos should be >= 0;
529
    1  Current position - pos must be 0;
530
    2  End of stream - pos must be 0.
531
Returns the new absolute position.
532
[clinic start generated code]*/
533
534
static PyObject *
535
_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence)
536
/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=ffef24668fd71a5d]*/
537
78.7k
{
538
78.7k
    CHECK_INITIALIZED(self);
539
78.7k
    CHECK_CLOSED(self);
540
541
78.7k
    if (whence != 0 && whence != 1 && whence != 2) {
542
0
        PyErr_Format(PyExc_ValueError,
543
0
                     "Invalid whence (%i, should be 0, 1 or 2)", whence);
544
0
        return NULL;
545
0
    }
546
78.7k
    else if (pos < 0 && whence == 0) {
547
0
        PyErr_Format(PyExc_ValueError,
548
0
                     "Negative seek position %zd", pos);
549
0
        return NULL;
550
0
    }
551
78.7k
    else if (whence != 0 && pos != 0) {
552
0
        PyErr_SetString(PyExc_OSError,
553
0
                        "Can't do nonzero cur-relative seeks");
554
0
        return NULL;
555
0
    }
556
557
    /* whence = 0: offset relative to beginning of the string.
558
       whence = 1: no change to current position.
559
       whence = 2: change position to end of file. */
560
78.7k
    if (whence == 1) {
561
0
        pos = self->pos;
562
0
    }
563
78.7k
    else if (whence == 2) {
564
0
        pos = self->string_size;
565
0
    }
566
567
78.7k
    self->pos = pos;
568
569
78.7k
    return PyLong_FromSsize_t(self->pos);
570
78.7k
}
571
572
/*[clinic input]
573
@critical_section
574
_io.StringIO.write
575
    s as obj: object
576
    /
577
578
Write string to file.
579
580
Returns the number of characters written, which is always equal to
581
the length of the string.
582
[clinic start generated code]*/
583
584
static PyObject *
585
_io_StringIO_write_impl(stringio *self, PyObject *obj)
586
/*[clinic end generated code: output=d53b1d841d7db288 input=1561272c0da4651f]*/
587
67.5k
{
588
67.5k
    Py_ssize_t size;
589
590
67.5k
    CHECK_INITIALIZED(self);
591
67.5k
    if (!PyUnicode_Check(obj)) {
592
0
        PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
593
0
                     Py_TYPE(obj)->tp_name);
594
0
        return NULL;
595
0
    }
596
67.5k
    CHECK_CLOSED(self);
597
67.5k
    size = PyUnicode_GET_LENGTH(obj);
598
599
67.5k
    if (size > 0 && write_str(self, obj) < 0)
600
0
        return NULL;
601
602
67.5k
    return PyLong_FromSsize_t(size);
603
67.5k
}
604
605
/*[clinic input]
606
@critical_section
607
_io.StringIO.close
608
609
Close the IO object.
610
611
Attempting any further operation after the object is closed
612
will raise a ValueError.
613
614
This method has no effect if the file is already closed.
615
[clinic start generated code]*/
616
617
static PyObject *
618
_io_StringIO_close_impl(stringio *self)
619
/*[clinic end generated code: output=04399355cbe518f1 input=305d19aa29cc40b9]*/
620
0
{
621
0
    self->closed = 1;
622
    /* Free up some memory */
623
0
    if (resize_buffer(self, 0) < 0)
624
0
        return NULL;
625
0
    PyUnicodeWriter_Discard(self->writer);
626
0
    self->writer = NULL;
627
0
    Py_CLEAR(self->readnl);
628
0
    Py_CLEAR(self->writenl);
629
0
    Py_CLEAR(self->decoder);
630
0
    Py_RETURN_NONE;
631
0
}
632
633
static int
634
stringio_traverse(PyObject *op, visitproc visit, void *arg)
635
13.1k
{
636
13.1k
    stringio *self = stringio_CAST(op);
637
13.1k
    Py_VISIT(Py_TYPE(self));
638
13.1k
    Py_VISIT(self->readnl);
639
13.1k
    Py_VISIT(self->writenl);
640
13.1k
    Py_VISIT(self->decoder);
641
13.1k
    Py_VISIT(self->dict);
642
13.1k
    return 0;
643
13.1k
}
644
645
static int
646
stringio_clear(PyObject *op)
647
38.9k
{
648
38.9k
    stringio *self = stringio_CAST(op);
649
38.9k
    Py_CLEAR(self->readnl);
650
38.9k
    Py_CLEAR(self->writenl);
651
38.9k
    Py_CLEAR(self->decoder);
652
38.9k
    Py_CLEAR(self->dict);
653
38.9k
    return 0;
654
38.9k
}
655
656
static void
657
stringio_dealloc(PyObject *op)
658
38.9k
{
659
38.9k
    stringio *self = stringio_CAST(op);
660
38.9k
    PyTypeObject *tp = Py_TYPE(self);
661
38.9k
    _PyObject_GC_UNTRACK(self);
662
38.9k
    self->ok = 0;
663
38.9k
    if (self->buf) {
664
38.9k
        PyMem_Free(self->buf);
665
38.9k
        self->buf = NULL;
666
38.9k
    }
667
38.9k
    PyUnicodeWriter_Discard(self->writer);
668
38.9k
    (void)stringio_clear(op);
669
38.9k
    FT_CLEAR_WEAKREFS(op, self->weakreflist);
670
38.9k
    tp->tp_free(self);
671
38.9k
    Py_DECREF(tp);
672
38.9k
}
673
674
static PyObject *
675
stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
676
38.9k
{
677
38.9k
    stringio *self;
678
679
38.9k
    assert(type != NULL && type->tp_alloc != NULL);
680
38.9k
    self = (stringio *)type->tp_alloc(type, 0);
681
38.9k
    if (self == NULL)
682
0
        return NULL;
683
684
    /* tp_alloc initializes all the fields to zero. So we don't have to
685
       initialize them here. */
686
687
38.9k
    self->buf = (Py_UCS4 *)PyMem_Malloc(0);
688
38.9k
    if (self->buf == NULL) {
689
0
        Py_DECREF(self);
690
0
        return PyErr_NoMemory();
691
0
    }
692
693
38.9k
    return (PyObject *)self;
694
38.9k
}
695
696
/*[clinic input]
697
_io.StringIO.__init__
698
    initial_value as value: object(c_default="NULL") = ''
699
    newline as newline_obj: object(c_default="NULL") = '\n'
700
701
Text I/O implementation using an in-memory buffer.
702
703
The initial_value argument sets the value of object.  The newline
704
argument is like the one of TextIOWrapper's constructor.
705
[clinic start generated code]*/
706
707
static int
708
_io_StringIO___init___impl(stringio *self, PyObject *value,
709
                           PyObject *newline_obj)
710
/*[clinic end generated code: output=a421ea023b22ef4e input=cee2d9181b2577a3]*/
711
38.9k
{
712
38.9k
    const char *newline = "\n";
713
38.9k
    Py_ssize_t value_len;
714
715
    /* Parse the newline argument. We only want to allow unicode objects or
716
       None. */
717
38.9k
    if (newline_obj == Py_None) {
718
0
        newline = NULL;
719
0
    }
720
38.9k
    else if (newline_obj) {
721
16.5k
        if (!PyUnicode_Check(newline_obj)) {
722
0
            PyErr_Format(PyExc_TypeError,
723
0
                         "newline must be str or None, not %.200s",
724
0
                         Py_TYPE(newline_obj)->tp_name);
725
0
            return -1;
726
0
        }
727
16.5k
        newline = PyUnicode_AsUTF8(newline_obj);
728
16.5k
        if (newline == NULL)
729
0
            return -1;
730
16.5k
    }
731
732
38.9k
    if (newline && newline[0] != '\0'
733
22.3k
        && !(newline[0] == '\n' && newline[1] == '\0')
734
0
        && !(newline[0] == '\r' && newline[1] == '\0')
735
0
        && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
736
0
        PyErr_Format(PyExc_ValueError,
737
0
                     "illegal newline value: %R", newline_obj);
738
0
        return -1;
739
0
    }
740
38.9k
    if (value && value != Py_None && !PyUnicode_Check(value)) {
741
0
        PyErr_Format(PyExc_TypeError,
742
0
                     "initial_value must be str or None, not %.200s",
743
0
                     Py_TYPE(value)->tp_name);
744
0
        return -1;
745
0
    }
746
747
38.9k
    self->ok = 0;
748
749
38.9k
    PyUnicodeWriter_Discard(self->writer);
750
38.9k
    self->writer = NULL;
751
38.9k
    Py_CLEAR(self->readnl);
752
38.9k
    Py_CLEAR(self->writenl);
753
38.9k
    Py_CLEAR(self->decoder);
754
755
38.9k
    assert((newline != NULL && newline_obj != Py_None) ||
756
38.9k
           (newline == NULL && newline_obj == Py_None));
757
758
38.9k
    if (newline) {
759
38.9k
        self->readnl = PyUnicode_FromString(newline);
760
38.9k
        if (self->readnl == NULL)
761
0
            return -1;
762
38.9k
    }
763
38.9k
    self->readuniversal = (newline == NULL || newline[0] == '\0');
764
38.9k
    self->readtranslate = (newline == NULL);
765
    /* If newline == "", we don't translate anything.
766
       If newline == "\n" or newline == None, we translate to "\n", which is
767
       a no-op.
768
       (for newline == None, TextIOWrapper translates to os.linesep, but it
769
       is pointless for StringIO)
770
    */
771
38.9k
    if (newline != NULL && newline[0] == '\r') {
772
0
        self->writenl = Py_NewRef(self->readnl);
773
0
    }
774
775
38.9k
    _PyIO_State *module_state = find_io_state_by_def(Py_TYPE(self));
776
38.9k
    if (self->readuniversal) {
777
16.5k
        self->decoder = PyObject_CallFunctionObjArgs(
778
16.5k
            (PyObject *)module_state->PyIncrementalNewlineDecoder_Type,
779
16.5k
            Py_None, self->readtranslate ? Py_True : Py_False, NULL);
780
16.5k
        if (self->decoder == NULL)
781
0
            return -1;
782
16.5k
    }
783
784
    /* Now everything is set up, resize buffer to size of initial value,
785
       and copy it */
786
38.9k
    self->string_size = 0;
787
38.9k
    if (value && value != Py_None)
788
22.3k
        value_len = PyUnicode_GetLength(value);
789
16.5k
    else
790
16.5k
        value_len = 0;
791
38.9k
    if (value_len > 0) {
792
        /* This is a heuristic, for newline translation might change
793
           the string length. */
794
22.3k
        if (resize_buffer(self, 0) < 0)
795
0
            return -1;
796
22.3k
        self->state = STATE_REALIZED;
797
22.3k
        self->pos = 0;
798
22.3k
        if (write_str(self, value) < 0)
799
0
            return -1;
800
22.3k
    }
801
16.5k
    else {
802
        /* Empty stringio object, we can start by accumulating */
803
16.5k
        if (resize_buffer(self, 0) < 0)
804
0
            return -1;
805
16.5k
        self->writer = PyUnicodeWriter_Create(0);
806
16.5k
        if (self->writer == NULL) {
807
0
            return -1;
808
0
        }
809
16.5k
        self->state = STATE_ACCUMULATING;
810
16.5k
    }
811
38.9k
    self->pos = 0;
812
38.9k
    self->module_state = module_state;
813
38.9k
    self->closed = 0;
814
38.9k
    self->ok = 1;
815
38.9k
    return 0;
816
38.9k
}
817
818
/* Properties and pseudo-properties */
819
820
/*[clinic input]
821
@critical_section
822
_io.StringIO.readable
823
824
Returns True if the IO object can be read.
825
[clinic start generated code]*/
826
827
static PyObject *
828
_io_StringIO_readable_impl(stringio *self)
829
/*[clinic end generated code: output=b19d44dd8b1ceb99 input=6cd2ffd65a8e8763]*/
830
0
{
831
0
    CHECK_INITIALIZED(self);
832
0
    CHECK_CLOSED(self);
833
0
    Py_RETURN_TRUE;
834
0
}
835
836
/*[clinic input]
837
@critical_section
838
_io.StringIO.writable
839
840
Returns True if the IO object can be written.
841
[clinic start generated code]*/
842
843
static PyObject *
844
_io_StringIO_writable_impl(stringio *self)
845
/*[clinic end generated code: output=13e4dd77187074ca input=1b3c63dbaa761c69]*/
846
0
{
847
0
    CHECK_INITIALIZED(self);
848
0
    CHECK_CLOSED(self);
849
0
    Py_RETURN_TRUE;
850
0
}
851
852
/*[clinic input]
853
@critical_section
854
_io.StringIO.seekable
855
856
Returns True if the IO object can be seeked.
857
[clinic start generated code]*/
858
859
static PyObject *
860
_io_StringIO_seekable_impl(stringio *self)
861
/*[clinic end generated code: output=4d20b4641c756879 input=a820fad2cf085fc3]*/
862
0
{
863
0
    CHECK_INITIALIZED(self);
864
0
    CHECK_CLOSED(self);
865
0
    Py_RETURN_TRUE;
866
0
}
867
868
/* Pickling support.
869
870
   The implementation of __getstate__ is similar to the one for BytesIO,
871
   except that we also save the newline parameter. For __setstate__ and unlike
872
   BytesIO, we call __init__ to restore the object's state. Doing so allows us
873
   to avoid decoding the complex newline state while keeping the object
874
   representation compact.
875
876
   See comment in bytesio.c regarding why only pickle protocols and onward are
877
   supported.
878
*/
879
880
/*[clinic input]
881
@critical_section
882
_io.StringIO.__getstate__
883
884
[clinic start generated code]*/
885
886
static PyObject *
887
_io_StringIO___getstate___impl(stringio *self)
888
/*[clinic end generated code: output=780be4a996410199 input=76f27255ef83bb92]*/
889
0
{
890
0
    PyObject *initvalue = _io_StringIO_getvalue_impl(self);
891
0
    PyObject *dict;
892
0
    PyObject *state;
893
894
0
    if (initvalue == NULL)
895
0
        return NULL;
896
0
    if (self->dict == NULL) {
897
0
        dict = Py_NewRef(Py_None);
898
0
    }
899
0
    else {
900
0
        dict = PyDict_Copy(self->dict);
901
0
        if (dict == NULL) {
902
0
            Py_DECREF(initvalue);
903
0
            return NULL;
904
0
        }
905
0
    }
906
907
0
    state = Py_BuildValue("(OOnN)", initvalue,
908
0
                          self->readnl ? self->readnl : Py_None,
909
0
                          self->pos, dict);
910
0
    Py_DECREF(initvalue);
911
0
    return state;
912
0
}
913
914
/*[clinic input]
915
@critical_section
916
_io.StringIO.__setstate__
917
918
    state: object
919
    /
920
[clinic start generated code]*/
921
922
static PyObject *
923
_io_StringIO___setstate___impl(stringio *self, PyObject *state)
924
/*[clinic end generated code: output=cb3962bc6d5c5609 input=8a27784b11b82e47]*/
925
0
{
926
0
    PyObject *initarg;
927
0
    PyObject *position_obj;
928
0
    PyObject *dict;
929
0
    Py_ssize_t pos;
930
931
0
    assert(state != NULL);
932
0
    CHECK_CLOSED(self);
933
934
    /* We allow the state tuple to be longer than 4, because we may need
935
       someday to extend the object's state without breaking
936
       backward-compatibility. */
937
0
    if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) < 4) {
938
0
        PyErr_Format(PyExc_TypeError,
939
0
                     "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
940
0
                     Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
941
0
        return NULL;
942
0
    }
943
944
    /* Initialize the object's state. */
945
0
    initarg = PyTuple_GetSlice(state, 0, 2);
946
0
    if (initarg == NULL)
947
0
        return NULL;
948
0
    if (_io_StringIO___init__((PyObject *)self, initarg, NULL) < 0) {
949
0
        Py_DECREF(initarg);
950
0
        return NULL;
951
0
    }
952
0
    Py_DECREF(initarg);
953
954
    /* Restore the buffer state. Even if __init__ did initialize the buffer,
955
       we have to initialize it again since __init__ may translate the
956
       newlines in the initial_value string. We clearly do not want that
957
       because the string value in the state tuple has already been translated
958
       once by __init__. So we do not take any chance and replace object's
959
       buffer completely. */
960
0
    {
961
0
        PyObject *item = PyTuple_GET_ITEM(state, 0);
962
0
        if (PyUnicode_Check(item)) {
963
0
            Py_UCS4 *buf = PyUnicode_AsUCS4Copy(item);
964
0
            if (buf == NULL)
965
0
                return NULL;
966
0
            Py_ssize_t bufsize = PyUnicode_GET_LENGTH(item);
967
968
0
            if (resize_buffer(self, bufsize) < 0) {
969
0
                PyMem_Free(buf);
970
0
                return NULL;
971
0
            }
972
0
            memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
973
0
            PyMem_Free(buf);
974
0
            self->string_size = bufsize;
975
0
        }
976
0
        else {
977
0
            assert(item == Py_None);
978
0
            self->string_size = 0;
979
0
        }
980
0
    }
981
982
    /* Set carefully the position value. Alternatively, we could use the seek
983
       method instead of modifying self->pos directly to better protect the
984
       object internal state against erroneous (or malicious) inputs. */
985
0
    position_obj = PyTuple_GET_ITEM(state, 2);
986
0
    if (!PyLong_Check(position_obj)) {
987
0
        PyErr_Format(PyExc_TypeError,
988
0
                     "third item of state must be an integer, got %.200s",
989
0
                     Py_TYPE(position_obj)->tp_name);
990
0
        return NULL;
991
0
    }
992
0
    pos = PyLong_AsSsize_t(position_obj);
993
0
    if (pos == -1 && PyErr_Occurred())
994
0
        return NULL;
995
0
    if (pos < 0) {
996
0
        PyErr_SetString(PyExc_ValueError,
997
0
                        "position value cannot be negative");
998
0
        return NULL;
999
0
    }
1000
0
    self->pos = pos;
1001
1002
    /* Set the dictionary of the instance variables. */
1003
0
    dict = PyTuple_GET_ITEM(state, 3);
1004
0
    if (dict != Py_None) {
1005
0
        if (!PyDict_Check(dict)) {
1006
0
            PyErr_Format(PyExc_TypeError,
1007
0
                         "fourth item of state should be a dict, got a %.200s",
1008
0
                         Py_TYPE(dict)->tp_name);
1009
0
            return NULL;
1010
0
        }
1011
0
        if (self->dict) {
1012
            /* Alternatively, we could replace the internal dictionary
1013
               completely. However, it seems more practical to just update it. */
1014
0
            if (PyDict_Update(self->dict, dict) < 0)
1015
0
                return NULL;
1016
0
        }
1017
0
        else {
1018
0
            self->dict = Py_NewRef(dict);
1019
0
        }
1020
0
    }
1021
1022
0
    Py_RETURN_NONE;
1023
0
}
1024
1025
/*[clinic input]
1026
@critical_section
1027
@getter
1028
_io.StringIO.closed -> bool
1029
[clinic start generated code]*/
1030
1031
static int
1032
_io_StringIO_closed_get_impl(stringio *self)
1033
/*[clinic end generated code: output=754068c44422cafa input=ea05e89b945e721c]*/
1034
45.2k
{
1035
45.2k
    CHECK_INITIALIZED_INT(self);
1036
45.2k
    return self->closed;
1037
45.2k
}
1038
1039
/*[clinic input]
1040
@critical_section
1041
@getter
1042
_io.StringIO.line_buffering -> bool
1043
[clinic start generated code]*/
1044
1045
static int
1046
_io_StringIO_line_buffering_get_impl(stringio *self)
1047
/*[clinic end generated code: output=56c0edde9001fb37 input=326f8b3bd1feb699]*/
1048
0
{
1049
0
    CHECK_INITIALIZED_INT(self);
1050
0
    CHECK_CLOSED_INT(self);
1051
0
    return 0;
1052
0
}
1053
1054
/*[clinic input]
1055
@critical_section
1056
@getter
1057
_io.StringIO.newlines
1058
[clinic start generated code]*/
1059
1060
static PyObject *
1061
_io_StringIO_newlines_get_impl(stringio *self)
1062
/*[clinic end generated code: output=35d7c0b66d7e0160 input=092a14586718244b]*/
1063
0
{
1064
0
    CHECK_INITIALIZED(self);
1065
0
    CHECK_CLOSED(self);
1066
0
    if (self->decoder == NULL) {
1067
0
        Py_RETURN_NONE;
1068
0
    }
1069
0
    return PyObject_GetAttr(self->decoder, &_Py_ID(newlines));
1070
0
}
1071
1072
static struct PyMethodDef stringio_methods[] = {
1073
    _IO_STRINGIO_CLOSE_METHODDEF
1074
    _IO_STRINGIO_GETVALUE_METHODDEF
1075
    _IO_STRINGIO_READ_METHODDEF
1076
    _IO_STRINGIO_READLINE_METHODDEF
1077
    _IO_STRINGIO_TELL_METHODDEF
1078
    _IO_STRINGIO_TRUNCATE_METHODDEF
1079
    _IO_STRINGIO_SEEK_METHODDEF
1080
    _IO_STRINGIO_WRITE_METHODDEF
1081
1082
    _IO_STRINGIO_SEEKABLE_METHODDEF
1083
    _IO_STRINGIO_READABLE_METHODDEF
1084
    _IO_STRINGIO_WRITABLE_METHODDEF
1085
1086
    _IO_STRINGIO___GETSTATE___METHODDEF
1087
    _IO_STRINGIO___SETSTATE___METHODDEF
1088
    {NULL, NULL}        /* sentinel */
1089
};
1090
1091
static PyGetSetDef stringio_getset[] = {
1092
    _IO_STRINGIO_CLOSED_GETSETDEF
1093
    _IO_STRINGIO_NEWLINES_GETSETDEF
1094
    /*  (following comments straight off of the original Python wrapper:)
1095
        XXX Cruft to support the TextIOWrapper API. This would only
1096
        be meaningful if StringIO supported the buffer attribute.
1097
        Hopefully, a better solution, than adding these pseudo-attributes,
1098
        will be found.
1099
    */
1100
    _IO_STRINGIO_LINE_BUFFERING_GETSETDEF
1101
    {NULL}
1102
};
1103
1104
static struct PyMemberDef stringio_members[] = {
1105
    {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(stringio, weakreflist), Py_READONLY},
1106
    {"__dictoffset__", Py_T_PYSSIZET, offsetof(stringio, dict), Py_READONLY},
1107
    {NULL},
1108
};
1109
1110
static PyType_Slot stringio_slots[] = {
1111
    {Py_tp_dealloc, stringio_dealloc},
1112
    {Py_tp_doc, (void *)_io_StringIO___init____doc__},
1113
    {Py_tp_traverse, stringio_traverse},
1114
    {Py_tp_clear, stringio_clear},
1115
    {Py_tp_iternext, stringio_iternext},
1116
    {Py_tp_methods, stringio_methods},
1117
    {Py_tp_members, stringio_members},
1118
    {Py_tp_getset, stringio_getset},
1119
    {Py_tp_init, _io_StringIO___init__},
1120
    {Py_tp_new, stringio_new},
1121
    {0, NULL},
1122
};
1123
1124
PyType_Spec _Py_stringio_spec = {
1125
    .name = "_io.StringIO",
1126
    .basicsize = sizeof(stringio),
1127
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1128
              Py_TPFLAGS_IMMUTABLETYPE),
1129
    .slots = stringio_slots,
1130
};