Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm Sender: cygwin-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin AT sourceware DOT cygnus DOT com Message-ID: <050b01be664b$915527d0$e63d2509@jonpryor.raleigh.ibm.com> From: "Jonathan Pryor" To: "Cygwin Mailing List" Subject: egcs-1.1.1: bugs with template classes Date: Thu, 4 Mar 1999 09:30:05 -0500 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0508_01BE6621.96380440" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 4.72.3110.5 X-MimeOLE: Produced By Microsoft MimeOLE V4.72.3110.3 ------=_NextPart_000_0508_01BE6621.96380440 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit These are some odd bugs... Attached is a C++ source file with a number of template classes. It is compilable under egcs-2.91.60, egcs-2.91.57, mingw32 (using egcs-1.1.1) and MSVC 6.0 (don't have access to 5.0 at the moment). The bugs are only visible in the egcs and mingw32 compilers, though in the following output, where the cygwin egcs compiler would generate STATUS_ACCESS_VIOLATION output to the console, mingw32 output would pop up a dialog box titled "a.exe - Application Error. The instruction at ... referenced memory at...". Bug 1: If I read the value of a class member variable from inside an inline template class member function, the value of the variable in that function is the same as the value the variable was constructed to. For example, if we compile the attached source file with: g++ -DFIRST_BUG def2.cpp And run the output `a.exe', we get the following output: main: Creating CUser object. After successful creation, m_pUnkOuter should be a non-null value. CoClass::CoClass(): value of this: 0x245ff2c CoClass::CoClass(): value of m_pUnkOuter: 0x0 Baz::Baz(): value of this: 0x245ff28 Baz::Baz(): value of m_pUnkOuter: 0x0 CNonDelegator::CNonDelegator(): value of this: 0x245ff34 CNonDelegator::CNonDelegator(): value of m_pThis: 0x245ff28 CDelegator::CDelegator(): assigning m_pUnkOuter to &m_nd. CDelegator::CDelegator(): value of m_pUnkOuter: 0x245ff34 CUser::CUser(): value of m_pUnkOuter: 0x245ff34 main: Calling IFoo::Bar(). This will end up going through m_pUnkOuter. CDelegator::Bar(): value of m_pUnkOuter: 0x245ff34 CNonDelegator::Bar(): value of m_pThis: 0x245ff28 CUser::InternalBar() called! main: If we're here, obviously m_pUnkOuter is non-null... CoClass::GetFoo() called: m_pUnkOuter = 0x0 main: value returned by CoClass::GetFoo(): 0x0 Note that `m_pUnkOuter' is constructed to 0, and is set to 0x245f34 in the CDelegator constructor. Yet, in CoClass::GetFoo(), it's value is 0x0! If I modify the CoClass constructor so that `m_pUnkOuter' is initialized to a non-null value (such as 0xfefefefe), the value CoClass::GetFoo() returns is the same as the constructed value (0xfefefefe). The work-around is to directly access the member-variable -- which I don't like, but it works. "Outlining" the class definition (so that all the member functions definitions are not in the class declaration) does not change the behavior shown. Bug 2: If we compile the source with the command: g++ def2.cpp and execute the resulting executable, we get an access violation. main: Creating CUser object. After successful creation, m_pUnkOuter should be a non-null value. CoClass::CoClass(): value of this: 0x245ff3c CoClass::CoClass(): value of m_pUnkOuter: 0x0 Baz::Baz(): value of this: 0x245ff38 Baz::Baz(): value of m_pUnkOuter: 0x0 CNonDelegator::CNonDelegator(): value of this: 0x245ff40 CNonDelegator::CNonDelegator(): value of m_pThis: 0x245ff38 CDelegator::CDelegator(): assigning m_pUnkOuter to &m_nd. CDelegator::CDelegator(): value of m_pUnkOuter: 0x245ff40 CUser::CUser(): value of m_pUnkOuter: 0x4081c8 main: Calling IFoo::Bar(). This will end up going through m_pUnkOuter. CDelegator::Bar(): value of m_pUnkOuter: 0x4081c8 [main] C:\tmp\a.exe 1000 (0) handle_exceptions: Exception: STATUS_ACCESS_VIOLATION [main] a 1000 (0) handle_exceptions: Dumping stack trace to a.exe.core The access violation appears to occur from `m_pUnkOuter' not pointing to a valid object. However, I'm not sure *why* its pointing to an invalid object... I got this "bug" trying to minimize the source code needed to demonstrate the first bug -- and instead got access violations. What I can point out is that the value of `m_pUnkOuter' changes for some reason between the CDelegator constructor and the CUser constructor (it changes from 0x245FF40 to 0x4081c8). All I know is that *I'm* not doing this change... Bug 3: The third bug is a variation of the second -- it causes an access violation because the value of `m_pUnkOuter' changes...when I don't assign to it. The major difference between this version and the `Bug 2' version is that instead of assigning directly to `m_pUnkOuter' in the derived class, I use a base-class member function to do the assignment -- CoClass::SetFoo(). To see the bug, compile with: g++ -DSET_FOO [-DFIRST_BUG] def2.cpp The behavior described below is present whether or not `-DFIRST_BUG' was used to compile the program. Run the resulting executable `a.exe' to get: main: Creating CUser object. After successful creation, m_pUnkOuter should be a non-null value. CoClass::CoClass(): value of this: 0x245ff3c CoClass::CoClass(): value of m_pUnkOuter: 0x0 Baz::Baz(): value of this: 0x245ff38 Baz::Baz(): value of m_pUnkOuter: 0x0 CNonDelegator::CNonDelegator(): value of this: 0x245ff40 CNonDelegator::CNonDelegator(): value of m_pThis: 0x245ff38 CDelegator::CDelegator(): assigning m_pUnkOuter to &m_nd. CDelegator::CDelegator(): value of m_pUnkOuter: 0x4081a0 CUser::CUser(): value of m_pUnkOuter: 0x4081c8 main: Calling IFoo::Bar(). This will end up going through m_pUnkOuter. CDelegator::Bar(): value of m_pUnkOuter: 0x4081c8 [main] C:\tmp\a.exe 1000 (0) handle_exceptions: Exception: STATUS_ACCESS_VIOLATION [main] a 1000 (0) handle_exceptions: Dumping stack trace to a.exe.core This one is really odd. In the above 2 bugs, CDelegator assigns `m_pUnkOuter' to the address of `m_nd'. This can be verified by looking at the address of `this' in the CNonDelegator constructor. In Bug 1 and Bug 2, `m_pUnkOuter' in the CDelegator constructor is the same value as `this' in the CNonDelegator constructor -- which is correct behavior. In this version, however, note that this *isn't* the case -- `m_pUnkOuter' is set...in outer space as far as I know. Very odd. Very wrong. Again, using the same source, with the same compile defines, creates a working executable with "correct" (in my belief) behavior. I should note that MSVC does give a warning in the compile that egcs doesn't: def2.cpp(67) : warning C4355: 'this' : used in base member initializer list def2.cpp(67) : while compiling class-template member function '__thiscall CUser::CUser(struct IFoo *)' However, in my belief this should be safe in this instance, so I'm willing to ignore this particular warning. Thanks, - Jon ------=_NextPart_000_0508_01BE6621.96380440 Content-Type: application/octet-stream; name="def2.cpp" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="def2.cpp" // lots of "interesting uses of templates"... Is it a bug? #include struct IFoo { virtual void Bar () =3D 0; }; struct IDitto : public IFoo { virtual void Oops () =3D 0; }; template class CNonDelegator : public IFoo { Delegatee* m_pThis; public: CNonDelegator ( Delegatee* pThis ) : m_pThis(pThis) { printf ("CNonDelegator::CNonDelegator(): value of this: 0x%x\n", = this); printf ("CNonDelegator::CNonDelegator(): value of m_pThis: 0x%x\n",=20 m_pThis ); } void Bar () { printf ("CNonDelegator::Bar(): value of m_pThis: 0x%x\n", m_pThis ); m_pThis->InternalBar (); } }; template class CDelegator : public base { CNonDelegator m_nd; public: CDelegator ( IFoo* pOuter, Deferer* pThis ) : m_nd(pThis) { if ( pOuter ) { printf ("CDelegator::CDelegator(): assigning m_pUnkOuter to = pOuter.\n"); #ifdef SET_FOO SetFoo ( pOuter ); #else m_pUnkOuter =3D pOuter; #endif } else { printf ("CDelegator::CDelegator(): assigning m_pUnkOuter to = &m_nd.\n"); #if SET_FOO SetFoo ( &m_nd ); #else m_pUnkOuter =3D &m_nd; #endif } printf ("CDelegator::CDelegator(): value of m_pUnkOuter: 0x%x\n", m_pUnkOuter ); } void Bar () { printf ("CDelegator::Bar(): value of m_pUnkOuter: 0x%x\n", = m_pUnkOuter); m_pUnkOuter->Bar (); } }; template class CUser : public CDelegator > { typedef CDelegator > base_class; public: CUser (IFoo* pOuter ) : base_class (pOuter, this) { printf ("CUser::CUser(): value of m_pUnkOuter: 0x%x\n", m_pUnkOuter = ); } void InternalBar () { printf ("CUser::InternalBar() called!\n"); } }; #if FIRST_BUG class FakeAutoCS { public: void Lock() {} void Unlock () {} }; class DefTM { public: static unsigned long Increment ( long* pn ) { return ++(*pn); } static unsigned long Decrement ( long* pn ) { return --(*pn); } typedef FakeAutoCS CriticalSection; typedef FakeAutoCS AutoCriticalSection; }; template class CRootObject { typedef typename tm::CriticalSection CriticalSection; typedef typename tm::AutoCriticalSection AutoCriticalSection; AutoCriticalSection m_cs; public: void Lock() { m_cs.Lock(); } void Unlock() { m_cs.Unlock(); } }; #endif // FIRST_BUG template class CoClass=20 #if FIRST_BUG : public CRootObject #endif // FIRST_BUG { protected: IFoo* m_pUnkOuter; public: CoClass () : m_pUnkOuter(0) { printf ("CoClass::CoClass(): value of this: 0x%x\n", this ); printf ("CoClass::CoClass(): value of m_pUnkOuter: 0x%x\n", = m_pUnkOuter); } IFoo* GetFoo() { printf ("CoClass::GetFoo() called: m_pUnkOuter =3D = 0x%x\n",m_pUnkOuter); return m_pUnkOuter; } #if SET_FOO void SetFoo ( IFoo* pFoo ) { m_pUnkOuter =3D pFoo; } #endif // SET_FOO }; class Baz :=20 public IDitto,=20 public CoClass=20 { public: Baz () { printf ("Baz::Baz(): value of this: 0x%x\n", this ); printf ("Baz::Baz(): value of m_pUnkOuter: 0x%x\n", m_pUnkOuter ); } void Oops () { printf ("Baz::Oops().\n"); } }; int main (int, char **) { printf ("main: Creating CUser object. After successful creation, = m_pUnkOuter" " should be a non-null value.\n"); CUser b(0); IFoo* pFoo =3D &b; printf ("main: Calling IFoo::Bar(). This will end up going through " "m_pUnkOuter.\n"); pFoo->Bar (); printf ("main: If we're here, obviously m_pUnkOuter is = non-null...\n"); =20 pFoo =3D b.GetFoo (); printf ("main: value returned by CoClass::GetFoo(): 0x%x\n", pFoo ); return 0; } ------=_NextPart_000_0508_01BE6621.96380440 Content-Type: text/plain; charset= -- Want to unsubscribe from this list? Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com ------=_NextPart_000_0508_01BE6621.96380440--