Coverage Report

Created: 2026-10-17 06:15

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.3M
#define STATE_REALIZED 1
12
218k
#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
26.3M
#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.4M
    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.4M
    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
43.8k
    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.3M
    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
153k
{
97
    /* Here, unsigned types are used to avoid dealing with signed integer
98
       overflow, which is undefined in C. */
99
153k
    size_t alloc = self->buf_size;
100
153k
    Py_UCS4 *new_buf = NULL;
101
102
153k
    assert(self->buf != NULL);
103
104
    /* Reserve one more char for line ending detection. */
105
153k
    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
153k
    if (size > PY_SSIZE_T_MAX)
109
0
        goto overflow;
110
111
153k
    if (size < alloc / 2) {
112
        /* Major downsize; resize down to exact size. */
113
37.5k
        alloc = size + 1;
114
37.5k
    }
115
116k
    else if (size < alloc) {
116
        /* Within allocated size; quick exit */
117
1.94k
        return 0;
118
1.94k
    }
119
114k
    else if (size <= alloc * 1.125) {
120
        /* Moderate upsize; overallocate similar to list_resize() */
121
4.71k
        alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
122
4.71k
    }
123
109k
    else {
124
        /* Major upsize; resize up to exact size */
125
109k
        alloc = size + 1;
126
109k
    }
127
128
151k
    if (alloc > SIZE_MAX / sizeof(Py_UCS4))
129
0
        goto overflow;
130
151k
    new_buf = (Py_UCS4 *)PyMem_Realloc(self->buf, alloc * sizeof(Py_UCS4));
131
151k
    if (new_buf == NULL) {
132
0
        PyErr_NoMemory();
133
0
        return -1;
134
0
    }
135
151k
    self->buf_size = alloc;
136
151k
    self->buf = new_buf;
137
138
151k
    return 0;
139
140
0
  overflow:
141
0
    PyErr_SetString(PyExc_OverflowError,
142
0
                    "new buffer size too large");
143
0
    return -1;
144
151k
}
145
146
static PyObject *
147
make_intermediate(stringio *self)
148
30
{
149
30
    PyObject *intermediate = PyUnicodeWriter_Finish(self->writer);
150
30
    self->writer = NULL;
151
30
    self->state = STATE_REALIZED;
152
30
    if (intermediate == NULL)
153
0
        return NULL;
154
155
30
    self->writer = PyUnicodeWriter_Create(0);
156
30
    if (self->writer == NULL) {
157
0
        Py_DECREF(intermediate);
158
0
        return NULL;
159
0
    }
160
30
    if (PyUnicodeWriter_WriteStr(self->writer, intermediate)) {
161
0
        Py_DECREF(intermediate);
162
0
        return NULL;
163
0
    }
164
30
    self->state = STATE_ACCUMULATING;
165
30
    return intermediate;
166
30
}
167
168
static int
169
realize(stringio *self)
170
26.3M
{
171
26.3M
    Py_ssize_t len;
172
26.3M
    PyObject *intermediate;
173
174
26.3M
    if (self->state == STATE_REALIZED)
175
26.3M
        return 0;
176
26.3M
    assert(self->state == STATE_ACCUMULATING);
177
15.9k
    self->state = STATE_REALIZED;
178
179
15.9k
    intermediate = PyUnicodeWriter_Finish(self->writer);
180
15.9k
    self->writer = NULL;
181
15.9k
    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
15.9k
    len = PyUnicode_GET_LENGTH(intermediate);
188
15.9k
    if (resize_buffer(self, len) < 0) {
189
0
        Py_DECREF(intermediate);
190
0
        return -1;
191
0
    }
192
15.9k
    if (!PyUnicode_AsUCS4(intermediate, self->buf, len, 0)) {
193
0
        Py_DECREF(intermediate);
194
0
        return -1;
195
0
    }
196
197
15.9k
    Py_DECREF(intermediate);
198
15.9k
    return 0;
199
15.9k
}
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
85.6k
{
206
85.6k
    Py_ssize_t len;
207
85.6k
    PyObject *decoded = NULL;
208
209
85.6k
    assert(self->buf != NULL);
210
85.6k
    assert(self->pos >= 0);
211
212
85.6k
    if (self->decoder != NULL) {
213
63.9k
        decoded = _PyIncrementalNewlineDecoder_decode(
214
63.9k
            self->decoder, obj, 1 /* always final */);
215
63.9k
    }
216
21.7k
    else {
217
21.7k
        decoded = Py_NewRef(obj);
218
21.7k
    }
219
85.6k
    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
85.6k
    if (decoded == NULL)
225
0
        return -1;
226
227
85.6k
    assert(PyUnicode_Check(decoded));
228
85.6k
    len = PyUnicode_GET_LENGTH(decoded);
229
85.6k
    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
85.6k
    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
85.6k
    if (self->state == STATE_ACCUMULATING) {
241
23.1k
        if (self->string_size == self->pos) {
242
            // gh-149046: Avoid PyUnicodeWriter_WriteStr() which calls str(obj)
243
            // on str subclasses
244
23.1k
            if (_PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)self->writer, decoded))
245
0
                goto fail;
246
23.1k
            goto success;
247
23.1k
        }
248
0
        if (realize(self))
249
0
            goto fail;
250
0
    }
251
252
62.5k
    if (self->pos + len > self->string_size) {
253
62.5k
        if (resize_buffer(self, self->pos + len) < 0)
254
0
            goto fail;
255
62.5k
    }
256
257
62.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
62.5k
    if (!PyUnicode_AsUCS4(decoded,
274
62.5k
                          self->buf + self->pos,
275
62.5k
                          self->buf_size - self->pos,
276
62.5k
                          0))
277
0
        goto fail;
278
279
85.6k
success:
280
    /* Set the new length of the internal string if it has changed. */
281
85.6k
    self->pos += len;
282
85.6k
    if (self->string_size < self->pos)
283
85.6k
        self->string_size = self->pos;
284
285
85.6k
    Py_DECREF(decoded);
286
85.6k
    return 0;
287
288
0
fail:
289
0
    Py_XDECREF(decoded);
290
0
    return -1;
291
62.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
58.5k
{
344
58.5k
    Py_ssize_t n;
345
58.5k
    Py_UCS4 *output;
346
347
58.5k
    CHECK_INITIALIZED(self);
348
58.5k
    CHECK_CLOSED(self);
349
350
    /* adjust invalid sizes */
351
58.5k
    n = self->string_size - self->pos;
352
58.5k
    if (size < 0 || size > n) {
353
31.6k
        size = n;
354
31.6k
        if (size < 0)
355
0
            size = 0;
356
31.6k
    }
357
358
    /* Optimization for seek(0); read() */
359
58.5k
    if (self->state == STATE_ACCUMULATING && self->pos == 0 && size == n) {
360
30
        PyObject *result = make_intermediate(self);
361
30
        self->pos = self->string_size;
362
30
        return result;
363
30
    }
364
365
58.5k
    ENSURE_REALIZED(self);
366
58.5k
    output = self->buf + self->pos;
367
58.5k
    self->pos += size;
368
58.5k
    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output, size);
369
58.5k
}
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.2M
{
375
26.2M
    Py_UCS4 *start, *end, old_char;
376
26.2M
    Py_ssize_t len, consumed;
377
378
    /* In case of overseek, return the empty string */
379
26.2M
    if (self->pos >= self->string_size)
380
41.9k
        return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
381
382
26.1M
    start = self->buf + self->pos;
383
26.1M
    if (limit < 0 || limit > self->string_size - self->pos)
384
26.1M
        limit = self->string_size - self->pos;
385
386
26.1M
    end = start + limit;
387
26.1M
    old_char = *end;
388
26.1M
    *end = '\0';
389
26.1M
    len = _PyIO_find_line_ending(
390
26.1M
        self->readtranslate, self->readuniversal, self->readnl,
391
26.1M
        PyUnicode_4BYTE_KIND, (char*)start, (char*)end, &consumed);
392
26.1M
    *end = old_char;
393
    /* If we haven't found any line ending, we just return everything
394
       (`consumed` is ignored). */
395
26.1M
    if (len < 0)
396
36.7k
        len = limit;
397
26.1M
    self->pos += len;
398
26.1M
    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len);
399
26.2M
}
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
static PyObject *
424
stringio_iternext_lock_held(PyObject *op)
425
26.2M
{
426
26.2M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
427
428
26.2M
    PyObject *line;
429
26.2M
    stringio *self = stringio_CAST(op);
430
431
26.2M
    CHECK_INITIALIZED(self);
432
26.2M
    CHECK_CLOSED(self);
433
26.2M
    ENSURE_REALIZED(self);
434
435
26.2M
    if (Py_IS_TYPE(self, self->module_state->PyStringIO_Type)) {
436
        /* Skip method call overhead for speed */
437
26.2M
        line = _stringio_readline(self, -1);
438
26.2M
    }
439
0
    else {
440
        /* XXX is subclassing StringIO really supported? */
441
0
        line = PyObject_CallMethodNoArgs(op, &_Py_ID(readline));
442
0
        if (line && !PyUnicode_Check(line)) {
443
0
            PyErr_Format(PyExc_OSError,
444
0
                         "readline() should have returned a str object, "
445
0
                         "not '%.200s'", Py_TYPE(line)->tp_name);
446
0
            Py_DECREF(line);
447
0
            return NULL;
448
0
        }
449
0
    }
450
451
26.2M
    if (line == NULL)
452
0
        return NULL;
453
454
26.2M
    if (PyUnicode_GET_LENGTH(line) == 0) {
455
        /* Reached EOF */
456
41.9k
        Py_DECREF(line);
457
41.9k
        return NULL;
458
41.9k
    }
459
460
26.1M
    return line;
461
26.2M
}
462
463
static PyObject *
464
stringio_iternext(PyObject *op)
465
26.2M
{
466
26.2M
    PyObject *ret;
467
26.2M
    Py_BEGIN_CRITICAL_SECTION(op);
468
26.2M
    ret = stringio_iternext_lock_held(op);
469
26.2M
    Py_END_CRITICAL_SECTION();
470
26.2M
    return ret;
471
26.2M
}
472
473
/*[clinic input]
474
@critical_section
475
_io.StringIO.truncate
476
    pos: object = None
477
    /
478
479
Truncate size to pos.
480
481
The pos argument defaults to the current file position, as
482
returned by tell().  The current file position is unchanged.
483
Returns the new absolute position.
484
[clinic start generated code]*/
485
486
static PyObject *
487
_io_StringIO_truncate_impl(stringio *self, PyObject *pos)
488
/*[clinic end generated code: output=c76c43b5ecfaf4e2 input=d59fd2ee49757ae6]*/
489
38.0k
{
490
38.0k
    CHECK_INITIALIZED(self);
491
38.0k
    CHECK_CLOSED(self);
492
493
38.0k
    Py_ssize_t size;
494
38.0k
    if (pos == Py_None) {
495
38.0k
        size = self->pos;
496
38.0k
    }
497
0
    else {
498
0
        size = PyLong_AsLong(pos);
499
0
        if (size == -1 && PyErr_Occurred()) {
500
0
            return NULL;
501
0
        }
502
0
        if (size < 0) {
503
0
            PyErr_Format(PyExc_ValueError,
504
0
                         "negative pos value %zd", size);
505
0
            return NULL;
506
0
        }
507
0
    }
508
509
38.0k
    if (size < self->string_size) {
510
37.5k
        ENSURE_REALIZED(self);
511
37.5k
        if (resize_buffer(self, size) < 0)
512
0
            return NULL;
513
37.5k
        self->string_size = size;
514
37.5k
    }
515
516
38.0k
    return PyLong_FromSsize_t(size);
517
38.0k
}
518
519
/*[clinic input]
520
@critical_section
521
_io.StringIO.seek
522
    pos: Py_ssize_t
523
    whence: int = 0
524
    /
525
526
Change stream position.
527
528
Seek to character offset pos relative to position indicated by
529
whence:
530
    0  Start of stream (the default).  pos should be >= 0;
531
    1  Current position - pos must be 0;
532
    2  End of stream - pos must be 0.
533
Returns the new absolute position.
534
[clinic start generated code]*/
535
536
static PyObject *
537
_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence)
538
/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=ffef24668fd71a5d]*/
539
76.1k
{
540
76.1k
    CHECK_INITIALIZED(self);
541
76.1k
    CHECK_CLOSED(self);
542
543
76.1k
    if (whence != 0 && whence != 1 && whence != 2) {
544
0
        PyErr_Format(PyExc_ValueError,
545
0
                     "Invalid whence (%i, should be 0, 1 or 2)", whence);
546
0
        return NULL;
547
0
    }
548
76.1k
    else if (pos < 0 && whence == 0) {
549
0
        PyErr_Format(PyExc_ValueError,
550
0
                     "Negative seek position %zd", pos);
551
0
        return NULL;
552
0
    }
553
76.1k
    else if (whence != 0 && pos != 0) {
554
0
        PyErr_SetString(PyExc_OSError,
555
0
                        "Can't do nonzero cur-relative seeks");
556
0
        return NULL;
557
0
    }
558
559
    /* whence = 0: offset relative to beginning of the string.
560
       whence = 1: no change to current position.
561
       whence = 2: change position to end of file. */
562
76.1k
    if (whence == 1) {
563
0
        pos = self->pos;
564
0
    }
565
76.1k
    else if (whence == 2) {
566
0
        pos = self->string_size;
567
0
    }
568
569
76.1k
    self->pos = pos;
570
571
76.1k
    return PyLong_FromSsize_t(self->pos);
572
76.1k
}
573
574
/*[clinic input]
575
@critical_section
576
_io.StringIO.write
577
    s as obj: object
578
    /
579
580
Write string to file.
581
582
Returns the number of characters written, which is always equal to
583
the length of the string.
584
[clinic start generated code]*/
585
586
static PyObject *
587
_io_StringIO_write_impl(stringio *self, PyObject *obj)
588
/*[clinic end generated code: output=d53b1d841d7db288 input=1561272c0da4651f]*/
589
63.9k
{
590
63.9k
    Py_ssize_t size;
591
592
63.9k
    CHECK_INITIALIZED(self);
593
63.9k
    if (!PyUnicode_Check(obj)) {
594
0
        PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
595
0
                     Py_TYPE(obj)->tp_name);
596
0
        return NULL;
597
0
    }
598
63.9k
    CHECK_CLOSED(self);
599
63.9k
    size = PyUnicode_GET_LENGTH(obj);
600
601
63.9k
    if (size > 0 && write_str(self, obj) < 0)
602
0
        return NULL;
603
604
63.9k
    return PyLong_FromSsize_t(size);
605
63.9k
}
606
607
/*[clinic input]
608
@critical_section
609
_io.StringIO.close
610
611
Close the IO object.
612
613
Attempting any further operation after the object is closed
614
will raise a ValueError.
615
616
This method has no effect if the file is already closed.
617
[clinic start generated code]*/
618
619
static PyObject *
620
_io_StringIO_close_impl(stringio *self)
621
/*[clinic end generated code: output=04399355cbe518f1 input=305d19aa29cc40b9]*/
622
0
{
623
0
    self->closed = 1;
624
    /* Free up some memory */
625
0
    if (resize_buffer(self, 0) < 0)
626
0
        return NULL;
627
0
    PyUnicodeWriter_Discard(self->writer);
628
0
    self->writer = NULL;
629
0
    Py_CLEAR(self->readnl);
630
0
    Py_CLEAR(self->writenl);
631
0
    Py_CLEAR(self->decoder);
632
0
    Py_RETURN_NONE;
633
0
}
634
635
static int
636
stringio_traverse(PyObject *op, visitproc visit, void *arg)
637
12.7k
{
638
12.7k
    stringio *self = stringio_CAST(op);
639
12.7k
    Py_VISIT(Py_TYPE(self));
640
12.7k
    Py_VISIT(self->readnl);
641
12.7k
    Py_VISIT(self->writenl);
642
12.7k
    Py_VISIT(self->decoder);
643
12.7k
    Py_VISIT(self->dict);
644
12.7k
    return 0;
645
12.7k
}
646
647
static int
648
stringio_clear(PyObject *op)
649
37.7k
{
650
37.7k
    stringio *self = stringio_CAST(op);
651
37.7k
    Py_CLEAR(self->readnl);
652
37.7k
    Py_CLEAR(self->writenl);
653
37.7k
    Py_CLEAR(self->decoder);
654
37.7k
    Py_CLEAR(self->dict);
655
37.7k
    return 0;
656
37.7k
}
657
658
static void
659
stringio_dealloc(PyObject *op)
660
37.7k
{
661
37.7k
    stringio *self = stringio_CAST(op);
662
37.7k
    PyTypeObject *tp = Py_TYPE(self);
663
37.7k
    _PyObject_GC_UNTRACK(self);
664
37.7k
    self->ok = 0;
665
37.7k
    if (self->buf) {
666
37.7k
        PyMem_Free(self->buf);
667
37.7k
        self->buf = NULL;
668
37.7k
    }
669
37.7k
    PyUnicodeWriter_Discard(self->writer);
670
37.7k
    (void)stringio_clear(op);
671
37.7k
    FT_CLEAR_WEAKREFS(op, self->weakreflist);
672
37.7k
    tp->tp_free(self);
673
37.7k
    Py_DECREF(tp);
674
37.7k
}
675
676
static PyObject *
677
stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
678
37.7k
{
679
37.7k
    stringio *self;
680
681
37.7k
    assert(type != NULL && type->tp_alloc != NULL);
682
37.7k
    self = (stringio *)type->tp_alloc(type, 0);
683
37.7k
    if (self == NULL)
684
0
        return NULL;
685
686
    /* tp_alloc initializes all the fields to zero. So we don't have to
687
       initialize them here. */
688
689
37.7k
    self->buf = (Py_UCS4 *)PyMem_Malloc(0);
690
37.7k
    if (self->buf == NULL) {
691
0
        Py_DECREF(self);
692
0
        return PyErr_NoMemory();
693
0
    }
694
695
37.7k
    return (PyObject *)self;
696
37.7k
}
697
698
/*[clinic input]
699
_io.StringIO.__init__
700
    initial_value as value: object(c_default="NULL") = ''
701
    newline as newline_obj: object(c_default="NULL") = '\n'
702
703
Text I/O implementation using an in-memory buffer.
704
705
The initial_value argument sets the value of object.  The newline
706
argument is like the one of TextIOWrapper's constructor.
707
[clinic start generated code]*/
708
709
static int
710
_io_StringIO___init___impl(stringio *self, PyObject *value,
711
                           PyObject *newline_obj)
712
/*[clinic end generated code: output=a421ea023b22ef4e input=cee2d9181b2577a3]*/
713
37.7k
{
714
37.7k
    const char *newline = "\n";
715
37.7k
    Py_ssize_t value_len;
716
717
    /* Parse the newline argument. We only want to allow unicode objects or
718
       None. */
719
37.7k
    if (newline_obj == Py_None) {
720
0
        newline = NULL;
721
0
    }
722
37.7k
    else if (newline_obj) {
723
15.9k
        if (!PyUnicode_Check(newline_obj)) {
724
0
            PyErr_Format(PyExc_TypeError,
725
0
                         "newline must be str or None, not %.200s",
726
0
                         Py_TYPE(newline_obj)->tp_name);
727
0
            return -1;
728
0
        }
729
15.9k
        newline = PyUnicode_AsUTF8(newline_obj);
730
15.9k
        if (newline == NULL)
731
0
            return -1;
732
15.9k
    }
733
734
37.7k
    if (newline && newline[0] != '\0'
735
21.7k
        && !(newline[0] == '\n' && newline[1] == '\0')
736
0
        && !(newline[0] == '\r' && newline[1] == '\0')
737
0
        && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
738
0
        PyErr_Format(PyExc_ValueError,
739
0
                     "illegal newline value: %R", newline_obj);
740
0
        return -1;
741
0
    }
742
37.7k
    if (value && value != Py_None && !PyUnicode_Check(value)) {
743
0
        PyErr_Format(PyExc_TypeError,
744
0
                     "initial_value must be str or None, not %.200s",
745
0
                     Py_TYPE(value)->tp_name);
746
0
        return -1;
747
0
    }
748
749
37.7k
    self->ok = 0;
750
751
37.7k
    PyUnicodeWriter_Discard(self->writer);
752
37.7k
    self->writer = NULL;
753
37.7k
    Py_CLEAR(self->readnl);
754
37.7k
    Py_CLEAR(self->writenl);
755
37.7k
    Py_CLEAR(self->decoder);
756
757
37.7k
    assert((newline != NULL && newline_obj != Py_None) ||
758
37.7k
           (newline == NULL && newline_obj == Py_None));
759
760
37.7k
    if (newline) {
761
37.7k
        self->readnl = PyUnicode_FromString(newline);
762
37.7k
        if (self->readnl == NULL)
763
0
            return -1;
764
37.7k
    }
765
37.7k
    self->readuniversal = (newline == NULL || newline[0] == '\0');
766
37.7k
    self->readtranslate = (newline == NULL);
767
    /* If newline == "", we don't translate anything.
768
       If newline == "\n" or newline == None, we translate to "\n", which is
769
       a no-op.
770
       (for newline == None, TextIOWrapper translates to os.linesep, but it
771
       is pointless for StringIO)
772
    */
773
37.7k
    if (newline != NULL && newline[0] == '\r') {
774
0
        self->writenl = Py_NewRef(self->readnl);
775
0
    }
776
777
37.7k
    _PyIO_State *module_state = find_io_state_by_def(Py_TYPE(self));
778
37.7k
    if (self->readuniversal) {
779
15.9k
        self->decoder = PyObject_CallFunctionObjArgs(
780
15.9k
            (PyObject *)module_state->PyIncrementalNewlineDecoder_Type,
781
15.9k
            Py_None, self->readtranslate ? Py_True : Py_False, NULL);
782
15.9k
        if (self->decoder == NULL)
783
0
            return -1;
784
15.9k
    }
785
786
    /* Now everything is set up, resize buffer to size of initial value,
787
       and copy it */
788
37.7k
    self->string_size = 0;
789
37.7k
    if (value && value != Py_None)
790
21.7k
        value_len = PyUnicode_GetLength(value);
791
15.9k
    else
792
15.9k
        value_len = 0;
793
37.7k
    if (value_len > 0) {
794
        /* This is a heuristic, for newline translation might change
795
           the string length. */
796
21.7k
        if (resize_buffer(self, 0) < 0)
797
0
            return -1;
798
21.7k
        self->state = STATE_REALIZED;
799
21.7k
        self->pos = 0;
800
21.7k
        if (write_str(self, value) < 0)
801
0
            return -1;
802
21.7k
    }
803
15.9k
    else {
804
        /* Empty stringio object, we can start by accumulating */
805
15.9k
        if (resize_buffer(self, 0) < 0)
806
0
            return -1;
807
15.9k
        self->writer = PyUnicodeWriter_Create(0);
808
15.9k
        if (self->writer == NULL) {
809
0
            return -1;
810
0
        }
811
15.9k
        self->state = STATE_ACCUMULATING;
812
15.9k
    }
813
37.7k
    self->pos = 0;
814
37.7k
    self->module_state = module_state;
815
37.7k
    self->closed = 0;
816
37.7k
    self->ok = 1;
817
37.7k
    return 0;
818
37.7k
}
819
820
/* Properties and pseudo-properties */
821
822
/*[clinic input]
823
@critical_section
824
_io.StringIO.readable
825
826
Returns True if the IO object can be read.
827
[clinic start generated code]*/
828
829
static PyObject *
830
_io_StringIO_readable_impl(stringio *self)
831
/*[clinic end generated code: output=b19d44dd8b1ceb99 input=6cd2ffd65a8e8763]*/
832
0
{
833
0
    CHECK_INITIALIZED(self);
834
0
    CHECK_CLOSED(self);
835
0
    Py_RETURN_TRUE;
836
0
}
837
838
/*[clinic input]
839
@critical_section
840
_io.StringIO.writable
841
842
Returns True if the IO object can be written.
843
[clinic start generated code]*/
844
845
static PyObject *
846
_io_StringIO_writable_impl(stringio *self)
847
/*[clinic end generated code: output=13e4dd77187074ca input=1b3c63dbaa761c69]*/
848
0
{
849
0
    CHECK_INITIALIZED(self);
850
0
    CHECK_CLOSED(self);
851
0
    Py_RETURN_TRUE;
852
0
}
853
854
/*[clinic input]
855
@critical_section
856
_io.StringIO.seekable
857
858
Returns True if the IO object can be seeked.
859
[clinic start generated code]*/
860
861
static PyObject *
862
_io_StringIO_seekable_impl(stringio *self)
863
/*[clinic end generated code: output=4d20b4641c756879 input=a820fad2cf085fc3]*/
864
0
{
865
0
    CHECK_INITIALIZED(self);
866
0
    CHECK_CLOSED(self);
867
0
    Py_RETURN_TRUE;
868
0
}
869
870
/* Pickling support.
871
872
   The implementation of __getstate__ is similar to the one for BytesIO,
873
   except that we also save the newline parameter. For __setstate__ and unlike
874
   BytesIO, we call __init__ to restore the object's state. Doing so allows us
875
   to avoid decoding the complex newline state while keeping the object
876
   representation compact.
877
878
   See comment in bytesio.c regarding why only pickle protocols and onward are
879
   supported.
880
*/
881
882
/*[clinic input]
883
@critical_section
884
_io.StringIO.__getstate__
885
886
[clinic start generated code]*/
887
888
static PyObject *
889
_io_StringIO___getstate___impl(stringio *self)
890
/*[clinic end generated code: output=780be4a996410199 input=76f27255ef83bb92]*/
891
0
{
892
0
    PyObject *initvalue = _io_StringIO_getvalue_impl(self);
893
0
    PyObject *dict;
894
0
    PyObject *state;
895
896
0
    if (initvalue == NULL)
897
0
        return NULL;
898
0
    if (self->dict == NULL) {
899
0
        dict = Py_NewRef(Py_None);
900
0
    }
901
0
    else {
902
0
        dict = PyDict_Copy(self->dict);
903
0
        if (dict == NULL) {
904
0
            Py_DECREF(initvalue);
905
0
            return NULL;
906
0
        }
907
0
    }
908
909
0
    state = Py_BuildValue("(OOnN)", initvalue,
910
0
                          self->readnl ? self->readnl : Py_None,
911
0
                          self->pos, dict);
912
0
    Py_DECREF(initvalue);
913
0
    return state;
914
0
}
915
916
/*[clinic input]
917
@critical_section
918
_io.StringIO.__setstate__
919
920
    state: object
921
    /
922
[clinic start generated code]*/
923
924
static PyObject *
925
_io_StringIO___setstate___impl(stringio *self, PyObject *state)
926
/*[clinic end generated code: output=cb3962bc6d5c5609 input=8a27784b11b82e47]*/
927
0
{
928
0
    PyObject *initarg;
929
0
    PyObject *position_obj;
930
0
    PyObject *dict;
931
0
    Py_ssize_t pos;
932
933
0
    assert(state != NULL);
934
0
    CHECK_CLOSED(self);
935
936
    /* We allow the state tuple to be longer than 4, because we may need
937
       someday to extend the object's state without breaking
938
       backward-compatibility. */
939
0
    if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) < 4) {
940
0
        PyErr_Format(PyExc_TypeError,
941
0
                     "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
942
0
                     Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
943
0
        return NULL;
944
0
    }
945
946
    /* Initialize the object's state. */
947
0
    initarg = PyTuple_GetSlice(state, 0, 2);
948
0
    if (initarg == NULL)
949
0
        return NULL;
950
0
    if (_io_StringIO___init__((PyObject *)self, initarg, NULL) < 0) {
951
0
        Py_DECREF(initarg);
952
0
        return NULL;
953
0
    }
954
0
    Py_DECREF(initarg);
955
956
    /* Restore the buffer state. Even if __init__ did initialize the buffer,
957
       we have to initialize it again since __init__ may translate the
958
       newlines in the initial_value string. We clearly do not want that
959
       because the string value in the state tuple has already been translated
960
       once by __init__. So we do not take any chance and replace object's
961
       buffer completely. */
962
0
    {
963
0
        PyObject *item = PyTuple_GET_ITEM(state, 0);
964
0
        if (PyUnicode_Check(item)) {
965
0
            Py_UCS4 *buf = PyUnicode_AsUCS4Copy(item);
966
0
            if (buf == NULL)
967
0
                return NULL;
968
0
            Py_ssize_t bufsize = PyUnicode_GET_LENGTH(item);
969
970
0
            if (resize_buffer(self, bufsize) < 0) {
971
0
                PyMem_Free(buf);
972
0
                return NULL;
973
0
            }
974
0
            memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
975
0
            PyMem_Free(buf);
976
0
            self->string_size = bufsize;
977
0
        }
978
0
        else {
979
0
            assert(item == Py_None);
980
0
            self->string_size = 0;
981
0
        }
982
0
    }
983
984
    /* Set carefully the position value. Alternatively, we could use the seek
985
       method instead of modifying self->pos directly to better protect the
986
       object internal state against erroneous (or malicious) inputs. */
987
0
    position_obj = PyTuple_GET_ITEM(state, 2);
988
0
    if (!PyLong_Check(position_obj)) {
989
0
        PyErr_Format(PyExc_TypeError,
990
0
                     "third item of state must be an integer, got %.200s",
991
0
                     Py_TYPE(position_obj)->tp_name);
992
0
        return NULL;
993
0
    }
994
0
    pos = PyLong_AsSsize_t(position_obj);
995
0
    if (pos == -1 && PyErr_Occurred())
996
0
        return NULL;
997
0
    if (pos < 0) {
998
0
        PyErr_SetString(PyExc_ValueError,
999
0
                        "position value cannot be negative");
1000
0
        return NULL;
1001
0
    }
1002
0
    self->pos = pos;
1003
1004
    /* Set the dictionary of the instance variables. */
1005
0
    dict = PyTuple_GET_ITEM(state, 3);
1006
0
    if (dict != Py_None) {
1007
0
        if (!PyDict_Check(dict)) {
1008
0
            PyErr_Format(PyExc_TypeError,
1009
0
                         "fourth item of state should be a dict, got a %.200s",
1010
0
                         Py_TYPE(dict)->tp_name);
1011
0
            return NULL;
1012
0
        }
1013
0
        if (self->dict) {
1014
            /* Alternatively, we could replace the internal dictionary
1015
               completely. However, it seems more practical to just update it. */
1016
0
            if (PyDict_Update(self->dict, dict) < 0)
1017
0
                return NULL;
1018
0
        }
1019
0
        else {
1020
0
            self->dict = Py_NewRef(dict);
1021
0
        }
1022
0
    }
1023
1024
0
    Py_RETURN_NONE;
1025
0
}
1026
1027
/*[clinic input]
1028
@critical_section
1029
@getter
1030
_io.StringIO.closed -> bool
1031
[clinic start generated code]*/
1032
1033
static int
1034
_io_StringIO_closed_get_impl(stringio *self)
1035
/*[clinic end generated code: output=754068c44422cafa input=ea05e89b945e721c]*/
1036
43.8k
{
1037
43.8k
    CHECK_INITIALIZED_INT(self);
1038
43.8k
    return self->closed;
1039
43.8k
}
1040
1041
/*[clinic input]
1042
@critical_section
1043
@getter
1044
_io.StringIO.line_buffering -> bool
1045
[clinic start generated code]*/
1046
1047
static int
1048
_io_StringIO_line_buffering_get_impl(stringio *self)
1049
/*[clinic end generated code: output=56c0edde9001fb37 input=326f8b3bd1feb699]*/
1050
0
{
1051
0
    CHECK_INITIALIZED_INT(self);
1052
0
    CHECK_CLOSED_INT(self);
1053
0
    return 0;
1054
0
}
1055
1056
/*[clinic input]
1057
@critical_section
1058
@getter
1059
_io.StringIO.newlines
1060
[clinic start generated code]*/
1061
1062
static PyObject *
1063
_io_StringIO_newlines_get_impl(stringio *self)
1064
/*[clinic end generated code: output=35d7c0b66d7e0160 input=092a14586718244b]*/
1065
0
{
1066
0
    CHECK_INITIALIZED(self);
1067
0
    CHECK_CLOSED(self);
1068
0
    if (self->decoder == NULL) {
1069
0
        Py_RETURN_NONE;
1070
0
    }
1071
0
    return PyObject_GetAttr(self->decoder, &_Py_ID(newlines));
1072
0
}
1073
1074
static struct PyMethodDef stringio_methods[] = {
1075
    _IO_STRINGIO_CLOSE_METHODDEF
1076
    _IO_STRINGIO_GETVALUE_METHODDEF
1077
    _IO_STRINGIO_READ_METHODDEF
1078
    _IO_STRINGIO_READLINE_METHODDEF
1079
    _IO_STRINGIO_TELL_METHODDEF
1080
    _IO_STRINGIO_TRUNCATE_METHODDEF
1081
    _IO_STRINGIO_SEEK_METHODDEF
1082
    _IO_STRINGIO_WRITE_METHODDEF
1083
1084
    _IO_STRINGIO_SEEKABLE_METHODDEF
1085
    _IO_STRINGIO_READABLE_METHODDEF
1086
    _IO_STRINGIO_WRITABLE_METHODDEF
1087
1088
    _IO_STRINGIO___GETSTATE___METHODDEF
1089
    _IO_STRINGIO___SETSTATE___METHODDEF
1090
    {NULL, NULL}        /* sentinel */
1091
};
1092
1093
static PyGetSetDef stringio_getset[] = {
1094
    _IO_STRINGIO_CLOSED_GETSETDEF
1095
    _IO_STRINGIO_NEWLINES_GETSETDEF
1096
    /*  (following comments straight off of the original Python wrapper:)
1097
        XXX Cruft to support the TextIOWrapper API. This would only
1098
        be meaningful if StringIO supported the buffer attribute.
1099
        Hopefully, a better solution, than adding these pseudo-attributes,
1100
        will be found.
1101
    */
1102
    _IO_STRINGIO_LINE_BUFFERING_GETSETDEF
1103
    {NULL}
1104
};
1105
1106
static struct PyMemberDef stringio_members[] = {
1107
    {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(stringio, weakreflist), Py_READONLY},
1108
    {"__dictoffset__", Py_T_PYSSIZET, offsetof(stringio, dict), Py_READONLY},
1109
    {NULL},
1110
};
1111
1112
static PyType_Slot stringio_slots[] = {
1113
    {Py_tp_dealloc, stringio_dealloc},
1114
    {Py_tp_doc, (void *)_io_StringIO___init____doc__},
1115
    {Py_tp_traverse, stringio_traverse},
1116
    {Py_tp_clear, stringio_clear},
1117
    {Py_tp_iternext, stringio_iternext},
1118
    {Py_tp_methods, stringio_methods},
1119
    {Py_tp_members, stringio_members},
1120
    {Py_tp_getset, stringio_getset},
1121
    {Py_tp_init, _io_StringIO___init__},
1122
    {Py_tp_new, stringio_new},
1123
    {0, NULL},
1124
};
1125
1126
PyType_Spec _Py_stringio_spec = {
1127
    .name = "_io.StringIO",
1128
    .basicsize = sizeof(stringio),
1129
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1130
              Py_TPFLAGS_IMMUTABLETYPE),
1131
    .slots = stringio_slots,
1132
};