Skip to content

Overflow in Bigarray.reshape #14655

@last-genius

Description

@last-genius

Bigarray.reshape does not seem to handle overflow well, allowing to read into uninitialized memory.

Below example shows how data pointer isn't reallocated, caml_ba_num_elts still returns 0, but .get() into uninitialized memory is allowed:

Array1.create 0
arr->data: 0xebb0480
elements: 0
arr.get(5) exception: Invalid_argument("index out of bounds")

Bigarray.reshape [|8; 2305843009213693952|]
Size in bytes: 0 (dim1: 8, dim2: 2305843009213693952)

arr->data: 0xebb0480
elements: 0
arr[5][5]: -2134031706542294431 <--- this value is random on every program invocation

It seems like caml_umul_overflow in caml_ba_alloc should catch this, raising Out_of_memory, but this doesn't seem to be the case.


Source code of the example above.

bin/dune:

(executable
 (foreign_stubs
  (language c)
  (names reshape_stubs)
 )
 (public_name reshape)
 (name main)
 (libraries reshape))

bin/main.ml:

external elements : ('a, 'b, 'c) Bigarray.Genarray.t -> int = "stub_arr_size"

let _ =
  let open Bigarray in
  print_endline "Array1.create 0" ;
  let arr = Array1.create int c_layout 0 in
  Printf.printf "elements: %d\n" (elements (genarray_of_array1 arr)) ;

  let _ =
    try Array1.get arr 5
    with e ->
      Printf.printf "arr.get(5) exception: %s\n" (Printexc.to_string e) ;
      1
  in

  print_endline "\nBigarray.reshape [|8; 2305843009213693952|]" ;
  let x =
    array2_of_genarray
      (reshape (genarray_of_array1 arr) [|8; 2305843009213693952|])
  in

  print_endline
    (Printf.sprintf "Size in bytes: %d (dim1: %d, dim2: %d)\n"
       (Array2.size_in_bytes x) (Array2.dim1 x) (Array2.dim2 x)
    ) ;

  Printf.printf "elements: %d\n" (elements (genarray_of_array2 x)) ;
  Printf.printf "arr[5][5]: %d\n" (Array2.get x 5 5)

bin/reshape_stubs.c:

#include <caml/bigarray.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>


CAMLprim value
stub_arr_size (value arr)
{
    CAMLparam1(arr);
    printf("arr->data: %p\n", Caml_ba_array_val(arr)->data);
    CAMLreturn(Val_int(caml_ba_num_elts(Caml_ba_array_val(arr))));
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions