Skip to content

Commit bf19541

Browse files
stinosdpgeorge
authored andcommitted
py: Prevent segfault for operations on closed StringIO.
Addresses issue adafruit#1067.
1 parent 0ab3fc3 commit bf19541

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

py/objstringio.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,26 @@ typedef struct _mp_obj_stringio_t {
4242
mp_uint_t pos;
4343
} mp_obj_stringio_t;
4444

45+
#if MICROPY_CPYTHON_COMPAT
46+
STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) {
47+
if (o->vstr == NULL) {
48+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file"));
49+
}
50+
}
51+
#else
52+
#define check_stringio_is_open(o)
53+
#endif
54+
4555
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
4656
(void)kind;
4757
mp_obj_stringio_t *self = self_in;
48-
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
58+
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self);
4959
}
5060

5161
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
5262
(void)errcode;
5363
mp_obj_stringio_t *o = o_in;
64+
check_stringio_is_open(o);
5465
mp_uint_t remaining = o->vstr->len - o->pos;
5566
if (size > remaining) {
5667
size = remaining;
@@ -63,6 +74,7 @@ STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er
6374
STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
6475
(void)errcode;
6576
mp_obj_stringio_t *o = o_in;
77+
check_stringio_is_open(o);
6678
mp_uint_t remaining = o->vstr->alloc - o->pos;
6779
if (size > remaining) {
6880
// Take all what's already allocated...
@@ -82,14 +94,22 @@ STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size,
8294

8395
STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
8496
mp_obj_stringio_t *self = self_in;
97+
check_stringio_is_open(self);
8598
return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len);
8699
}
87100
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
88101

89102
STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
90103
mp_obj_stringio_t *self = self_in;
104+
#if MICROPY_CPYTHON_COMPAT
91105
vstr_free(self->vstr);
92106
self->vstr = NULL;
107+
#else
108+
vstr_clear(self->vstr);
109+
self->vstr->alloc = 0;
110+
self->vstr->len = 0;
111+
self->pos = 0;
112+
#endif
93113
return mp_const_none;
94114
}
95115
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);

tests/io/stringio1.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,14 @@
2828
a = io.StringIO()
2929
a.write("foo")
3030
print(a.read())
31+
32+
a = io.StringIO()
33+
a.close()
34+
for f in [a.read, a.getvalue, lambda:a.write("")]:
35+
# CPython throws for operations on closed I/O, micropython makes
36+
# the underlying string empty unless MICROPY_CPYTHON_COMPAT defined
37+
try:
38+
f()
39+
print("ValueError")
40+
except ValueError:
41+
print("ValueError")

0 commit comments

Comments
 (0)