Skip to main content
GitHub

ARR03-F. Specify array bounds when copying data to device memory

Programmers shall explicitly specify array bounds or ranges when transferring data between host and device memory. This ensures sufficient memory is mapped and prevents undefined behavior.

In heterogeneous computing environments (e.g., using GPUs or other accelerators), arrays often must be explicitly moved from host to device. Omitting bounds can introduce several risks:

  • Insufficient data transfer: For assumed-size or partially known arrays, the compiler may copy too few elements, causing undefined behavior on the device.
  • Excessive data transfer: Copying the entire array when only a section is needed degrades performance.
  • Memory violations: Incorrect bounds may cause out-of-bounds access on the device, leading to illegal memory access or silent data corruption.

Programmers should not rely on compiler defaults, as optimizations may assume that out-of-bounds behavior does not occur, potentially bypassing safety checks.

Noncompliant Code Example

In this noncompliant example, a large array data_buffer is used to store simulation results, but only a portion of it (defined by n ) is valid. The directive !$omp target data attempts to map the entire array to the device (e.g. GPU). This is inefficient and potentially dangerous if the entire buffer has not been appropriately initialized or allocated for the device's memory limits.

Non-compliant code
program device_transfer
  use iso_fortran_env, only: real64
  implicit none
  integer, parameter        :: max_size = 100000
  real(real64), allocatable :: data_buffer(:)
  integer, parameter        :: n = 1000
  integer                   :: i

  allocate(data_buffer(max_size))

  data_buffer(1:n) = [(real(i, real64), i = 1, n)]

  ! Noncompliant: Maps the entire buffer instead of the actual used range (n elements)
  !$omp target map(to: data_buffer)
    ! Accelerator operations here
  !$omp end

end program

Compliant Solution

In this compliant solution, the programmer uses an array section to specify the exact bounds of the data to be transferred. This ensures that only the required memory is mapped to the device, providing enough storage for objects while avoiding the ambiguity of undefined behavior.

Compliant code
program device_transfer
  use iso_fortran_env, only: real64
  implicit none
  integer, parameter        :: max_size = 100000
  real(real64), allocatable :: data_buffer(:)
  integer, parameter        :: n = 1000
  integer                   :: i

  allocate(data_buffer(max_size))

  data_buffer(1:n) = [(real(i, real64), i = 1, n)]

  ! Compliant: Explicitly specifies the range for the transfer
  !$omp target map(to: data_buffer(1:n))
    ! Accelerator operations here
  !$omp end target

end program

Risk Assessment

Failure to specify array bounds when mapping data to a device can lead to memory corruption on the accelerator, performance bottlenecks, or program termination.

RecommendationSeverityLikelihoodDetectableRepairablePriorityLevel
ARR03-FHighProbableNoYesP27L1

Attachments: