Author Oren Milman
Recipients Oren Milman
Date 2017-09-29.10:39:57
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1506681598.22.0.213398074469.issue31637@psf.upfronthosting.co.za>
In-reply-to
Content
The following code:
from ctypes import *
from _testcapi import PY_SSIZE_T_MAX, LONG_MAX

if LONG_MAX == PY_SSIZE_T_MAX == (1 << 31) - 1:
    class MyArray(Array):
        _type_ = c_longlong
        _length_ = 1 << 29

    arr = MyArray()
    for i in range(3):
        arr[i] = i
    for i in range(3):
        print(arr[i])

Produces this output (on a 32bit Python on my Windows 10):
2
2
2

This is because PyCArrayType_new() (in Modules/_ctypes/_ctypes.c) raises a
"array too large" error in case (length * itemsize < 0). However, this
multiplication might also overflow to a non-negative number, e.g. to zero in
the code above.
PyCArrayType_new() then does:
    stgdict->size = itemsize * length;

Array_ass_item() and Array_item() both do:
    size = stgdict->size / stgdict->length;
    offset = index * size;

So in the above code, the integer overflow caused the array to collapse to a
single element (the first element).


ISTM that we can fix this by changing the overflow detection logic to this:
    assert(itemsize >= 0 && length >= 0);
    array_size = itemsize * length;
    if (itemsize && array_size / itemsize != length) {
        PyErr_SetString(PyExc_OverflowError,
                        "array too large");
        goto error;
    }

The assertion is guaranteed to be true after #29843 is resolved. (I would open
a PR for #29843 soon.)
History
Date User Action Args
2017-09-29 10:39:58Oren Milmansetrecipients: + Oren Milman
2017-09-29 10:39:58Oren Milmansetmessageid: <1506681598.22.0.213398074469.issue31637@psf.upfronthosting.co.za>
2017-09-29 10:39:58Oren Milmanlinkissue31637 messages
2017-09-29 10:39:57Oren Milmancreate