Compare commits

...

4 commits

Author SHA1 Message Date
Jeff Epler
f4ac38a6a0 array: Forbid construction of array(O) from bytearray
This is the final of a set of patches that Closes: #707
2018-03-25 21:45:56 -05:00
Jeff Epler
1497476af4 array: Forbid wrong type in +, +=, and extend 2018-03-25 21:44:25 -05:00
Jeff Epler
a0a5e688e4 array: Forbid wrong type in array slice assignment
This fixes a segfault which could occur with array slice assignment
of 'O'-type arrays, such as
    >>> import array
    >>> a = array.array('O')
    >>> a[:] = array.array('P', [4])
    >>> a
    array('O', [Segmentation fault

it also brings behavior in line with Python 3, which forbids slice
assignment among arrays of different types:

    [python3]
    >>> array.array('b')[:] = array.array('B')
    TypeError: bad argument type for built-in operation

    [circuitpython, after this commit]
    >>> array.array('b')[:] = array.array('B')
    ValueError: lhs and rhs should be compatible
2018-03-25 21:44:25 -05:00
Jeff Epler
5756111293 array: don't allow 'S' typecode 2018-03-25 21:04:21 -05:00
2 changed files with 81 additions and 2 deletions

View file

@ -121,6 +121,9 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
&& mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
// construct array from raw bytes
// we round-down the len to make it a multiple of sz (CPython raises error)
if(typecode == 'O') {
mp_raise_ValueError("cannot construct array(O) from bytearray");
}
size_t sz = mp_binary_get_size('@', typecode, NULL);
size_t len = bufinfo.len / sz;
mp_obj_array_t *o = array_new(typecode, len);
@ -161,7 +164,11 @@ STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size
// get typecode
const char *typecode = mp_obj_str_get_str(args[0]);
if(*typecode == 'S') {
// a typecode accepted by mp_binary_get_size but not OK for array
mp_raise_ValueError("bad typecode");
}
if (n_args == 1) {
// 1 arg: make an empty array
return MP_OBJ_FROM_PTR(array_new(*typecode, 0));
@ -281,6 +288,10 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);
if(lhs_bufinfo.typecode == 'O' && rhs_bufinfo.typecode != 'O') {
return MP_OBJ_NULL; // op not supported
}
size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);
// convert byte count to element count (in case rhs is not multiple of sz)
@ -372,6 +383,10 @@ STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
mp_buffer_info_t arg_bufinfo;
mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);
if(self->typecode == 'O' && arg_bufinfo.typecode != 'O') {
mp_raise_ValueError("cannot extend array(O) with non-object type");
}
size_t sz = mp_binary_get_size('@', self->typecode, NULL);
// convert byte count to element count
@ -420,7 +435,8 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
if (MP_OBJ_IS_OBJ(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) {
// value is array, bytearray or memoryview
mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value);
if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) {
if ((o->typecode & TYPECODE_MASK)
!= (src_slice->typecode & TYPECODE_MASK)) {
compat_error:
mp_raise_ValueError("lhs and rhs should be compatible");
}

View file

@ -0,0 +1,63 @@
try:
import array
except ImportError:
print("SKIP")
raise SystemExit
def raises(f):
try:
f()
except:
print(True)
else:
print(False)
def f():
a = array.array('O')
a[:] = array.array('P', [4])
print(a)
raises(f)
def f():
a = array.array('b')
a[:] = array.array('B')
print(a)
raises(f)
def f():
a = array.array('O')
a = a + 'bbbbbbbb'
print(a)
raises(f)
def f():
a = array.array('O')
a = a + array.array('P', [4])
print(a)
raises(f)
def f():
a = array.array('O')
a += array.array('P', [4])
print(a)
raises(f)
def f():
a = array.array('O')
a.extend('bbbbbbbb')
print(a)
raises(f)
def f():
a = array.array('O')
a.extend(array.array('P', [4]))
print(a)
raises(f)
def f():
a = array.array('O', bytearray('bbbbbbbb'))
print(a)
raises(f)
def f():
a = array.array('O', bytearray('bbbbbbbb'))