3

Suppose we have an hpp and cpp files with declaration and implementation of the same function with same name/parameters but different return types. The cpp omit to include the hpp. So compiler is ok and linker doesn't raise any error.

hpp declare function as follow:

std::string myFunction(int *);

cpp omit to include hpp and implement the function but with different return type:

const std::string& myFunction(int *address) {...}

Then when client code include the hpp and use the function, and the code is executed, the value of address received by the function is not the one that was sent and I get a SEGFAULT. Indeed debugging I get a different value for address parameter than what I sent.

I understand that an error was made as this code is obviously incorrect: I shall have used the same return type and to help the compiler warn me that the return type were actually different.

Still I'd like to understand what made this issue at runtime ? To me this is something related to the expected position of the arguments in the stack or something like that. But a formal explanation would be interesting for better understanding how C++ works.

Hani Gotc
  • 840
  • 11
  • 24
  • 4
    It's [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). Your code should spawn small demons. For `what made this issue at runtime?` you need to inspect generated assembly code by the compiler. You will need to specify architecture, compiler, compiler version and compiler options and provide a small MCVE, or post the generated assembly by your compiler, so others can replicate and inspect the behavior. – KamilCuk Mar 08 '19 at 08:17
  • 5
    "understanding how C++ works" - note that this is beyond the realm of C++ the language (from that point of view, your program is simply wrong, period). It therefore depends on the particular calling convention/ABI, which is platform-specific and potentially also compiler-specific. – Angew is no longer proud of SO Mar 08 '19 at 08:20

2 Answers2

3

As per the standard, your program is ill-formed. The section on "Program and linkage" deals with this issue:

6.5 Program and linkage [basic.link]
...

10. After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound. A violation of this rule on type identity does not require a diagnostic.

The last sentence of the quote states that there is no diagnostic required from the compiler for this. So even if you had included the header file correctly, the compiler might not have complained.

P.W
  • 26,289
  • 6
  • 39
  • 76
2

The second function returns a pointer, the first (assuming 64 bit environment) returns 24 bytes worth of value (along the lines of size + capacity + start pointer). When the compiler compiles client code it expects the 24 bytes and likely dereferences the start pointer. But the function you linked only returns 8 bytes (a pointer to a std::string), which would have to be dereferenced twice (once to get the std::string and then dereferencing the start pointer).

If start would be in the first 8 bytes returned, your client code would assume that's where the string data is, but it's where the std::string values lie. It would also be more or less random what the returned size and capacity are, and everything would blow up more or less quickly.

And if start would not be in the 8 first bytes returned, the compiler will try to dereference size, which is probably a small integer (possibly 0). That's essentially always a segfault.

There's really no way at all this can go right, not even in the slightest. Don't break the rules.

This is a pretty informal explanation because you didn't specify what platform/calling convention etc. you are using. The gist is always the same though - returning a reference (which is just a pointer behind the scenes) and a value are obviously incompatible. It's as if you expected a package full of food but instead got a letter to pick up your package somewhere, so you start eating the letter instead of picking up the package first - computers are that "dumb".

Max Langhof
  • 23,383
  • 5
  • 39
  • 72