Thread overview
Wrong method called.
Jan 15, 2006
Dave
Mar 04, 2006
Walter Bright
Mar 04, 2006
alan
Mar 04, 2006
Brad Roberts
Mar 05, 2006
Dave
January 15, 2006
I saw this elsewhere, but can't find the original and don't know if it was ever reported in digitalmars.D.bugs or not.

Summary: Changing the order of class methods in an import file can result in the wrong method called when the executable is built with the corresponding object file. This happens on both Linux and Windows. On windows, the equivalent C++ code doesn't exhibit the same bug with DMC.

Build and run the following with:

\> dmd main.d c.d -ofmain
\> dmd main.d c.obj -version=_OBJ_ -ofmain_obj

\> main
method1()
method2()

\> main_obj
method2()
method1()

main.d:
-------
import c;

void main()
{
C c = new C;
c.method1();
c.method2();
}

c.d:
----
class C
{
version(_OBJ_)
{
void method2() { printf("method2()\n"); }
void method1() { printf("method1()\n"); }
}
else
{
void method1() { printf("method1()\n"); }
void method2() { printf("method2()\n"); }
}
}

C++ code:

\> dmc main.cpp c.cpp -omain_cpp
\> dmc main.cpp c.obj -D_OBJ_ -omain_cpp_obj

main.cpp:
---------
#include "c.h"

int main()
{
C *c = new C();
c->method1();
c->method2();

return 0;
}

c.cpp:
------
#include "c.h"
#include <stdio.h>

void C::method1() { printf("method1()\n"); }
void C::method2() { printf("method2()\n"); }

c.h:
----
class C
{
public:
#ifdef _OBJ_
virtual void method2();
virtual void method1();
#else
virtual void method1();
virtual void method2();
#endif
};


March 04, 2006
"Dave" <Dave_member@pathlink.com> wrote in message news:dqef6s$2ovu$1@digitaldaemon.com...
>I saw this elsewhere, but can't find the original and don't know if it was ever
> reported in digitalmars.D.bugs or not.
>
> Summary: Changing the order of class methods in an import file can result
> in the
> wrong method called when the executable is built with the corresponding
> object
> file.

It's not a bug. The order in the import file *must* match the order in the import's compiled object file. In the example presented, the order in the import file is changed (via a command line switch) to be different from what it was in the object file.


March 04, 2006
In article <ducnmk$rv$4@digitaldaemon.com>, Walter Bright says...
>
>It's not a bug. The order in the import file *must* match the order in the import's compiled object file. In the example presented, the order in the import file is changed (via a command line switch) to be different from what it was in the object file.
>
>

dmd b.d a.d -c

dmd main.d a.obj b.obj
Error: AssertError Failure a.d(5)

dmd main.d b.obj a.obj
Error: AssertError Failure a.d(5)

============================================

dmd a.d b.d -c

dmd main.d a.obj b.obj
Bar.bar()

dmd main.d b.obj a.obj
Bar.bar()

============================================

dmd main.d a.d b.d
Bar.bar()

dmd main.d b.d a.d
Bar.bar()


OK, it's not a bug, it's a feature! I believe we now know why compiling object modules seperately causes problems. Walter, I think you have a big problem here.


March 04, 2006
On Sat, 4 Mar 2006, alan wrote:

> In article <ducnmk$rv$4@digitaldaemon.com>, Walter Bright says...
> >
> >It's not a bug. The order in the import file *must* match the order in the import's compiled object file. In the example presented, the order in the import file is changed (via a command line switch) to be different from what it was in the object file.
> >
> >
> 
> dmd b.d a.d -c
> 
> dmd main.d a.obj b.obj
> Error: AssertError Failure a.d(5)
> 
> dmd main.d b.obj a.obj
> Error: AssertError Failure a.d(5)
> 
> ============================================
> 
> dmd a.d b.d -c
> 
> dmd main.d a.obj b.obj
> Bar.bar()
> 
> dmd main.d b.obj a.obj
> Bar.bar()
> 
> ============================================
> 
> dmd main.d a.d b.d
> Bar.bar()
> 
> dmd main.d b.d a.d
> Bar.bar()
> 
> 
> OK, it's not a bug, it's a feature! I believe we now know why compiling object modules seperately causes problems. Walter, I think you have a big problem here.

Careful.. don't confuse the original topic here with a different topic. The start of this is changing a module such that it doesn't match the .obj/.o being linked in.  Your example is order of linking.  If you lie to the compiler about the contents of the compiled code by changing the header, you're out of luck in general.

Later,
Brad
March 05, 2006
In article <Pine.LNX.4.64.0603041438430.30259@bellevue.puremagic.com>, Brad Roberts says...
>
>On Sat, 4 Mar 2006, alan wrote:
>
>> In article <ducnmk$rv$4@digitaldaemon.com>, Walter Bright says...
>> >
>> >It's not a bug. The order in the import file *must* match the order in the import's compiled object file. In the example presented, the order in the import file is changed (via a command line switch) to be different from what it was in the object file.
>> >
>> >
>> 
>> dmd b.d a.d -c
>> 
>> dmd main.d a.obj b.obj
>> Error: AssertError Failure a.d(5)
>> 
>> dmd main.d b.obj a.obj
>> Error: AssertError Failure a.d(5)
>> 
>> ============================================
>> 
>> dmd a.d b.d -c
>> 
>> dmd main.d a.obj b.obj
>> Bar.bar()
>> 
>> dmd main.d b.obj a.obj
>> Bar.bar()
>> 
>> ============================================
>> 
>> dmd main.d a.d b.d
>> Bar.bar()
>> 
>> dmd main.d b.d a.d
>> Bar.bar()
>> 
>> 
>> OK, it's not a bug, it's a feature! I believe we now know why compiling object modules seperately causes problems. Walter, I think you have a big problem here.
>
>Careful.. don't confuse the original topic here with a different topic. The start of this is changing a module such that it doesn't match the .obj/.o being linked in.  Your example is order of linking.  If you lie to the compiler about the contents of the compiled code by changing the header, you're out of luck in general.
>

The OP was demonstrating a problem that can manifest itself in many ways with versioning, making bugs caused by this hard to find and fix (because the program might not crash). For example:

module a;
import b, std.stdio;
void main()
{
B b = new B;
writefln(b.foo(10));
}

module b;
class B
{
version(bar)
int bar(int x) { return x + x; }
int foo(int x) { return x * x; }
}

# dmd -c -version=bar b.d ; dmd -quiet a.d b.o ; a
20

Like the OP, DMC and also VC++ will call the correct function with equivalent code.

I'm sure this will become a problem with library users not building their apps. with the same compiler conditionals that were used to build the library. So if it is something that wouldn't greatly complicate D compilers (or drastically effect performance in calling virtual methods) then it would be a nice to have change.

- Dave