Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A runtime error occurs when assigning a variable of bitset_large #726

Closed
degawa opened this issue Jul 8, 2023 · 7 comments · Fixed by #727
Closed

A runtime error occurs when assigning a variable of bitset_large #726

degawa opened this issue Jul 8, 2023 · 7 comments · Fixed by #727
Labels
bug Something isn't working

Comments

@degawa
Copy link
Contributor

degawa commented Jul 8, 2023

Description

A runtime error occurs when assigning bitset_large type variables to oneself. Such a situation arises when extending stdlib_sorting to support sorting arrays of bitset_large type. The error message is Fortran runtime error: Allocatable argument 'set2' is not allocated. set2 is defined in the procedure assign_large as the variable on the right-hand side of the assignment operator.

This phenomenon can be reproduced with the following code.

program main
    use, intrinsic :: iso_fortran_env
    use :: stdlib_bitsets
    implicit none

    type(bitset_large) :: bitsetl(0:16**3 - 1)
    integer(int32) :: i

    character(32) :: bin
    do i = 0, size(bitsetl, kind=int32) - 1
        write (bin, '(b32.32)') i
        call bitsetl(i)%from_string(bin)
    end do

    bitsetl(0) = bitsetl(0)
end program main

The details are described in the Additional Information section. For simplicity, gfortran 11.2.0 was used as the compiler, and -Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace was used as the compile option. The options are specified in the actions defined in ci_windows.yml.

Expected Behaviour

I expected the bitsetl(0) value to remain unchanged in the above code.

Version of stdlib

2b7280b

Platform and Architecture

Windows 10 22H2 64bit, gfortran 11.2 bundled with quickstart Fortran on Windows

Additional Information

Here I describe how I identified the issue.

The directory structure was

D:\
├─bitset_test
└─stdlib

Cloned stdlib and built it with compiler options used in the actions defined in ci_windows.yml.

D:\>git clone https://github.com/fortran-lang/stdlib.git
D:\>cd stdlib
D:\stdlib>cmake -Wdev -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_Fortran_FLAGS_DEBUG="-Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace" -DCMAKE_MAXIMUM_RANK:String=4 -DCMAKE_Fortran_COMPILER=gfortran -G "Unix Makefiles"
D:\stdlib>cmake --build build

Then install it in the bitset_test directory.

D:\stdlib>cmake --install build --prefix ../bitset_test
D:\stdlib>cd ..\bitset_test

In the bitset_test directory, I compiled main.f90 using gfortran. The main.f90 is shown the Description section.

>gfortran main.f90 -Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace -Iinclude\fortran_stdlib\GNU-11.2.0 -Llib -lfortran_stdlib

When running the generated executable file a.exe, a runtime error occurred, and the error message was displayed:

D:\bitset_test>a
At line 97 of file D:/stdlib/build/src/stdlib_bitsets_large.f90
Fortran runtime error: Allocatable argument 'set2' is not allocated

Error termination. Backtrace:

Could not print backtrace: libbacktrace could not find executable to open
...

The line specified by the message is in the procedure assign_large that performs the assignment operation of bitset_large type.

    pure module subroutine assign_large( set1, set2 )
!     Used to define assignment for bitset_large
        type(bitset_large), intent(out) :: set1
        type(bitset_large), intent(in)  :: set2

        set1 % num_bits = set2 % num_bits
        allocate( set1 % blocks( size( set2 % blocks, kind=bits_kind ) ) )
        set1 % blocks(:) = set2 % blocks(:)

    end subroutine assign_large

The error may be due to the deallocation of the component blocks of set2 caused by the intent(out) attribute for set1 since set1 and set2 are the same variable.

I changed the attribute of set1, the argument specifying the left-hand side of the assignment operator, from out to inout and re-run the executable again, followed by the above procedures. An error still occurred, but the message has changed to Attempting to allocate already allocated variable 'set1'.

D:\bitset_test>a
At line 97 of file D:/stdlib/build/src/stdlib_bitsets_large.f90
Fortran runtime error: Attempting to allocate already allocated variable 'set1'

Error termination. Backtrace:

Could not print backtrace: libbacktrace could not find executable to open
...

Since the same variables are specified on both sides of the assignment operator, it is natural that the variable on the left side is already allocated. But no error should occur in this situation.

The solutions I am trying to are:

  • change the intent of set1 from out to inout and use the automatic array allocation for the component blocks:
        set1 % num_bits = set2 % num_bits
-        allocate( set1 % blocks( size( set2 % blocks, kind=bits_kind ) ) )
-        set1 % blocks(:) = set2 % blocks(:)
+        set1 % blocks = set2 % blocks(:)
  • Or eliminate the user-defined assignment procedure and use Fortran's intrinsic assignment operation of use-defined type.
@degawa degawa added the bug Something isn't working label Jul 8, 2023
@jvdp1
Copy link
Member

jvdp1 commented Jul 8, 2023

Thank you.
I can reproduce the error on my Linux machine.
I will open a PR to replicate this issue and to test different compiler versions.

The error may be due to the deallocation of the component blocks of set2 caused by the intent(out) attribute for set1 >since set1 and set2 are the same variable.

It seems to be indeed the case.

Intel ifort compilers do not seem to have this issue (see #727 ). Therefore, is it a compiler issue or a code issue?

@milancurcic @awvwgk any idea?

Note: since the derived type bitset_large does not contain pointers, I would suggest to remove the user-defined assignment procedure in favor of the intrinsic assignment operation

jvdp1 added a commit to jvdp1/stdlib that referenced this issue Jul 8, 2023
@degawa
Copy link
Contributor Author

degawa commented Jul 11, 2023

Thank you for working on reproducing this issue on your Linux machine.

I don't know why the intel compiler does not reproduce the issue, but I suspect it is the compiler implementation.

The gfortran's behavior may be compiler-dependent, but the code does not seem to violate the Fortran standard, so I would like to fix the assignment procedure for bitset_large to solve the issue.

@PierUgit
Copy link
Contributor

PierUgit commented Jul 15, 2023

the code does not seem to violate the Fortran standard

I'm not sure... When assigning an object to itself, the routine assign_large is called with the same actual object in the two arguments. Argument aliasing is normally not authorized... unless there are some exceptions?

@degawa
Copy link
Contributor Author

degawa commented Jul 15, 2023

Thank you, @PierUgit, for comment on argument aliasing. I asked for help in Fortran Discourse because the issue was beyond my knowledge and may provide important insights for other Fortran users.

@FortranFan
Copy link

FortranFan commented Jul 15, 2023

bitsetl(0) = bitsetl(0)

To make the program conform, my read is you can change the assignment to explicitly reference an expression on the right-hand side:

bitsetl(0) = ( bitsetl(0) )

And then file another report with GCC Bugzilla for that processor.

This might satisfy the principle of least change for stdlib while enhancing that one processor if the support request gets worked on promptly.

@degawa
Copy link
Contributor Author

degawa commented Jul 19, 2023

Thank you, @FortranFan, for the information from a different perspective from what we have been considering.

The modification you suggested would require changes in several places in the sorting procedures for fixing the issue occurring only with the bitset_large type. We will also need to investigate the impact of the changes on the already supported types.
As @jvdp1 and @PierUgit said, the bitset_large type has no pointer component, so removing the user-defined assignment operator for bitset_large type is the easiest way to fix the issue.

@jvdp1
Copy link
Member

jvdp1 commented Jul 19, 2023

The modification you suggested would require changes in several places in the sorting procedures for fixing the issue occurring only with the bitset_large type. We will also need to investigate the impact of the changes on the already supported types.

As the sorting procedures are most likely used for sorting arrays of integers or reals, I am not in favour of such a solution, as it could impact the performances of these procedures. But it questions the versatility of the sorting procedures too.

14NGiestas pushed a commit that referenced this issue Aug 8, 2023
* add explicity in test_stdlib_bitset_large

* add test following issue #726

* remove assign bitset_large

* Update src/stdlib_bitsets_large.fypp

* Update src/stdlib_bitsets.fypp

* remove assign bitset_64

* update specs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants