Integer or real to character string: bug with gfortran with OpenMP?

This post is related this “Equivalent of str function (from python) in Fortran”, but I prefer to open a new post.

For a large code, I want to use a function equivalent to « TO_string » to convert an integer or a real to a character string to create some log output. There are several implementations, I’ve got one that is similar to those in the Fortran stdlib or other libraries (fstring or M_msg). In all these procedures, the integer (except for Fortran stdlib) or the real are written in a character string with the intrinsic « write ». These work fine.

However, when I’m using it with openmp with gfortran, I’ve got unexpected behavior. Some characters get mixed up or missing.
When, I’m using an opemmp critical zone enclosing the character string set up, the problem is solved. However, I don’t want to use a critical zone.

The following code (see below) is a minimal example showing this behavior. It has three tests:

  1. TO_string extract from QDUtilLib using OpenMP without critical zone
  2. TO_string extract from stdlib using OpenMP without critical zone
  3. TO_string extract from QDUtilLib using OpenMP with critical zone

The first two tests give unexpected behavior with gfortran (v10 and v12 on linux, v13 on macOS). The third test works as expected with gfortran (see below the output file res.txt)
The three tests work fine with ifx (v2023 on linux)

Concerning, the gfortran problem, I thought, it came from the writing in a character string. However, the stdlinb TO_string procedure for integer does not use this. So, it seems this problem is more general and related to the character manipulation.

Probably, it is a gfortran bug.

Do you know how to overcome this problem?


Fortran code:
teststring_OMP.f90 (4.2 KB)

output (gfortran v13, macOS)
res.txt (4.1 KB)

That is surprising.

Since I’ve been reading the OpenMP spec recently, it says the following:

The OpenMP specification makes no guarantee that input or output to the same file is synchronous when executed in parallel. In this case, the programmer is responsible for synchronizing input and output processing with the assistance of OpenMP synchronization constructs or library routines. For the case where each thread accesses a different file, the programmer does not need to synchronize access.

It appears fine then since each internal write across different threads has its own distinct character buffer (i.e. different file). But the gfortran documentations states there are some caveats when it comes to thread-safety of the READ and WRITE statements: Thread-safety of the runtime library (The GNU Fortran Compiler)

I don’t see any reason why the stdlib version shouldn’t work though. Could you try adding the recursive attribute to “trick” the compiler to produce a reentrant procedure? (Not a guarantee for thread-safety, but perhaps it changes something.)

Inspecting the intermediate form that gfortran produces using the -fdump-tree-original flag may also shed some light on what is going on. Here it is in case anyone would like to scrutinize it:

I observe no difference in the procedure stdlib_to_string_1_int32 when switching on -fopenmp or adding the recursive attribute.

Thanks @ivanpribec, I’ve tried with the recursive attribute, but it doesn’t do the trick.

1 Like

Oddly enough, when the integer to string (with write) is used without a function, the problem disappears!

The code below works as expected with gfortran and OpenMP.

Fortran code:

teststring2_OMP.f90 (1.4 KB)

When I tried the original test program (in the first post) with gfortran-10 or 11, it gives the following error. So could you check the corresponding line? (“clen” may be insufficient…?)

test with OpenMP (without CRITICAL) with QDUtil TO_string
At line 119 of file teststring_OMP_orig.f90
Fortran runtime error: End of record

For some reason, if I attach -fopenmp, this error disappears and (apparently) gives the expected result with gfortran-10 and 11 (both on Linux/Ubuntu and Mac(Intel)). But I may be doing something wrong for compilation, so not sure yet…

EDIT: I was looking only at the last output of the result (with CRITICAL), so please ignore the above message (sorry!!). Without CRITICAL, I also got a strange result with gfortran-10 and 11 both on Ubuntu and Mac.

EDIT2: If I change character(:), allocatable :: string for the result variable to character(10) :: string, both QDutil and stdlib seem to work as expected. Then, character(:), allocatable for function result + OpenMP might have some issue in gfortran…? (not sure yet)

This looks very similar to what is reported in Bug 113797.

3 Likes

As older versions of gfortran are mentioned, the resolved Bug 99529 might also be relevant.

Thanks @Martin. Indeed, this bug seems related to my problem.