Bug 10332 - Template classes are not instantiated correctly in presense of #pragma pack()
Summary: Template classes are not instantiated correctly in presense of #pragma pack()
Status: RESOLVED DUPLICATE of bug 7046
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-04-07 10:46 UTC by Igor A. Goussarov
Modified: 2003-08-22 02:05 UTC (History)
5 users (show)

See Also:
Host: i386-unknown-freebsd4.4
Target: i386-*-freebsd4.4
Build: i386-unknown-freebsd4.4
Known to work:
Known to fail:
Last reconfirmed:


Attachments
alignment_bug_02.tgz (792 bytes, application/x-gzip )
2003-05-21 15:17 UTC, Igor A. Goussarov
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Igor A. Goussarov 2003-04-07 10:46:02 UTC
The packing size used for class template instantiation is set by the #pragma pack directive which is in effect at the point of template instantiation (whether implicit or explicit), rather then by the #pragma pack directive which was in effect at the point of class template definition.

This is not a correct behaviour, because in a complex program it's hard to control the point of implicit instantiation of any given template class. And the wrong packing size is leading to incorrect code generation if a given template class was instantiadet with different packing sizes in different translation units. Consider the code examples in Howtorepeat section.

Related problem reports: other/4957

Release:
3.2 (and seen on mainline -LJR)

Environment:
System: FreeBSD gate.studio1001.akella.ru 4.4-RELEASE FreeBSD 4.4-RELEASE #11: Thu Jun 6 12:58:54
host: i386-unknown-freebsd4.4
build: i386-unknown-freebsd4.4
target: i386-unknown-freebsd4.4
configured with: /usr/src/gcc-3.2/configure --prefix=/usr

How-To-Repeat:
1. Try to compile and run the following example (all code examples in this report could be compiled with "g++ file.cpp", no special command-line options are required)

//---------------------------- begin example
#include <stdio.h>

#pragma pack(4)

template <typename X >
struct T
{
    char      x1;   /* Usually 3 padding bytes are added after x1 member. */
    int       x2;
};

#pragma pack(1)
template T<int>;   /* T<int> is instantiated here */

#pragma pack(4)
template T<float>; /* T<float> is instantiated here */

int main()
{
 printf("sizeof T<int>   = %d\n", sizeof(T<int>));
 printf("sizeof T<float> = %d\n", sizeof(T<float>));
}
//---------------------------- end example

(parameter types 'int' and 'float' are not used in any way, they are required just to separate two template instances)

The output is:
sizeof T<int>   = 5
sizeof T<float> = 8
Which shows that the size (and member offsets) of the template class depends on the #pragma pack at place of instantiation.

2. There is a more complicated example which shows how to trigger this bug accidently.
Unpack the attached archive and compile two sample translation units (tu01.cpp and tu02.cpp) in alignment_bug/case_02 directory. The only difference between these translation units is the order of #include directives which causes different implicit instantiation of the same template class (include guards are skipped in such simple case). This test case repeats the behaviour reported in other/4957.
Comment 1 Igor A. Goussarov 2003-04-07 10:46:02 UTC
Fix:
Do not rely on implicit instantiation. Instantiate all desired template classes explicitly (sic!).

LJR: Also consider using the attribute form instead of pragma form
to control  implicit instantiation behavior.  This binds closer.

template <typename X >
struct T
{
    char  x1;   /* Usually 3 padding bytes are added after x1 member. */
    int   x2;
} __attribute ((__packed__));
Comment 2 Loren Rittle 2003-04-11 01:16:40 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: Igor created a small test case which displays the behavior he considers a bug and included an analysis of the failure.  I will add only one comment: because a feature is hard to use in a complex program does not imply that the feature has incorrect behaviour.  In this case, #pragma pack came from a C ABI.  It is doubtful anyone ever looked at the rules as applied to C ++.  E.g. no documentation on such interactions is found in tm.texi.  One correct resolution to this PR is to update our documentation.  (I will also add another user-level fix.)
Comment 3 igusarov 2003-04-11 15:46:35 UTC
From: "Igor A. Goussarov" <igusarov@akella.com>
To: ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
   nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Cc:  
Subject: Re: c++/10332: Template classes are not instantiated correctly in
 presense of #pragma pack()
Date: Fri, 11 Apr 2003 15:46:35 +0400

 Hello Loren and the team,
 
     Thank you for taking time to examine this another report!
     Unfortunately the fix you suggested isn't very good for two reasons:
 a) __atribute__ is much less portable (compared to #pragma pack which is 
 supported at least by gcc, MSVC, BCB and CodeWarrior)
 b) the fix doesn't address the problem.
 
     I _don't_ want to have packed template classes. I want to have 
 ordinary templates, which use default packing and alignment. But: if 
 this template occasiously got instantiated at the point where "#pragma 
 pack" was set to some obscure value, then the template instance somewhy 
 become packed! This is the behaviour I object to.
 
     Let me put it in other words:
 1. I wrote a template class which doesn't need any packing.
 2. I was using this template class in many translation units all over 
 the program.
 3. One day I wrote another not-template class (or POD struct), which 
 _has_ to be packed.
 4. If the template class in question is implicitly instantiated from 
 within the said packed struct, it miraculously becomes packed.
 5. More disasters follows when several TUs are linked together...
 
     So you see, I'm not trying to apply packing to template classes 
 intentionally. Well, in a sense, packing and templates are used 
 together, since a single translation unit contains them both. But it 
 doesn't look right to me that some class affects the instantiation of a 
 previously defined template. This is kind of... not right.
     For example, imagine that the layout of vtable for polymorphic 
 classes was dependent on the use of some feature in some other place in 
 the program. This would come as a surprise to the developer of the said 
 class, because he always firmly belived that since the class was fully 
 defined nothing more can change it.
     So did I, and so was I surprised. Actually, I've called this 
 behaviour "a bug" because I get used to think that once a class was 
 defined nothing more can change it (and inherently its layout).
 
     Being a programmer myself I can see where all this comes from: it is 
 likely that gcc uses some global variable for storing the current 
 packing size instead of associating the packing size with each 
 individual data structure. Thus, when there is a need to create an 
 instance of a template class, the compiler simply uses the current value 
 of that global variable.
     If this is the case, then changing such behaviour of the compiler is 
 not easy. I mean, it looks more like design issue rather then like 
 implementation bug. Also I can see that such situation is impossible to 
 detect and thus no diagnostic message is ever possible... Pity.
 
 Best Regards,
 Igor
 

Comment 4 velco 2003-04-11 16:52:55 UTC
From: Momchil Velikov <velco@fadata.bg>
To: "Igor A. Goussarov" <igusarov@akella.com>
Cc: ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
	nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in presense of #pragma pack()
Date: 11 Apr 2003 16:52:55 +0300

 >>>>> "Igor" == Igor A Goussarov <igusarov@akella.com> writes:
 
     Igor>     Being a programmer myself I can see where all this comes from: it
     Igor> is likely that gcc uses some global variable for storing the current
     Igor> packing size instead of associating the packing size with each
     Igor> individual data structure. Thus, when there is a need to create an
     Igor> instance of a template class, the compiler simply uses the current
     Igor> value of that global variable.
 
 What is the scope of #pragma pack ?
 
 ~velco

Comment 5 velco 2003-04-14 11:57:04 UTC
From: Momchil Velikov <velco@fadata.bg>
To: "Igor A. Goussarov" <igusarov@akella.com>
Cc: ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
	nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in presense of #pragma pack()
Date: 14 Apr 2003 11:57:04 +0300

 >>>>> "Igor" == Igor A Goussarov <igusarov@akella.com> writes:
 
     Igor> Momchil Velikov wrote:
     >> What is the scope of #pragma pack ?
 
     Igor>     Apparently, from the line it is encountered at till the end of
     Igor> translation unit or till the next #pragma pack.
 
 In that case holding it in a global variable looks appropriate, no ?
 
 ~velco

Comment 6 igusarov 2003-04-14 12:50:28 UTC
From: "Igor A. Goussarov" <igusarov@akella.com>
To: Momchil Velikov <velco@fadata.bg>
Cc: ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
   nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in
 presense of #pragma pack()
Date: Mon, 14 Apr 2003 12:50:28 +0400

 Momchil Velikov wrote:
 > What is the scope of #pragma pack ?
 
     Apparently, from the line it is encountered at till the end of 
 translation unit or till the next #pragma pack.
     Er... Was it one of them trick questions?
 
 Best Regards,
 Igor
 

Comment 7 igusarov 2003-04-14 14:02:26 UTC
From: "Igor A. Goussarov" <igusarov@akella.com>
To: Momchil Velikov <velco@fadata.bg>
Cc: ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
   nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in
 presense of #pragma pack()
Date: Mon, 14 Apr 2003 14:02:26 +0400

 Momchil Velikov wrote:
  >>>>>>"Igor" == Igor A Goussarov <igusarov@akella.com> writes:
  >     Igor> Momchil Velikov wrote:
  >     >> What is the scope of #pragma pack ?
  >
  >     Igor>     Apparently, from the line it is encountered at till the 
 end of
  >     Igor> translation unit or till the next #pragma pack.
  >
  > In that case holding it in a global variable looks appropriate, no ?
 
     Up to a certain degree, yes. The concept of "packing" is applied to 
 structures, thus the packing size is a property of each structure. 
 Holding it in a global variable is justifiable only if there's 
 absolutely no chance that this variable could potentially be altered 
 before it is used to create an internal compiler representation of the 
 structure in question. I grant that C plain structures are 
 "instantiated" immediately at the point of their definition. C++ 
 templates are not.
     The compiler still have to store the last packing size in a global 
 var (or a stack, to support #pragma push/pop). But as soon as a struct 
 definition is encountered (whether a template or not), the value of that 
 global var should've been copied to that structure description. And the 
 compiler should later use the value from the structure description 
 rather then from the global var. In other words, the global var only 
 stores the current packing size and is used _solely_ to initialize the 
 packing size of each new defined struct.
     As Loren has mentioned, #pragma pack came from C compiler, and 
 probably its interference with C++ entities was not fully considered...
     By now, I'm most interested in figuring out the point of view of the 
 gcc developers: do you tend to think that the current interference of 
 #pragma pack and templates is an undocumented feature or an incorrect 
 behaviour?
 
 Best Regards,
 Igor
 

Comment 8 rittle 2003-04-14 18:42:04 UTC
From: Loren James Rittle <rittle@latour.rsch.comm.mot.com>
To: igusarov@akella.com
Cc: velco@fadata.bg, ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org,
   gcc-prs@gcc.gnu.org, nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in presense of #pragma pack()
Date: Mon, 14 Apr 2003 18:42:04 -0500 (CDT)

 In article <3E9A8732.7000600@akella.com>,
 "Igor A. Goussarov" <igusarov@akella.com> writes:
 
 >>>> What is the scope of #pragma pack ? 
 Igor> Apparently, from the line it is encountered at till the end of
 Igor> translation unit or till the next #pragma pack.
 >> In that case holding it in a global variable looks appropriate, no ?
 
 >     Up to a certain degree, yes. The concept of "packing" is applied to 
 > structures, thus the packing size is a property of each structure. 
 > Holding it in a global variable is justifiable only if there's 
 > absolutely no chance that this variable could potentially be altered 
 > before it is used to create an internal compiler representation of the 
 > structure in question. I grant that C plain structures are 
 > "instantiated" immediately at the point of their definition. C++ 
 > templates are not. [...]
 
 >     By now, I'm most interested in figuring out the point of view of the 
 > gcc developers: do you tend to think that the current interference of 
 > #pragma pack and templates is an undocumented feature or an incorrect 
 > behaviour?
 
 Agreed.  The proper fix is to either (a) document what is happening,
 only available if no external spec says we are doing something wrong,
 or (b) retain the global flag but capture it's value and bind it for
 use when the C++ template is actually instantiated.
 
 I'd favor (b) unless disallowed by the spec(s) that we claim to
 implement for this pragma.  This is either an easy patch (if the
 infrastructure allows it) or a nightmare (if it doesn't).  FYI, if
 updating the documentation is not enough, this is outside my area to
 productively fix.
 
 Regards,
 Loren

Comment 9 igusarov 2003-04-15 17:39:08 UTC
From: "Igor A. Goussarov" <igusarov@akella.com>
To: rittle@labs.mot.com
Cc: velco@fadata.bg, ljrittle@gcc.gnu.org, gcc-bugs@gcc.gnu.org,
   gcc-prs@gcc.gnu.org, nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Subject: Re: c++/10332: Template classes are not instantiated correctly in
 presense of #pragma pack()
Date: Tue, 15 Apr 2003 17:39:08 +0400

 Loren James Rittle wrote:
  > The proper fix is to either (a) document what is happening,
  > only available if no external spec says we are doing something wrong,
  > or (b) retain the global flag but capture it's value and bind it for
  > use when the C++ template is actually instantiated.
 
     The whole realm of #pragma is out of scope of the C++ standard. And 
 I don't know which other documents could be considered relyable external 
 specs...
     I can suggest examining the behaviour of other compilers (to keep 
 the behaviour consistent) or taking this question of the correct 
 behaviour to the trusted expert or community.
 
 Best Regards,
 Igor
Comment 10 Andrew Pinski 2003-08-22 02:05:10 UTC
This is a dup of the older bug 7046 which describes the problem better and does not have too 
many comments.

*** This bug has been marked as a duplicate of 7046 ***