py: Prevent segfault for operations on closed StringIO.

Addresses issue #1067.
This commit is contained in:
stijn 2015-01-16 13:36:18 +01:00 committed by Damien George
parent 0ab3fc3805
commit bf19541f46
2 changed files with 32 additions and 1 deletions

View File

@ -42,15 +42,26 @@ typedef struct _mp_obj_stringio_t {
mp_uint_t pos; mp_uint_t pos;
} mp_obj_stringio_t; } 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) { 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; (void)kind;
mp_obj_stringio_t *self = self_in; mp_obj_stringio_t *self = self_in;
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr); print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self);
} }
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
(void)errcode; (void)errcode;
mp_obj_stringio_t *o = o_in; mp_obj_stringio_t *o = o_in;
check_stringio_is_open(o);
mp_uint_t remaining = o->vstr->len - o->pos; mp_uint_t remaining = o->vstr->len - o->pos;
if (size > remaining) { if (size > remaining) {
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) { STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
(void)errcode; (void)errcode;
mp_obj_stringio_t *o = o_in; mp_obj_stringio_t *o = o_in;
check_stringio_is_open(o);
mp_uint_t remaining = o->vstr->alloc - o->pos; mp_uint_t remaining = o->vstr->alloc - o->pos;
if (size > remaining) { if (size > remaining) {
// Take all what's already allocated... // 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) { STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
mp_obj_stringio_t *self = 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); 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_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
STATIC mp_obj_t stringio_close(mp_obj_t self_in) { STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
mp_obj_stringio_t *self = self_in; mp_obj_stringio_t *self = self_in;
#if MICROPY_CPYTHON_COMPAT
vstr_free(self->vstr); vstr_free(self->vstr);
self->vstr = NULL; self->vstr = NULL;
#else
vstr_clear(self->vstr);
self->vstr->alloc = 0;
self->vstr->len = 0;
self->pos = 0;
#endif
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);

View File

@ -28,3 +28,14 @@ print(a.getvalue())
a = io.StringIO() a = io.StringIO()
a.write("foo") a.write("foo")
print(a.read()) 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")