3
#include <iostream>

using namespace std;

string test(string s)
{
    string rv = "Hey Hello";
    if(s=="")
        return rv;
    else
        cout<<"Not returning"<<endl;

}

int main()
{
    string ss = test("test");
    cout<<ss<<endl;
}

The above code should not return any value and probably print garbage, but its returning "Hey Hello" even without return statement at the end in test function. Can you tell my why its behaving like this?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Ankit Agrawal
  • 51
  • 1
  • 5
  • 6
    Since your code has [**Undefined Behaviour**](https://en.wikipedia.org/wiki/Undefined_behavior), anything could happen, including **appearing to work**. As a wild guess, the compiler might be assuming that since the `else` branch in `test` is illegal, the `if` condition must always be true, so optimises the function to always `return rv;`. – BoBTFish Jun 22 '18 at 08:45
  • 2
    Because of UB.. – Jarod42 Jun 22 '18 at 08:46
  • 7
    Isn't `"Hey Hello"` valid garbage ? ;-) – Jarod42 Jun 22 '18 at 08:47
  • 1
    Or possibly just the right state is coincidentally left in the right registers. You'd expect rv to be cleaned up and deallocated but because "Hey Hello" is a const char sequence it likely gets left in the right place. Your best bet to understand this would be to look at the assembly listing it's generating. – Rup Jun 22 '18 at 08:48
  • 1
    Typically not returning from non-void functions makes your program to generate a segmentation fault when you enable optimizations. You can't assume the compiler will always generate the same assembler when your program has undefined behavior. – Jorge Bellon Jun 22 '18 at 08:56
  • The optimizer might just do NRVO in all branches – M.M Jun 22 '18 at 09:18
  • 3
    Possible duplicate of [C and C++ functions without a return statement](https://stackoverflow.com/questions/32513793/c-and-c-functions-without-a-return-statement) – xskxzr Jun 22 '18 at 09:20

4 Answers4

6

reaching the end of a function returning non-void without any return statement is undefined behavior

you should have compiler warning for this kind of things if they are active

compiler are allowed to assume that undefined behavior is unreachable so the compiler have probably deleted the if statement and kept only the branch that doesn't lead to undefined behavior

Tyker
  • 2,971
  • 9
  • 21
1

Sincerely I'm surprised that this code is compiling! You should consider the warnings as errors. Warnings are important.

My guess is that the compiler writer thought:

whenever the coder has a branch without return statement it probably means that she knows that the branch cannot be visited (for instance a precondition on the arguments is checked before calling the function) so the branch can be removed.

This could explain why the compiler behaves in this way. But a more formal answer to your question is: "this is undefined behavior, everything could happen".

When trying to compile it with gcc the output depends on the optimization level.

jimifiki
  • 5,377
  • 2
  • 34
  • 60
0

First of all, your test function causes undefined behavior because it doesn't return so literally anything can happen.

However if I were to speculate a little bit, the code behaves like this probably because it accidentally interprets the block of memory that used to be occupied by the rv local variable as the returned value. And that object happens to hold "Hello World". So although the function didn't properly return, the memory on the stack and heap could be interpreted as if the local variable was the result.

Nonetheless, that is only a guess and according to C++ standard it's just undefined behavior which means either you know what you're doing and you never let that not-returning path execute or the code is just wrong.

navyblue
  • 776
  • 4
  • 8
0

As Tyker mentioned, this code causes undefined behaviour, meaning everything can happen.

It is most likely caused by optimizer, which assumes that each execution branch returns some value, and based on this optimizes final code. You should try with optimization turned off, but note that every compiler can generate completely different results.

Take a look at disassembly (clang 4.0, -O3) of this function (I used char* instead of std::string):

test: # @test
  mov eax, .L.str.1
  cmp rdi, rax
  je .LBB0_2 // <<-- IF .L.str.1 == "", goto .LBB0_2
  // CALL PRINTF
  push rax
  mov edi, .L.str.2
  xor eax, eax
  call printf
  add rsp, 8
  // END OF CALL PRINTF
  .LBB0_2:
  mov eax, .L.str // <<--- RETURN .L.str to the caller (optimization!)
  ret

.L.str:
  .asciz "Hey Hello"

.L.str.1:
  .zero 1

Label .LBB0_2 is reached regardless of if statement results, so it's returned in every case.

Outshined
  • 709
  • 7
  • 22