The Fortran standard does not require the automatic deallocation of allocatable components when a program terminates via
ERROR STOP. While the standard mandates that allocatable components are deallocated when their parent object is explicitly deallocated or goes out of scope,
ERROR STOP is considered an abnormal termination that may bypass normal stack unwinding and finalization procedures.
Standard Requirements vs. Reality
The primary reason for uncertainty lies in the distinction between a normal program exit and an error stop. In a normal exit, objects with automatic storage are destroyed, triggering the deallocation of their allocatable components. However, ERROR STOP is designed to halt execution immediately. Consequently:
- The standard does not guarantee that finalizers will be called.
- Automatic storage components may not be properly deallocated.
- Memory is reclaimed by the operating system when the process terminates, but the Fortran-level state remains inconsistent until then.
Impact of TARGET and Pointers
The presence of the TARGET attribute and pointer association adds complexity. If a pointer is associated with an allocatable component, the standard requires the pointer to be disassociated only when the component is deallocated. If ERROR STOP prevents the deallocation of the component, the pointer remains logically associated in the runtime state, potentially leading to undefined behavior if the program were to continue (which it does).
Compiler Behavior
Major compilers handle this scenario differently based on their implementation of the runtime library and error-handling routines:
- gfortran: Generally does not perform finalization for automatic variables on
ERROR STOP, which often results in reported leaks by tools like Valgrind, even though the OS cleans the memory.
- ifort / Intel: Similar to gfortran, it often prioritizes immediate exit, though specific flags may influence how the runtime cleanup is performed.
- flang: Behavior depends heavily on the LLVM backend, but typically follows the pattern of skipping complex stack unwinding during abrupt stops.
Verification Steps
To determine if your specific environment is leaking logically, use the following test pattern:
module m
type :: data_type
allocatable :: arr :: integer(:)
end type data_type
end module m
program test
use m
type :: data_type :: d
allocate(d%arr(1000))
!! Trigger the error stop
error stop 1, "Test Failure"
end program test
Run this through a memory debugger (e.g., Valgrind). If the tool reports "definitely lost" despite the process ending, the compiler is not deallocating components on ERROR STOP.
Diagnostic Question: Are you using automatic storage (local variables) or static/heap storage for the parent derived type?