1

Two libs that defines the same class A, in different ways (this is legacy-crap-code)

Prototypes for A:

in lib A:

#include <string>

struct A
{
     static void func( const std::string& value);
};

in lib B:

#include <string>

struct A
{
   void func( const std::string& value);
};

main.cpp uses A:s header from lib A (component A)

#include "liba.h"

int main()
{
    A::func( "some stuff");
    return 0;
}

main is linked with both lib A and lib B.

If lib B is "linked before" lib A (in the link-directive) we get a core, hence, lib B:s definition is picket.

This is not the behavior I expected. I thought that there would be some difference between the symbols, so the loader/runtime linker could pick the right symbol. That is, the hidden this-pointer for non-static member functions is somehow included in the symbol.

Is this really conformant behavior?

Same behavior on both:

g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)

RHEL devtool with g++ 4.8.1

Fredrik
  • 335
  • 2
  • 9
  • Like you, I would have expected the staticness of a member function to be encoded somehow in the mangled name, simply to avoid such errors. But in GCC, evidently, it isn't. – TonyK Apr 28 '14 at 10:49
  • _"Is this really conformant behavior?"_ Your program violates the One Definition Rule, so is not a valid C++ program and so yes, it is 100% conforming for your program to break in unexpected ways. – Jonathan Wakely Apr 28 '14 at 11:18

3 Answers3

3

It is not possible to overload a non-static member function with a static one or viceversa. From the standard:

ISO 14882:2003 C++ Standard 13.1/2 – Overloadable declarations

Certain function declarations cannot be overloaded:

  • Function declarations that differ only in the return type cannot be overloaded.
  • Member function declarations with the same name and the same parameter types cannot be overloaded if any of them is a static member function declaration (9.4).

More details and references might be found in question 5365714.

So you have two definitions of the same class A in the same program, which should be identical, and they are not. To signal an error when there are inconsistent definitions in separate translation units is not mandatory for the linker. The result is implementation defined The program is ill-formed (updated as per @jonathan's comment). In an illustrating example from Stroustrup in the C++ faq it is described as undefined behavior.

In the case of GCC, as you said, the definition used depends on the order of the libraries in the link command (assuming lib A and lib B are compiled on itself, and then linked with the main program). The linker uses the first definition found in the libraries passed from left to right. A discussion on the link order options for GCC is in 409470.

Community
  • 1
  • 1
joanpau
  • 568
  • 5
  • 14
  • Good answer, except that it is not "implementation-defined", it is **ill-formed, no diagnostic required**. Implementation-defined would mean the implementation is required to document what happens, but the program is broken so there is no requirement on the implementation. – Jonathan Wakely Apr 28 '14 at 11:17
  • @joanpau Thanks. I think I should have been clearer that I know that it's not conformant code, and I was asking if it was ok from the linker/loader point of view to produce this behavior (given the crap-code). I was hoping the linker/loader would be required to help in some way, or at least "do the right thing". One could argue that a core is the best result, and I a helping hand... – Fredrik Apr 28 '14 at 11:54
  • 2
    As @jonathan properly points out, the program is ill-formed (answer updated). The notion of what an implementation is supposed to do in such cases is not clear ([15805394](http://stackoverflow.com/questions/15805394) and [22180312](http://stackoverflow.com/questions/22180312)), but there are no requirements: the linker could report an error if it detected the inconsistency, or produce a program with unexpected results like in your case. – joanpau Apr 29 '14 at 10:38
1

You cannot overload functions in C++ based on the return type, so I would guess that you cannot do it on basis of static/v-non-static member functions.

You will need to fix one of the header files -- preferably by not declaring the same type twice.

To illustrate look at this;

struct A {
    int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

and compare it to this....

struct A {
    static int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

And observe two things;

  1. Nowhere when I declared the actual implementation of A::X did I specify that it was a static member function -- the compiler didn't care, but took what ever information from the definition of struct.
  2. The name mangling of the symbol, whether static or not is the same _ZN1A1XEi which encodes the name of the class the name of the method and the type of the arguments.

So in conclusion, using incorrect headers against compiled code would lead to undefined behavior....

Soren
  • 14,402
  • 4
  • 41
  • 67
  • The return types are the same. The issue is that one is static and the other is non-static. And, yes, I can think of several ways of fixing this, but I would like to now if this is expected behavior or not. – Fredrik Apr 25 '14 at 15:08
  • I added more information to the answer -- the bottom line is that you should expect undefined behavior. Im supprised that you don't get any compilation errors on defining the same struct twice, and I can only assume that some conditional compiling or having two versions of the header file means that each compilation unit actualy only have one definition -- but as you can see from my example, the symbol table does not encode any information of the static nature -- but the generate calling code would, as `*this` is not provided to static members and if it was expected you will get a core/crash – Soren Apr 25 '14 at 15:29
  • Note that there are some times when the return type of a function is included in the mangled name (mainly template functions): http://mentorembedded.github.io/cxx-abi/abi.html#mangling When trying to read that spec, I sure feel sorry for whoever has to implement it. – Michael Burr Apr 25 '14 at 15:45
  • Like I described, the two TU:s for class A is linked in two different libraries. So, we're not violating one-definition-rule, compile time at least. The symbol table is from g++, which I've also inspected, and is the implementation we're using - evidently this is expected on g++ :) . My question is if this is expected or not according to the standard (or the intention of the standard, since linkage and such is not specified in the standard, to my knowledge). – Fredrik Apr 25 '14 at 15:45
0

Since a class cannot have both a static member function and non-static member function with the same name, there's no need to include that information in the mangled name.

You will need to solve this problem by including namespaces for your classes, renaming them, or being careful not to use the libraries together.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • I assume you mean with the same signature. Evidently there is a need in copy-paste-crap-code :) – Fredrik Apr 25 '14 at 16:03