Repository navigation
[BUG] Overflow in _C_make_dataobj due to c_int type #2777
Description
Description
When running large 3D grids (e.g., 1295^3 points), Devito fails due to integer overflow in the C structure definition in devito/types/dense.py.
The problem originates from the use of ctypes.c_int (32-bit signed integer), which overflows when matrix size exceeds 2^31-1 elements, even if index-mode=int64 and linearize=True are enabled.
This results in incorrect memory size interpretation and crashes in GPU memory allocation.
File
devito/types/dense.py
Affected Section
_C_ctype = POINTER(type(_C_structname, (Structure,),
{'_fields_': [(_C_field_data, c_restrict_void_p),
(_C_field_size, POINTER(c_int)),
(_C_field_nbytes, c_ulong),
(_C_field_nopad_size, POINTER(c_ulong)),
(_C_field_domain_size, POINTER(c_ulong)),
(_C_field_halo_size, POINTER(c_int)),
(_C_field_halo_ofs, POINTER(c_int)),
(_C_field_owned_ofs, POINTER(c_int)),
(_C_field_dmap, c_void_p)]}))
Proposed Fix
Replace c_int with c_long in the _C_ctype struct definition to safely handle arrays larger than 2^31 elements:
from ctypes import c_long
_C_ctype = POINTER(type(_C_structname, (Structure,),
{'_fields_': [(_C_field_data, c_restrict_void_p),
(_C_field_size, POINTER(c_long)),
(_C_field_nbytes, c_ulong),
(_C_field_nopad_size, POINTER(c_ulong)),
(_C_field_domain_size, POINTER(c_ulong)),
(_C_field_halo_size, POINTER(c_long)),
(_C_field_halo_ofs, POINTER(c_long)),
(_C_field_owned_ofs, POINTER(c_long)),
(_C_field_dmap, c_void_p)]}))
After this modification, all large-domain runs succeed without overflow.
Steps to Reproduce:
1. Use a large 3D simulation (> 2^31 elements):
2. Observe the runtime error (CUDA memory allocation failure, but triggered by invalid size).
3. Inspect dense.py - note c_int usage for size fields.
Observed Behavior
Out of memory allocating 18446744065653020036 bytes of device memory
Failing in Thread:1
Accelerator Fatal Error: call to cuMemAlloc returned error 2 (CUDA_ERROR_OUT_OF_MEMORY)
The reported allocation size is clearly invalid (≈ 1.8×10^31 bytes), caused by signed 32-bit overflow.
Expected Behavior
Correct allocation for 24.5 GB domain (~2.17×10^9 elements), no overflow, normal execution.
Environment
• Devito version: 4.8.20
• Backend: OpenACC / NVHPC 25.1
• MPI: Enabled
• Hardware: NVIDIA H100 (80 GB HBM)
• OS: HPC cluster environment - Linux
• Python: 3.10 (NVHPC env)
Fix verified on GPU backends - replacing c_int with c_long solves the issue fully.
Activity
mloubout commentedon Oct 26, 2025
This is not a bug.
Operator(...., opt=('advanced', {'index-mode':'int64'}))kelv1n9 commentedon Oct 26, 2025
Hi, thanks for the reply.
I already used
index-mode='int64', but the overflow still happened. The issue is not in Python indexing but in the C struct_C_ctypeindevito/types/dense.py.That struct uses
c_int(32-bit) for fields likesizeandhofs. When the grid is larger than 2^31 elements, these values overflow before being passed to the compiled kernel. The result is a wrong memory size (for example18446744065653020036) and a CUDA error.After changing
c_inttoc_long, the same large grid (1295^3, about 24.5 GB) runs correctly on GPU and CPU. No crashes, no page faults.So even with
index-mode=int64, the struct itself still limits integer size to 32 bits. It may be safer to switch those fields toc_longorc_int64on 64-bit systems.mloubout commentedon Oct 26, 2025
Again, thos
__fields__do not have any impact on any part of the memory management, indexing or anything like. Those only inform ctypes of the pointer sizes , i.e the size of the struct, so that ctypes can call the library. Addinitonally all the fields you "changed toc_clongare arrays of int, so unless you are runnign anN^3grid whereNis larger than int32, it will never overflow.Basically you made a change that does not do what you think it does and the only reason it "runs" is pure luck. So i would recomment to make an actual MFE that shows the error rather than try to hack something in that only breaks the ctype type matcing and pointer sizes.
kelv1n9 commentedon Oct 27, 2025
I prepared a MFE to demonstrate that the overflow occurs even with
opt=('advanced', {'index-mode': 'int64', 'linearize': True}).This is not random, the failure happens before kernel execution, during
dataobjcreation indense.py.Minimal Code
Case 1: Default (
c_int)In
devito/types/dense.py:Structure generated at runtime:
Run:
Output:
This happens before the actual computation: the kernel receives a corrupted value (≈1.84×10^19 bytes).
This number is exactly what you get when a negative 32-bit integer (overflowed
int) is reinterpreted as unsigned 64-bit during CUDA memory call.Case 2: After Replacing
c_int->c_longChanged imports and structure in
dense.py:Generated struct:
Run again:
Summary
index-mode='int64'._C_make_dataobj(), whendata.shape(≈2.17×10^9 elements) is packed into(c_int * ndim).c_intfield cannot store large shape values (e.g., 1295^3 > 2^31−1).c_longresolves the issue reproducibly on both CPU and GPU.This is not random success, it’s a reproducible fix that prevents integer overflow when building the
dataobjstruct.Maybe the safest long-term solution is to cast these integer fields dynamically based on the selected
index-mode(int32orint64).mloubout commentedon Oct 31, 2025
the issue is probably in the map to device that uses
u[0:nx*ny*nz]that should be cast to ``u[0:(long)nx*(long)ny*(long)nz]`. but upcasting all the parameters is not the way to go there is no reason to use lojng for all of thosecompiler: Avoid int32 overflow in linearized host-device transfer size
compiler: Avoid int32 overflow in linearized host-device transfer size
compiler: Avoid int32 overflow in linearized host-device transfer size