When using a C main program that has in any way loaded libgfortran.so, redirected C stdin is broken. This is used by the R project <http://www.r-project.org> to run scripts, and even occurs even if the main (C) program has dlopen-ed a DSO with compiled Fortran code linked against libgfortran.so. There is separate bug that stops GFORTRAN_STDIN_UNIT being set to a negative value to avoid the initialization that causes the problem.
Created attachment 8547 [details] Reproduction details, partial fix.
Patch here: http://gcc.gnu.org/ml/fortran/2005-04/msg00278.html
Subject: Bug 20788 CVSROOT: /cvs/gcc Module name: gcc Changes by: fxcoudert@gcc.gnu.org 2005-04-10 10:38:00 Modified files: libgfortran : ChangeLog libgfortran/runtime: environ.c Log message: PR libfortran/20788 * runtime/environ.c (init_unsigned_integer): Function for environment variables we want to be positive. (init_integer): Function to allow negative environment variables (e.g. for GFORTRAN_STDIN_UNIT). Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/ChangeLog.diff?cvsroot=gcc&r1=1.190&r2=1.191 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/runtime/environ.c.diff?cvsroot=gcc&r1=1.9&r2=1.10
For your problem, an easy solution is to use static linking, which seems to avoid that issue (that is, you program works as expected without having to set GFORTRAN_STDIN_UNIT). Otherwise, I commited a patch to fix the issue with negative GFORTRAN_*_UNIT being ignored (on mainline only).
Subject: Re: Loading libgfortran.so clobbers C redirection of stdin Thank you for the suggestion, which had already been tried. It does not always work as the static library is not compiled with -fPIC and so cannot be linked into DSOs to be dlopen-ed. E.g. it fails on x86_64. Being unable to correctly compile a GNU project (R is a GNU project) with silent errors seems to us to be a quite serious bug. It make gcc4/gfortran unusable on a common platform (x86_64), and easy to break on many others. (R is an extensible system, and loading any extension compiled against a dyanmic libgfortran leads silently to incorrect results.) On Sun, 10 Apr 2005, fxcoudert at gcc dot gnu dot org wrote: > > ------- Additional Comments From fxcoudert at gcc dot gnu dot org 2005-04-10 10:38 ------- > For your problem, an easy solution is to use static linking, which seems to > avoid that issue (that is, you program works as expected without having to set > GFORTRAN_STDIN_UNIT). > > Otherwise, I commited a patch to fix the issue with negative GFORTRAN_*_UNIT > being ignored (on mainline only). > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Last reconfirmed|2005-04-10 10:20:45 |2005-04-10 10:38:34 > date| | > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20788 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter. > >
(In reply to comment #5) > Subject: Re: Loading libgfortran.so clobbers C redirection of stdin Also 4.0.0's release of gfortran is only a preview, a lot more bug will be fixed for 4.0.1.
First: using stdio in a mixed Fortran/C is a small nightmare. For short term purposes, I strongly suggest you use the GFORTRAN_STDIN_UNIT=-1 trick. That does exactly what you want (that is, suggest that Fortran runtime library should not mess with standard input). Now, an intersting thing for wandering bug-fixers is that you can mix c and fortran standard input if you disable preconnection and manually open /proc/self/fd/0 to unit 5: $ cat test.c #include <stdio.h> void foo_(void) { char buf[1024]; while(1) { if(fgets(buf, 1024, stdin) == NULL) break; printf("%s", buf); } } $ gcc -c test.c $ cat test1.f external foo character*70 c read (*,'(A)') c print *, c print *, 'calling the C routine' call foo print *, 'end of the program' end $ cat test2.f external foo character*70 c open (5, file='/proc/self/fd/0') read (*,'(A)') c print *, c print *, 'calling the C routine' call foo print *, 'end of the program' end $ gfortran test1.f test.o $ ./a.out < test.c #include <stdio.h> calling the C routine end of the program $ gfortran test2.f test.o $ GFORTRAN_STDIN_UNIT=-1 ./a.out < test.c #include <stdio.h> calling the C routine #include <stdio.h> void foo_(void) { char buf[1024]; while(1) { if(fgets(buf, 1024, stdin) == NULL) break; printf("%s", buf); } } end of the program So, the question is: what is the difference between preconnection and manually openning the unit? I did strace the two processes and I attach the diff of these traces here (about 50 lines, easy to read). I think the solution to this problem is here.
Created attachment 8648 [details] diff of strace (see comment #7)
The problem is that we're using mmap on the preconnected units, which confuses subsequent C I/O on the file. Patch here: http://gcc.gnu.org/ml/fortran/2005-05/msg00008.html Will be committed in source tree as soon as it's reviewed.
Subject: Bug 20788 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-4_0-branch Changes by: fxcoudert@gcc.gnu.org 2005-05-10 08:31:50 Modified files: libgfortran : ChangeLog libgfortran/io : unix.c Log message: PR libfortran/20788 * io/unix.c (fd_to_stream): Add an avoid_mmap argument indicating we don't we to mmap this stream. Use fd_open instead of mmap_open in that case. (open_external): Call fd_to_stream with avoid_mmap = 0. (input_stream): Call fd_to_stream with avoid_mmap = 1. (output_stream): Likewise. (error_stream): Likewise. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.163.2.25&r2=1.163.2.26 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/io/unix.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.21.10.1&r2=1.21.10.2
Subject: Bug 20788 CVSROOT: /cvs/gcc Module name: gcc Changes by: fxcoudert@gcc.gnu.org 2005-05-10 08:34:58 Modified files: libgfortran : ChangeLog libgfortran/io : read.c Log message: PR libfortran/20788 Missing entry from previous commit: * io/unix.c (fd_to_stream): Add an avoid_mmap argument indicating we don't we to mmap this stream. Use fd_open instead of mmap_open in that case. (open_external): Call fd_to_stream with avoid_mmap = 0. (input_stream): Call fd_to_stream with avoid_mmap = 1. (output_stream): Likewise. (error_stream): Likewise. Really committing: * io/read.c (read_f): Accept 'e', 'E', 'd' and 'D' as first non-blank characters of a real number. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/ChangeLog.diff?cvsroot=gcc&r1=1.210&r2=1.211 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libgfortran/io/read.c.diff?cvsroot=gcc&r1=1.8&r2=1.9
This one is fixed. Thanks for the bug report!