Execute_command_line problem

This program works well with ifort, ifx and AMD flang, but with gfortran in my system

gcc version 13.1.0 (Ubuntu 13.1.0-8ubuntu1~22.04)

it prints nothing at run-time and has to be stopped manually. Is the bug in my program or gfortran? The program:

program test
! f2008 using execute_command_line and assuming Linux
  implicit none
  print "(A,L2)", 'I am john',iam('john')
  print "(A,L2)", 'I am JOHN',iam('JOHN')

contains

  logical function iam(      name)
    character(*),intent(in)::name
    integer estat
    character(len(name)+38):: cmd
    cmd = 'if [ `whoami` != "'//name//'" ]; then exit 1; fi'
    call execute_command_line(cmd,exitstat=estat)
    iam = (estat==0)
  end function iam
end program test

The output from flang, ifx or ifort:

I am john T
I am JOHN F
1 Like

You have named the program “test”, is that also the name of the executable? I remember from a grey past that such a name may confuse the shell.

This is the same behavior that one sees when recursive i/o is invoked. Based on that observation, if you change the main program to

   logical :: q
   q = iam('john')
   print "(A,L2)", 'I am john', q
   q = iam('JOHN')
   print "(A,L2)", 'I am JOHN', q

then I think the code will work (it does on MacOS+gfortran). Of course, the code is not doing recursive i/o, so this appears to be some kind of compiler or library bug.

[edit] I experimented a little more with this. It appears that the error has nothing to do with the execute_command_line intrinsic. If you comment out that call, the program still hangs. I also experimented a little with constructing the cmd string with substring indexing and assignments,

    cmd(1:18) = 'if [ `whoami` != "'
    cmd(18+1:18+len(name)) = name
    cmd(19+len(name):) = '" ]; then exit 1; fi'

and the program still hangs. If you eliminate cmd, and just insert the expression as the subroutine argument, it still hangs. I don’t see anything wrong with either the original code or any of these modified versions, they all look alright to my eye. One can disagree with the concept of executing functions just for side effects (i.e. a subroutine might be better), but the language allows this so it looks like it should work.

No @Arjen I never call an executable “test”. I shall report the bug to gfortran.

Not on my side:

/tmp$ gfortran test.f90 && ./a.out
I am john F
I am JOHN F

I should have said, “If I comment out that call…”

Did the logical :: q version work for you?

I hope this gets fixed quickly, this seems like a dangerous land mine to have sitting somewhere in the compiler.

A minimalist version, hanging on the second call (in the print):

program test
  implicit none
  logical :: foo

  ! OK:
  call execute_command_line("export A=3")

  foo = iam()
  ! OK:
  print "(L2)", foo
  ! NOK (with gfortran):
  print "(L2)", iam()

contains

  logical function iam()
    call execute_command_line("export A=3")
  end function iam

end program test
1 Like

Trying to be even more minimalist, I tried to pass an empty string to execute_command_line():

call execute_command_line("")
end

and discovered another difference between GFortran and ifx:

/tmp$ ifx test2.f90 && ./a.out
forrtl: severe (124): Invalid command supplied to EXECUTE_COMMAND_LINE
Image              PC                Routine            Line        Source             
a.out              00000000004051A3  Unknown               Unknown  Unknown
a.out              000000000040515D  Unknown               Unknown  Unknown
libc.so.6          00007F93106280D0  Unknown               Unknown  Unknown
libc.so.6          00007F9310628189  __libc_start_main     Unknown  Unknown
a.out              0000000000405075  Unknown               Unknown  Unknown
/tmp$ gfortran test2.f90 && ./a.out
/tmp$

If the string contains one space, ifx is OK.

Page 367, the Fortran 2018 standards states:

COMMAND shall be a default character scalar. It is an INTENT (IN) argument. Its value is the command line to be executed. The interpretation is processor dependent.

Is it standard-conforming for a function not to assign any return value? I’d guess it isn’t.

2 Likes

Fortran 2023 standard, page 340:

if the function result is not a pointer, its value shall be defined by the function.

ifx complains:

$ ifx test.f90
test.f90(16): warning #6178: The return value of this FUNCTION has not been defined.   [IAM]
  logical function iam()
-------------------^

GFortran does not complain.

Fixed code:

  logical function iam()
    call execute_command_line("export A=3")
    iam = .true.
  end function iam
1 Like

This is exactly where the issue lies. With gfortran you cannot call a function involving I/O from a print statement. This also hangs:

program test
  implicit none
  print "(A,L2)", 'I am john',iam('john')
contains
  logical function iam(      name)
    character(*),intent(in)::name
    print *, 'hello world!'
    iam = .false.
  end function iam
end program test

probably the bash script still involves accessing stdout

1 Like

Yes, it seems stdout is locked by the first print. And the second print is waiting (forever) for stdout to be unlocked.

I remember we had already discuss that somewhere in the Discourse.

This is true when the iam() function has itself a print/write statement. But the original code had no print/write statements in the function.

While this is true in some cases, the code still hangs when the execute_command_line() operation does not write to stdout. Furthermore, on unix/posix operating systems, the execute_command_line() operation is performed in a separate process. One normally expects separate processes to have their own enviornments, their own file handles, etc., so one would expect this to work even if it does write to stdout (possibly with the results interlaced together in some arbitrary way).

This does work with other compilers, so it is not an OS feature, it appears to be specific to the gfortran compiler and/or its i/o libraries. And it fails on both linux and MacOS in a similar way, both unix/posix systems, but very different kernels.

1 Like

This is what I see from lldb when I ctrl+c it:

  * frame #0: 0x0000000182630524 libsystem_kernel.dylib`__psynch_mutexwait + 8
    frame #1: 0x000000018266b168 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
    frame #2: 0x0000000182668af8 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
    frame #3: 0x0000000100712acc libgfortran.5.dylib`_gfortrani_flush_all_units + 104
    frame #4: 0x00000001007252b8 libgfortran.5.dylib`execute_command_line + 56
    frame #5: 0x0000000100725514 libgfortran.5.dylib`_gfortran_execute_command_line_i4 + 132
    frame #6: 0x0000000100003c6c a.out`iam.0 at ffff.f90:14:49
    frame #7: 0x0000000100003d1c a.out`MAIN__ at ffff.f90:4:41
    frame #8: 0x0000000100003e04 a.out`main at ffff.f90:5:41
    frame #9: 0x00000001822ed0e0 dyld`start + 2360
1 Like