@@ -170,4 +170,33 @@ defmodule EMLXTest do
170170 end
171171 end
172172 end
173+
174+ describe "large tensors (element count > INT32_MAX)" do
175+ # Regression: elem_count used std::accumulate with an `int` initial value,
176+ # so products > INT32_MAX overflowed to a huge uint64 and the binary-size
177+ # guard rejected valid binaries with "Binary size is too small".
178+ # Real-world trigger: Gemma-4's embed_tokens_per_layer {262144, 8960}
179+ # = 2_348_810_240 elements > INT32_MAX (2_147_483_647).
180+ @ tag :large_tensor
181+ test "from_binary accepts shape whose element count exceeds INT32_MAX" do
182+ # 2 × 1_073_741_824 = 2_147_483_648 > INT32_MAX.
183+ # :u8 (1 byte/element) keeps total allocation at ~2 GB.
184+ #
185+ # We reshape on BinaryBackend first (pure Elixir, no NIF) because
186+ # Nx.from_binary always creates a 1D tensor — and a single dimension of
187+ # 2_147_483_648 also exceeds INT32_MAX, which breaks SHAPE_PARAM before
188+ # even reaching elem_count. The 2D shape {2, 1_073_741_824} has both
189+ # dims within int32 range; only their product overflows.
190+ n = 2_147_483_648
191+ binary = :binary . copy ( << 7 >> , n )
192+
193+ t =
194+ Nx . from_binary ( binary , :u8 , backend: Nx.BinaryBackend )
195+ |> Nx . reshape ( { 2 , 1_073_741_824 } )
196+ |> Nx . backend_transfer ( EMLX.Backend )
197+
198+ assert Nx . shape ( t ) == { 2 , 1_073_741_824 }
199+ assert Nx . to_number ( t [ 0 ] [ 0 ] ) == 7
200+ end
201+ end
173202end
0 commit comments