diff --git a/nibabel/tests/test_utils.py b/nibabel/tests/test_utils.py index 1810722b55..83122bbe95 100644 --- a/nibabel/tests/test_utils.py +++ b/nibabel/tests/test_utils.py @@ -1227,3 +1227,21 @@ def assert_rt(data, slope = slope, post_clips = post_clips, nan_fill = nan_fill) + + +def test_array_from_file_overflow(): + # Test for int overflow in size calculation in array_from_file + shape = (1500,) * 6 + class NoStringIO: # Null file-like for forcing error + def seek(self, n_bytes): + pass + def read(self, n_bytes): + return b'' + try: + array_from_file(shape, np.int8, NoStringIO()) + except IOError as err: + message = str(err) + assert_equal(message, + 'Expected {0} bytes, got {1} bytes from {2}\n' + ' - could the file be damaged?'.format( + 11390625000000000000, 0, 'object')) diff --git a/nibabel/volumeutils.py b/nibabel/volumeutils.py index d43c43f4cc..ce2e0cd6ac 100644 --- a/nibabel/volumeutils.py +++ b/nibabel/volumeutils.py @@ -14,6 +14,8 @@ import gzip import bz2 from os.path import exists, splitext +from operator import mul +from functools import reduce import numpy as np @@ -504,7 +506,8 @@ def array_from_file(shape, in_dtype, infile, offset=0, order='F', mmap=True): pass if len(shape) == 0: return np.array([]) - n_bytes = int(np.prod(shape) * in_dtype.itemsize) + # Use reduce and mul to work around numpy integer overflow + n_bytes = reduce(mul, shape) * in_dtype.itemsize if n_bytes == 0: return np.array([]) # Read data from file