Observed issues › oop/gcc-polymorphic-dispatch-abort
dynamic dispatch of a type-bound procedure in device code aborts
Legality: contested. An independent adjudicating reading finds the result not required: The spec requires only that type-bound procedures accessed in a target region appear in a declare target directive. The specific bindings sq_area, rect_area and area_of carry declare target, so that rule is met. Neither reading finds a rule on making the dynamic type information (descriptor or vtable) of a CLASS dummy usable on the device. q and rr are mapped as non-polymorphic objects whose passed class descriptors point to host data. How this is checked
A declare target function calls a type-bound procedure through a CLASS dummy argument (every bound procedure declare target). GCC 16.2 compiles it and the program aborts at run time. The same program calling the binding on the non-polymorphic objects works. AFAR runs it correctly.
Affected variants
| Compiler | MI300A gfx942 unified memory (XNACK 1) | MI300A gfx942 copy (XNACK 0) | MI250X gfx90a copy (XNACK 0) | MI300X gfx942 copy (XNACK 0) | MI350X gfx950 copy (XNACK 0) | A100 sm_80 separate memory | A100 sm_80 managed memory |
|---|---|---|---|---|---|---|---|
| AFAR 24.3.0 | correct | correct | unknown not run | correct | correct | n/a | n/a |
| CCE 19.0.0 | fails another way | fails another way | unknown not run | unknown not run | unknown not run | n/a | n/a |
| CCE 20.0.2 | fails another way | fails another way | unknown not run | unknown not run | unknown not run | n/a | n/a |
| CCE 21.0.3 | fails another way | fails another way | unknown not run | unknown not run | unknown not run | n/a | n/a |
| CCE 21.0.4 | fails another way | fails another way | unknown not run | unknown not run | unknown not run | n/a | n/a |
| NVHPC 25.11 | n/a | n/a | n/a | n/a | n/a | fails another way | fails another way |
| NVHPC 26.9 | n/a | n/a | n/a | n/a | n/a | fails another way | fails another way |
| GCC 16.2.0 | fails another way | behaves incorrectly | behaves incorrectly | behaves incorrectly | behaves incorrectly | behaves incorrectly | n/a |
"behaves incorrectly" / "not supported": this issue, confirmed in up to four environments (another build directory, another node, a repeat). "fails another way": a different failure, not counted as this issue. "unknown": not run there, or the runs disagree.
Messages
| Result | Compiler and GPU | Message |
|---|---|---|
| behaves incorrectly | GCC 16.2.0, MI300A copy | showMemory access fault by GPU node-7 (Agent handle: 0x591bc0) on address 0x401000. Reason: Unknown. Program received signal SIGABRT: Process abort signal. Backtrace for this error: #0 0x15555469662f in ??? #1 0x1555546965af in ??? #2 0x155554669ee4 in ??? #3 0x1555540d6bfe in ??? #4 0x1555540d4288 in ??? |
| behaves incorrectly | GCC 16.2.0, MI250X | showMemory access fault by GPU node-9 (Agent handle: 0x783070) on address 0x400000. Reason: Unknown. Program received signal SIGABRT: Process abort signal. Backtrace for this error: #0 0x15555469662f in ??? #1 0x1555546965af in ??? #2 0x155554669ee4 in ??? #3 0x1555540d6bfe in ??? #4 0x1555540d4288 in ??? |
| behaves incorrectly | GCC 16.2.0, MI300X | showMemory access fault by GPU node-1 (Agent handle: 0x1264f00) on address 0x401000. Reason: Unknown. Program received signal SIGABRT: Process abort signal. Backtrace for this error: #0 0x7febe423ebef in ??? #1 0x7febe428bedc in ??? #2 0x7febe423eb45 in ??? #3 0x7febe4228832 in ??? #4 0x7febe3e89a5e in ??? |
| behaves incorrectly | GCC 16.2.0, MI350X | showMemory access fault by GPU node-1 (Agent handle: 0xafa5c0) on address 0x401000. Reason: Unknown. Program received signal SIGABRT: Process abort signal. Backtrace for this error: #0 0x7f5d3683fc2f in ??? #1 0x7f5d3688d02c in ??? #2 0x7f5d3683fb85 in ??? #3 0x7f5d36829872 in ??? #4 0x7f5d36489a5e in ??? |
| behaves incorrectly | GCC 16.2.0, A100 separate | showlibgomp: cuCtxSynchronize error: an illegal memory access was encountered libgomp: cuModuleGetFunction (__do_global_dtors__entry) error: an illegal memory access was encountered libgomp: cuMemFree_v2 error: an illegal memory access was encountered libgomp: device finalization failed |
| fails another way | CCE 19.0.0, MI300A unified CCE 19.0.0, MI300A copy | showWarning: Headers and libraries from cray-libsci/25.03.0 will be ignored because depends on PE_MPICH which is unavailable.. lld: error: undefined symbol: __GET_TYPE_BOUND_PROC >>> referenced by <dir>:(oop_$ck_L75_2) >>> referenced by <dir>:(oop_$ck_L75_2) |
| fails another way | CCE 20.0.2, MI300A unified CCE 20.0.2, MI300A copy | showWarning: Headers and libraries from cray-libsci/25.09.0 will be ignored because depends on PE_MPICH which is unavailable.. lld: error: undefined symbol: __GET_TYPE_BOUND_PROC >>> referenced by <dir>:(oop_$ck_L75_2) >>> referenced by <dir>:(oop_$ck_L75_2) |
| fails another way | CCE 21.0.3, MI300A unified CCE 21.0.3, MI300A copy | showWarning: Headers and libraries from cray-libsci/26.03.0 will be ignored because depends on PE_MPICH which is unavailable.. lld: error: undefined symbol: __GET_TYPE_BOUND_PROC >>> referenced by <dir>//cooltmpdir-jp5qGf/repro-cce-openmppost_lld.amdgpu.lto.o:(oop_$ck_L75_2) >>> referenced by <dir>//cooltmpdir-jp5qGf/repro-cce-openmppost_lld.amdgpu.lto.o:(oop_$ck_L75_2) |
| fails another way | CCE 21.0.4, MI300A unified CCE 21.0.4, MI300A copy | showWarning: Headers and libraries from cray-libsci/26.03.0 will be ignored because depends on PE_MPICH which is unavailable.. lld: error: undefined symbol: __GET_TYPE_BOUND_PROC >>> referenced by <dir>//cooltmpdir-jjWH3y/repro-cce-openmppost_lld.amdgpu.lto.o:(oop_$ck_L75_2) >>> referenced by <dir>//cooltmpdir-jjWH3y/repro-cce-openmppost_lld.amdgpu.lto.o:(oop_$ck_L75_2) |
| fails another way | NVHPC 25.11, A100 separate NVHPC 25.11, A100 managed | showNVFORTRAN-W-0155-Compiler failed to translate accelerator region (see -Minfo messages): No device symbol for address reference (site-oop--gcc-polymorphic-dispatch-abort.f90: 80) NVFORTRAN-F-0704-Compilation aborted due to previous errors. (site-oop--gcc-polymorphic-dispatch-abort.f90) NVFORTRAN/x86-64 Linux 25.11-0: compilation aborted |
| fails another way | NVHPC 26.9, A100 separate NVHPC 26.9, A100 managed | showNVFORTRAN-W-0155-Compiler failed to translate accelerator region (see -Minfo messages): No device symbol for address reference (site-oop--gcc-polymorphic-dispatch-abort.f90: 80) NVFORTRAN-F-0704-Compilation aborted due to previous errors. (site-oop--gcc-polymorphic-dispatch-abort.f90) NVFORTRAN/x86-64 Linux 26.9-0: compilation aborted |
| fails another way | GCC 16.2.0, MI300A unified | showRUN_TIMEOUT |
Reproduce
GCC 16.2.0, MI300A copy
export LD_LIBRARY_PATH=$GCC_16_2/lib64:/opt/rocm-7.2.1/lib $GCC_16_2/bin/gfortran -fopenmp -foffload=amdgcn-amdhsa -foffload-options=amdgcn-amdhsa=-march=gfx942 -O2 repro.f90 -o repro HSA_XNACK=0 OMP_TARGET_OFFLOAD=mandatory ./repro
GCC 16.2.0, A100 separate
export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=$GCC_16_2/lib64 $GCC_16_2/bin/gfortran -fopenmp -foffload=nvptx-none -foffload-options=nvptx-none=-march=sm_80 -foffload-options=nvptx-none=-latomic -O2 repro.f90 -o repro OMP_TARGET_OFFLOAD=mandatory ./repro
AFAR 24.3.0, MI300A unified (runs correctly)
$AFAR/bin/amdflang -fopenmp --offload-arch=gfx942 -O2 repro.f90 -o repro HSA_XNACK=1 OMP_TARGET_OFFLOAD=mandatory ./repro
Program (89 lines)
! # Finding (fortran-oop): a type-bound call through a CLASS dummy in device code aborts at run time
!
! - toolchains and modes that fail: gcc_g90 (GCC 16.2 (gfx90a): copy), gcc_sm80 (GCC 16.2 (sm_80): copy); -O2
! - build: gfortran -fopenmp -foffload=amdgcn-amdhsa -foffload-options=amdgcn-amdhsa=-march=gfx90a -O2 (gcc_g90);
! -foffload=nvptx-none -foffload-options=nvptx-none=-march=sm_80 -foffload-options=nvptx-none=-latomic (gcc_sm80)
! - failure: crash (SIGABRT); OMP_TARGET_OFFLOAD=mandatory
! - observed: the program compiles and aborts (SIGABRT, a backtrace without symbols) in every run
! - expected: `r1= 29`
! - rule: 5.2 §1.2.6 p.19 l.1-3 (every type-bound procedure accessed is declare target)
! - same-compiler control: the same program with the region calling the binding on the TYPE objects instead of through area_of's
! CLASS(shape) dummy (controls/poly-dispatch-static.f90, one change): `r1= 29`, check=pass in the stored run and the gate's four
! environments a-d on both GPUs (results/oop/probe/ctl2.*.poly-dispatch-static.gcc.jsonl, (c) on another Tioga node;
! results/oop/probe/ctl2.*.poly-dispatch-static.wt-gcc_sm80.jsonl, (c) on another A100)
! - other families: AFAR correct; CCE fails at the device link (cce-polymorphic-dispatch-device-link.f90)
! - gate and confirmer: 8 cells, 8 confirmed in the gate's four environments (a-d; results/oop/main/gate_reruns*.jsonl); confirmer
! (results/oop/main/confirm.jsonl): compiler_bug (R20-runtime-bug) 4, needs_human (R22-expected-weak) 4; R22-expected-weak means
! the expected value has one source, the generator's Python model; the values follow from the program's arithmetic (checked by
! hand), and AFAR print them on this program
! - programs (4): oop-poly-dispatch, oop-poly-dispatch-loop, oop-poly-parent-call, oop-tbp-nested-call (offload/engine/oop_gen.py;
! this file is the first one)
! - legality: for the gcc cells: the rules (offload.engine.rules, with the fortran-oop restrictions) and AFAR's flang front end
! (-fsyntax-only) and a CCE compile and NVHPC 26.9 nvfortran (compile only) (tools/campaigns/oop.py legality,
! results/oop/main/legality.json)
module oop_m
implicit none
integer, parameter :: n = 64
type, abstract :: shape
integer :: id = 0
contains
procedure(area_if), deferred :: area
end type shape
abstract interface
integer function area_if(s)
import :: shape
class(shape), intent(in) :: s
end function area_if
end interface
type, extends(shape) :: sq
integer :: side = 0
contains
procedure :: area => sq_area
end type sq
type, extends(shape) :: rect
integer :: w = 0, h = 0
contains
procedure :: area => rect_area
end type rect
contains
integer function sq_area(s)
!$omp declare target
class(sq), intent(in) :: s
sq_area = s%side * s%side
end function sq_area
integer function rect_area(s)
!$omp declare target
class(rect), intent(in) :: s
rect_area = s%w * s%h
end function rect_area
integer function area_of(s)
!$omp declare target
class(shape), intent(in) :: s
area_of = s%area()
end function area_of
end module oop_m
program oop
use omp_lib
use oop_m
implicit none
integer :: host_flag
logical :: ok
integer :: r1
type(sq) :: q
type(rect) :: rr
host_flag = 1
!$omp target map(from: host_flag)
host_flag = merge(1, 0, omp_is_initial_device())
!$omp end target
q%side = 3
rr%w = 4
rr%h = 5
!$omp target map(tofrom: q, rr) map(from: r1)
r1 = area_of(q) + area_of(rr)
!$omp end target
ok = .true.
ok = ok .and. (r1 == 29)
print '(a,i0)', 'r1= ', r1
print '(a,i0,a,a)', 'RESULT ran_on_host=', host_flag, ' check=', merge('pass', 'fail', ok)
end program oop
Something to add? Dispute its legality · Report it fixed in a newer release · Report a mistake on this page
Expected and observed
Observed where it behaves incorrectly
Memory access fault by GPU node-7 (Agent handle: 0x591bc0) on address 0x401000. Reason: Unknown. Program received signal SIGABRT: Process abort signal. Backtrace for this error: #0 0x15555469662f in ??? #1 0x1555546965af in ??? #2 0x155554669ee4 in ??? #3 0x1555540d6bfe in ??? #4 0x1555540d4288 in ???
What the specification requires
The specification text this program relies on and the compiler is expected to support.
OpenMP 5.2 §1.2.6 p.19 l.1-3
Evidence
Same compiler, one change
- the same program; the binding is called on the TYPE objects (statically resolved) instead of through a CLASS dummy: not run yet
Control program
! control for oop-poly-dispatch: the same program; one change: the region calls the binding on the TYPE objects ! (statically resolved) instead of through area_of's CLASS(shape) dummy ! fortran-oop poly/dispatch (OpenMP 5.2, free-form Fortran): ! dynamic dispatch of a deferred binding (abstract type) through a CLASS(shape) dummy on the ! device ! spec: OpenMP 5.2 §1.2.6 p.19 l.1-3 (type-bound procedures accessed in a target region appear in a ! declare target directive); OpenMP 5.2 §7.8.1 p.205-207 (declare target, procedures) ! legality: defined ! expected (computed by compliance/oop_gen.py): r1= 29 module oop_m implicit none integer, parameter :: n = 64 type, abstract :: shape integer :: id = 0 contains procedure(area_if), deferred :: area end type shape abstract interface integer function area_if(s) import :: shape class(shape), intent(in) :: s end function area_if end interface type, extends(shape) :: sq integer :: side = 0 contains procedure :: area => sq_area end type sq type, extends(shape) :: rect integer :: w = 0, h = 0 contains procedure :: area => rect_area end type rect contains integer function sq_area(s) !$omp declare target class(sq), intent(in) :: s sq_area = s%side * s%side end function sq_area integer function rect_area(s) !$omp declare target class(rect), intent(in) :: s rect_area = s%w * s%h end function rect_area integer function area_of(s) !$omp declare target class(shape), intent(in) :: s area_of = s%area() end function area_of end module oop_m program oop use omp_lib use oop_m implicit none integer :: host_flag logical :: ok integer :: r1 type(sq) :: q type(rect) :: rr host_flag = 1 !$omp target map(from: host_flag) host_flag = merge(1, 0, omp_is_initial_device()) !$omp end target q%side = 3 rr%w = 4 rr%h = 5 !$omp target map(tofrom: q, rr) map(from: r1) r1 = q%area() + rr%area() !$omp end target ok = .true. ok = ok .and. (r1 == 29) print '(a,i0)', 'r1= ', r1 print '(a,i0,a,a)', 'RESULT ran_on_host=', host_flag, ' check=', merge('pass', 'fail', ok) end program oop
Other compilers run it correctly
AFAR 24.3.0