diff --git a/py/objstringio.c b/py/objstringio.c index f7b8074f35..c7e8395b49 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -42,15 +42,26 @@ typedef struct _mp_obj_stringio_t { mp_uint_t pos; } mp_obj_stringio_t; +#if MICROPY_CPYTHON_COMPAT +STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { + if (o->vstr == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + } +} +#else +#define check_stringio_is_open(o) +#endif + STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_stringio_t *self = self_in; - print(env, self->base.type == &mp_type_stringio ? "" : "", self->vstr); + print(env, self->base.type == &mp_type_stringio ? "" : "", self); } STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = o_in; + check_stringio_is_open(o); mp_uint_t remaining = o->vstr->len - o->pos; if (size > remaining) { 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 STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = o_in; + check_stringio_is_open(o); mp_uint_t remaining = o->vstr->alloc - o->pos; if (size > remaining) { // 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, STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = self_in; + check_stringio_is_open(self); return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); STATIC mp_obj_t stringio_close(mp_obj_t self_in) { mp_obj_stringio_t *self = self_in; +#if MICROPY_CPYTHON_COMPAT vstr_free(self->vstr); self->vstr = NULL; +#else + vstr_clear(self->vstr); + self->vstr->alloc = 0; + self->vstr->len = 0; + self->pos = 0; +#endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); diff --git a/tests/io/stringio1.py b/tests/io/stringio1.py index 6979fe7c9d..dae0187f88 100644 --- a/tests/io/stringio1.py +++ b/tests/io/stringio1.py @@ -28,3 +28,14 @@ print(a.getvalue()) a = io.StringIO() a.write("foo") print(a.read()) + +a = io.StringIO() +a.close() +for f in [a.read, a.getvalue, lambda:a.write("")]: + # CPython throws for operations on closed I/O, micropython makes + # the underlying string empty unless MICROPY_CPYTHON_COMPAT defined + try: + f() + print("ValueError") + except ValueError: + print("ValueError")