Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Segfault on deallocate() of private allocatable within OpenMP parallel region

Laß__Michael
Beginner
784 Views

When using ifort I encounter a segfault at "DEALLOCATE(test)" in the following code:

program demo

    INTEGER, DIMENSION(:), ALLOCATABLE :: test
    ALLOCATE(test(1))

    PRINT *, "Before parallel region:"
    IF (ALLOCATED(test)) THEN
        PRINT *, "  Test already allocated. Location:", LOC(test)
    ELSE
        PRINT *, "  Test not allocated."
    ENDIF

    PRINT *
    PRINT *, "Within parallel region:"

    !$omp parallel num_threads(2) default(none) private(test)

        IF (ALLOCATED(test)) THEN
            PRINT *, "  Test already allocated. Location:", LOC(test)
            PRINT *, "  Deallocating..."
            DEALLOCATE(test)
        ELSE
            PRINT *, "  Test not allocated."
        ENDIF

    !$omp end parallel

end program demo

Output is the following:

 Before parallel region:
   Test already allocated. Location:        46912518012896
 
 Within parallel region:
   Test already allocated. Location:       140737488326928
   Test already allocated. Location:        46912522410000
   Deallocating...
   Deallocating...
forrtl: severe (174): SIGSEGV, segmentation fault occurred

The output shows that (as expected) new private instances of test are created for each of the two threads at different memory locations. Both are already allocated as the OpenMP standard requires (Section 2.19.3, note on Fortran). However, when trying to deallocate them, a segfault occurs.

I cross-checked this with gfortran and the Cray ftn compiler and both have no issues with this code. So is this a bug in ifort or am I doing something illegal here? I'm using ifort in version 19.0.4.243 20190416.

Side note: Of course this is a very constructed example. Originally I encountered this issue using private instances of a more complex data structure that re-allocates some buffers on-demand.

0 Kudos
7 Replies
jimdempseyatthecove
Honored Contributor III
784 Views

In older versions of Fortran the behavior of passing in an unallocated array as private(array) resulted in the parallel region having an uninitialized array descriptor. The correction for this was to use firstprivate(array) such that the unallocated array descriptor was copied into the copy in the parallel region.

What are the results of your test program after changing private(test) to firstprivate(test)?

Jim Dempsey

0 Kudos
Laß__Michael
Beginner
784 Views

jimdempseyatthecove (Blackbelt) wrote:

In older versions of Fortran the behavior of passing in an unallocated array as private(array) resulted in the parallel region having an uninitialized array descriptor.

Note that in my case the array is already allocated before entering the parallel region. If I leave it unallocated, the private copies are unallocated as well and I can allocate them within the threads without problems. Here's a slightly modified version for demonstration:

program demo

        INTEGER, DIMENSION(:), ALLOCATABLE :: test
!       ALLOCATE(test(1))

        PRINT *, "Before parallel region:"
        IF (ALLOCATED(test)) THEN
                PRINT *, "  Test already allocated. Location:", LOC(test)
        ELSE
                PRINT *, "  Test not allocated."
        ENDIF

        PRINT *
        PRINT *, "Within parallel region:"

        !$omp parallel num_threads(2) default(none) private(test)

                IF (ALLOCATED(test)) THEN
                        PRINT *, "  Test already allocated. Location:", LOC(test)
                        PRINT *, "  Deallocating..."
                        DEALLOCATE(test)
                ELSE
                        PRINT *, "  Test not allocated."
                        PRINT *, "  Allocating..."
                        ALLOCATE(test(1))
                ENDIF

        !$omp end parallel

end program demo

Output:

 Before parallel region:
   Test not allocated.
 
 Within parallel region:
   Test not allocated.
   Test not allocated.
   Allocating...
   Allocating...

jimdempseyatthecove (Blackbelt) wrote:

The correction for this was to use firstprivate(array) such that the unallocated array descriptor was copied into the copy in the parallel region.

What are the results of your test program after changing private(test) to firstprivate(test)?

The segfault still occurs when changing private() to firstprivate().

0 Kudos
jimdempseyatthecove
Honored Contributor III
784 Views

>>Note that in my case the array is already allocated before entering the parallel region.

At issue, in the older versions of Intel Fortran, private(array) would not initialize an empty array descriptor, additionally the uninitialized array descriptor could, at times, report allocated as .true. Using firstprivate(array) would correct for this.

Seeing that in the past there had been an issue with private(array), even though your have the array allocated, I suggested that you try firstprivate(array) in the event that this old problem resurfaced itself. Your observation "The segfault still occurs when changing private() to firstprivate()" indicates that this is an entirely new problem.

Your test code is suitable to submit to Intel as a reproducer of the problem.

Jim Dempsey

0 Kudos
Laß__Michael
Beginner
784 Views

Thanks! I sent in a report as ticket #04378880.

0 Kudos
Ron_Green
Moderator
784 Views

I saw your issue come in.  So let me ask a stupid question:  What exactly do you expect to happen with the deallocate?

You want to deallocate the thread-private copy of test(:) right?  you are NOT suggesting that you expect the threads to deallocate TEST outside of the parallel region, correct?  You know that would be a race condition IF that is what you are trying to do.  The only thing that makes sense here, if it's legal at all, is to deallocate the thread local copies of TEST and leave the outside TEST alone - this IS what you intend yes?

0 Kudos
Laß__Michael
Beginner
784 Views

Thanks for looking into this! Exactly, I would expect the private copy within the thread to be deallocated so that the thread can for example reallocate its own copy with a different size. This is what seems to happen using gfortran. The original array outside of the parallel region of course must not be altered at all.

However, I am also not entirely sure if this is a legal operation according to the standard which is why I opened this thread in the forum first. The OpenMP standard only says that the private copies must be allocated if the original array is allocated when entering the parallel region. I'm not sure if this implies that it must be possible to de-/reallocate.

Anyway, a segfault at runtime seems to me like a bug. If it is an illegal thing to do, the compiler should probably error out at compile time.

0 Kudos
jimdempseyatthecove
Honored Contributor III
784 Views

>>The original array outside of the parallel region of course must not be altered at all

At issue here can be an implementation issue whereby the main thread of the region, when it happens to be one of the two threads within the parallel region, uses:

a) the original copy of the array, or
b) uses a copy of the original array

Jim Dempsey

0 Kudos
Reply