Skip to content

Commit 315c988

Browse files
committed
Check that array size doesn't overflow at construction time
Now, requesting to allocate an array that is too big gives the exception 'array is too big', like numpy. This does depend on a gcc extension, `__builtin_mul_overflow`, present since at least version 5. This extension is also supported in clang. msvc is probably the only compiler of note that does not support it. Closes: #576
1 parent 6fcfeda commit 315c988

File tree

3 files changed

+27
-2
lines changed

3 files changed

+27
-2
lines changed

code/ndarray.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,13 @@ bool ndarray_is_dense(ndarray_obj_t *ndarray) {
593593
return stride == ndarray->strides[ULAB_MAX_DIMS-ndarray->ndim] ? true : false;
594594
}
595595

596+
static size_t multiply_size(size_t a, size_t b) {
597+
size_t result;
598+
if (__builtin_mul_overflow(a, b, &result)) {
599+
mp_raise_ValueError(translate("array is too big"));
600+
}
601+
return result;
602+
}
596603

597604
ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype) {
598605
// Creates the base ndarray with shape, and initialises the values to straight 0s
@@ -612,11 +619,11 @@ ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides
612619
for(uint8_t i=ULAB_MAX_DIMS; i > ULAB_MAX_DIMS-ndim; i--) {
613620
ndarray->shape[i-1] = shape[i-1];
614621
ndarray->strides[i-1] = _strides[i-1];
615-
ndarray->len *= shape[i-1];
622+
ndarray->len = multiply_size(ndarray->len, shape[i-1]);
616623
}
617624

618625
// if the length is 0, still allocate a single item, so that contractions can be handled
619-
size_t len = ndarray->itemsize * MAX(1, ndarray->len);
626+
size_t len = multiply_size(ndarray->itemsize, MAX(1, ndarray->len));
620627
uint8_t *array = m_new0(byte, len);
621628
// this should set all elements to 0, irrespective of the of the dtype (all bits are zero)
622629
// we could, perhaps, leave this step out, and initialise the array only, when needed

tests/2d/numpy/zeros.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,18 @@
1111
for dtype in dtypes:
1212
print(np.zeros((3,3), dtype=dtype))
1313
print(np.zeros((4,2), dtype=dtype))
14+
15+
try:
16+
np.zeros((1<<31, 1<<31))
17+
except ValueError:
18+
print("ValueError")
19+
20+
try:
21+
np.zeros((2147483653, 2147483649))
22+
except ValueError:
23+
print("ValueError")
24+
25+
try:
26+
np.zeros((194899806, 189294637612))
27+
except ValueError:
28+
print("ValueError")

tests/2d/numpy/zeros.py.exp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ array([[0.0, 0.0],
3737
[0.0, 0.0],
3838
[0.0, 0.0],
3939
[0.0, 0.0]], dtype=float64)
40+
ValueError
41+
ValueError
42+
ValueError

0 commit comments

Comments
 (0)