Bug 13675 - #including a precompiled header more than once in the same unit fails
Summary: #including a precompiled header more than once in the same unit fails
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: pch (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: 4.4.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 12707 15118 24029 (view as bug list)
Depends on:
Blocks: 12707
  Show dependency treegraph
 
Reported: 2004-01-14 03:10 UTC by jbrandmeyer
Modified: 2014-02-16 13:17 UTC (History)
17 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail: 3.4.0 4.1.0 4.0.0
Last reconfirmed: 2005-06-12 20:41:50


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description jbrandmeyer 2004-01-14 03:10:18 UTC
This has also been observed on powerpc-apple-darwin6.8 with current sources as
of 1pm US Eastern time today when configured with ../gcc/configure
--enable-languages=c,c++ --program-suffix=-3.4
--enable-version-specific-runtime-libs

Both the C and C++ compilers are affected.

If a header file is precompiled and #included more than once in the same
compilation unit, the second inclusion generates an error like
"filename:linenumber:columnnumber calling fdopen: Bad file descriptor"

Consider this trivial example:
-----------pch-header.h-------
#ifndef PCH_HEADER_TEST_H
#define PCH_HEADER_TEST_H
extern int i;
#endif
----------another-pch-user.h-------
#include "pch-header.h"
----------pch-user1.cpp-------
#include "pch-header.h"
#include "another-pch-user.h"
---------------end----------
$ g++-3.4 -c -o pch-header.h.gch pch-header.h
$ g++-3.4 -c -o pch-user1.o pch-user1.cpp
In file included from pch-user1.cpp:2:
another-pch-user.h:1:24: calling fdopen: Bad file descriptor


$ g++-3.4 -v
Reading specs from /home/jonathan/lib/gcc/i686-pc-linux-gnu/3.4.0/specs
Configured with: ../gcc/configure --enable-languages=c,c++ --program-suffix=-3.4
--disable-checking --prefix=/home/jonathan
Thread model: posix
gcc version 3.4.0 20040108 (experimental)
Comment 1 Geoff Keating 2004-04-16 21:46:57 UTC
Doesn't happen on Apple's gcc 3.3.  It would be helpful to know when this got introduced.
Comment 2 Geoff Keating 2004-04-17 00:43:19 UTC
The example doesn't appear to fail if you use 'gcc' instead of 'g++'.
Comment 3 jbrandmeyer 2004-04-17 02:51:17 UTC
Subject: Re:  #including a precompiled header more than once
	in the same unit fails

On Fri, 2004-04-16 at 20:43, geoffk at gcc dot gnu dot org wrote:
> ------- Additional Comments From geoffk at gcc dot gnu dot org  2004-04-17 00:43 -------
> The example doesn't appear to fail if you use 'gcc' instead of 'g++'.

Sure it does:

$ gcc-3.4 -v -c -o pch-user1.o pch-user1.c
Reading specs from
/home/jonathan/programs/lib/gcc/i686-pc-linux-gnu/3.4.0/specsConfigured
with: ../gcc/configure --enable-languages=c,c++
--prefix=/home/jonathan/programs --disable-checking
--program-suffix=-3.4 --enable-version-specific-runtime-libs
Thread model: posix
gcc version 3.4.0 20040416 (prerelease)
 /home/jonathan/programs/libexec/gcc/i686-pc-linux-gnu/3.4.0/cc1 -quiet
-v pch-user1.c -quiet -dumpbase pch-user1.c -mtune=pentiumpro
-auxbase-strip pch-user1.o -version -o /tmp/ccKySByl.s
ignoring nonexistent directory
"/home/jonathan/programs/lib/gcc/i686-pc-linux-gnu/3.4.0/../../../../i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /home/jonathan/programs/include
 /home/jonathan/programs/lib/gcc/i686-pc-linux-gnu/3.4.0/include
 /usr/include
End of search list.
GNU C version 3.4.0 20040416 (prerelease) (i686-pc-linux-gnu)
        compiled by GNU C version 3.4.0 20040416 (prerelease).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64507
In file included from pch-user1.c:2:
another-pch-user.h:1:24: calling fdopen: Bad file descriptor

-Jonathan Brandmeyer

Comment 4 Geoff Keating 2004-04-17 08:12:44 UTC
In the example, the file is called "pch-user1.cpp", not "pch-user1.c".  With identical files,

+ /tmp/gcc-20030730-1/bin/g++ -c -o pch-header.h.gch pch-header.h
+ /tmp/gcc-20030730-1/bin/g++ -c -o pch-user1.o pch-user1.cpp
In file included from pch-user1.cpp:2:
another-pch-user.h:1:24: calling fdopen: Bad file descriptor

but

+ /tmp/gcc-20030730-1/bin/gcc -c -o pch-header.h.gch pch-header.h
+ /tmp/gcc-20030730-1/bin/gcc -c -o pch-user1.o pch-user1.cpp
[completes successfully]

This is interesting (what is different about gcc vs. g++ in this case?), but mostly it's a gotcha for people 
like me who forget to use g++ and then can't reproduce the bug.
Comment 5 Geoff Keating 2004-04-17 08:18:07 UTC
This seems to be introduced by Neil's cppfiles.c rewrite, in particular with CVS HEAD as of 2003-07
-29 22:20:00 UTC, I get no error message and successful compilation on the testcase, and as of 2003
-07-29 22:35:00 UTC, I get the error message.  The only change between those two times was Neil's 
change.  (I am not sure if this was really caused by the change or just exposed by it.)
Comment 6 Geoff Keating 2004-04-17 08:43:02 UTC
*** Bug 12707 has been marked as a duplicate of this bug. ***
Comment 7 Andrew Pinski 2004-04-24 18:54:32 UTC
*** Bug 15118 has been marked as a duplicate of this bug. ***
Comment 8 v13@it.teithe.gr 2004-04-24 19:09:09 UTC
This is a way to reproduce it: 
 
hell:/tmp/2$ cat a.h 
#define A "koko" 
 
hell:/tmp/2$ cat b.h 
#include "a.h" 
#define C B 
 
hell:/tmp/2$ cat c.h  
#include "a.h" 
#include "b.h" 
#define D B 
 
hell:/tmp/2$ gcc a.h -o a.h.gch 
hell:/tmp/2$ gcc b.h -o b.h.gch 
hell:/tmp/2$ gcc c.h -o c.h.gch 
In file included from c.h:2: 
b.h:1:15: calling fdopen: Bad file descriptor 
 
hell:/tmp/2$ g++ a.h -o a.h.gch 
hell:/tmp/2$ g++ b.h -o b.h.gch 
hell:/tmp/2$ g++ c.h -o c.h.gch 
In file included from c.h:2: 
b.h:1:15: calling fdopen: Bad file descriptor 
 
But if we change c.h to: 
hell:/tmp/2$ cat c.h 
#include "b.h" 
#include "a.h" 
#define D B 
 
It works... 
 
So this happens when compiling header C which includes header B and A, and 
header B includes header A too, but only if header A is included in C before 
B. :) 
Comment 9 pegasus 2004-06-03 03:55:43 UTC
Simpler test case:
touch a.h
echo '#include "a.h"' > a.c
echo '#include "a.h"' >> a.c
gcc a.h -o a.h.gch
gcc -c a.c -o a.o

The last gcc execution gives:
a.c:2:15: calling fdopen: Bad file descriptor

Possible workaround:
Disclamer: This is the first time I look at gcc's source code. This patch is
UNtested. Don't blame me if anything bad happens, etc.. 
This "works" by telling gcc to load the file once only. If loading the file more
than once was intentional, this will break your compilation.

--- gcc-3.4.0/gcc/cppfiles.c    2004-02-07 09:33:08.000000000 -0500
+++ gcc-3.4.0-new/gcc/cppfiles.c        2004-06-02 22:55:50.316126744 -0400
@@ -577,6 +577,7 @@
       pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname);
       close (file->fd);
       file->fd = -1;
+      _cpp_mark_file_once_only (pfile, file);
       return false;
     }

Comment 10 Geoff Keating 2004-06-25 22:02:30 UTC
That patch certainly isn't a good idea, marking things once-only changes the semantics.
Comment 11 Alexander Darovsky 2005-09-22 10:54:24 UTC
The same problem stays unresolved in GCC-3.4.4  
My test is: 
 
$ cat header1.h 
$ cat header2.h 
#include "header1.h" 
 
$ cat test.cpp 
#include "header1.h" 
#include "header2.h" 
 
main() 
{ 
} 
 
$g++ -x c++ -c header1.h 
g++ test.cpp 
In file included from test.cpp:2: 
header2.h:1:21: calling fdopen: Bad file descriptor 
test.cpp:4: internal compiler error: Segmentation fault 
 
Comment 12 Andrew Pinski 2005-09-23 12:45:02 UTC
*** Bug 24029 has been marked as a duplicate of this bug. ***
Comment 13 Rupert Swarbrick 2006-04-01 23:19:00 UTC
(In reply to comment #11)
> The same problem stays unresolved in GCC-3.4.4  

As far as I can tell, the problem is STILL unresolved with g++ 4.1, but there is a workaround for users that I post here for information.

Create a "proxy" header. e.g. if there is some PCH enabled "gtk_includes.hh", create "gtk_includes_proxy.hh", which is not precompiled and just has the contents:
#ifndef GTK_INCLUDES_PROXY_HEADER
#define GTK_INCLUDES_PROXY_HEADER
#include "gtk_includes.hh"
#endif

This will ensure that the actual precompiled header is only included once per module.
Comment 14 tim blechmann 2007-01-01 23:53:07 UTC
this is still a problem in the 4.2 branch
Comment 15 tim blechmann 2007-05-18 00:06:24 UTC
4.2.0 still has this bug ... maybe someone with enough power can add this to the "known to fail" section?
Comment 16 lukas 2007-11-27 03:06:35 UTC
I got the same problems using gch in some projects. I'm using only one precompiled header (defaults.h).
gcc is from SUSE Linux Enterprise Server 10
GNU C++ version 4.1.0 (SUSE Linux) (i586-suse-linux)
        compiled by GNU C version 4.1.0 (SUSE Linux).

strace shows that the fd for the pch is closed twice (but not opened twice) which seems to lead to the error
[pid 20079] stat64("defaults.h.gch", {st_mode=S_IFREG|0644, st_size=9211224, ...}) = 0
[pid 20079] open("defaults.h.gch", O_RDONLY|O_NOCTTY) = 5
....
[pid 20079] close(5)                    = 0
[pid 20079] munmap(0xb7d18000, 4096)    = 0
[pid 20079] close(5)                    = -1 EBADF (Bad file descriptor)

The example from comment #11 leads to the same strace even if you use only header1.h twice in test.cpp.

I removed all the not needed duplicates. This resolves most of the problems.

In some cases it was not possible to avoid the defaults.h in the headerfiles because these are automatically generated source files (qt moc) which do not include the precompiled header from the source so I had to put it in the corresponding header. 
I used the define from the precompiled header in these headers to avoid the conflict:
#ifndef __DEFAULTS_H__
#include "defaults.h"
#endif

But at the end I got a problem with the debug version.

As I did not find any duplicate includes in the header and the moc file.
I replaced the gch header by a copy which is not precompiled and the source compiled succesfully (as expected).
I moved the precompiled header include from the header to the moc file for testing and it compiled successfully. (suspicious)

Compiling with -v shows the following output:
GNU C++ version 4.1.0 (SUSE Linux) (i586-suse-linux)
        compiled by GNU C version 4.1.0 (SUSE Linux).
GGC heuristics: --param ggc-min-expand=77 --param ggc-min-heapsize=88425
Compiler executable checksum: 96db6faba1662b7eb3475b25f8211ddd
 as -V -Qy -o DrawWindow.moc.o /tmp/ccMxyQj6.s
GNU assembler version 2.17.50.0.6 (i386-redhat-linux-gnu) using BFD version 2.17.50.0.6 20061020
/tmp/ccMxyQj6.s: Assembler messages:
/tmp/ccMxyQj6.s:290: Error: file number 2 already allocated

The error does not occur if I use -g2 instead -g3 for compiling the precompiled header but still using -g3 for all other files (with strace I see that the precompiled header is used). But to avoid unpredictable results I'm using now only -g2 to avoid conflicts.

Use the example from comment #11 to reproduce it without including header1.h in the test.cpp:
$ cat test.cpp 
#include "header2.h" 
 
main() 
{ 
} 

compile with:
gcc -g3 -c -o header1.h.gch header1.h
gcc -g3 -c -o test test.cpp

If you use -g2 the bug does not occur.
If you include header1.h directly in test.cpp not via header2.h the bug does not occur.

Is this a bug of "gcc" causing "as" to fail or a bug of "as"?
I will report it as a new bug if someone can check to whom it belongs.
Comment 17 Jakub Jelinek 2008-04-01 10:58:46 UTC
Subject: Bug 13675

Author: jakub
Date: Tue Apr  1 10:58:02 2008
New Revision: 133790

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=133790
Log:
	PR pch/13675
	* files.c (struct _cpp_file): Remove pch field.
	(pch_open_file): Don't set file->pch, just file->pchname.
	(should_stack_file): After pfile->cb.read_pch call
	free pchname and clear pchname, don't close file->fd.
	Test file->pchname instead of file->pch.  Don't close fd after cb.
	(_cpp_stack_include): Test file->pchname instead of file->pch.

	* c-pch.c (c_common_read_pch): On error close (fd) resp. fclose (f).

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/c-pch.c
    trunk/libcpp/ChangeLog
    trunk/libcpp/files.c

Comment 18 Jakub Jelinek 2008-10-17 20:19:24 UTC
Fixed in 4.4.
Comment 19 Giovanni Funchal 2009-05-27 10:56:38 UTC
(In reply to comment #18)
> Fixed in 4.4.
> 

I still have this bug on 4.4.0, when using pch and -g3.
Comment 20 Giovanni Funchal 2009-05-27 14:34:37 UTC
For the problem reported on Comment #16, see Bug #40272.
Comment 21 Jackie Rosen 2014-02-16 13:17:25 UTC Comment hidden (spam)