11

Consider the following code:

#include <iostream>
#include <functional>

std::function<void ()> f()
{
    int x = 666;
    return [&] { std::cout << x << std::endl; };
}

int main()
{
    f()();
    return 0;
}

Compiling with GCC 7.5.0 on Ubuntu 18.04 bionic (WSL):

No optimization

$ g++ -o main -std=c++14 -Wall main.cpp
$ ./main
666

-O1

$ g++ -o main -O1 -std=c++14 -Wall main.cpp
$ ./main
0

-O2

$ g++ -o main -O2 -std=c++14 -Wall main.cpp
main.cpp: In function ‘int main()’:
main.cpp:7:31: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
     return [&] { std::cout << x << std::endl; };
                               ^
$ ./main
32699

-O3

$ g++ -o main -O3 -std=c++14 -Wall main.cpp
main.cpp: In function ‘int main()’:
main.cpp:7:31: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
     return [&] { std::cout << x << std::endl; };
                               ^
$ ./main
32528

Compiling with TDM-GCC 9.2.0 on Windows 10 x64:

No optimization

>g++ -o main.exe -std=c++14 -Wall main.cpp

>.\main.exe
666

-O1

>g++ -o main.exe -O1 -std=c++14 -Wall main.cpp

>.\main.exe
0

-O2

>g++ -o main.exe -O2 -std=c++14 -Wall main.cpp

>.\main.exe
0

-O3

>g++ -o main.exe -O3 -std=c++14 -Wall main.cpp

>.\main.exe
0

Compiling with MSVC 19.27.29111 on Windows 10 x64:

No optimization

>cl /EHsc main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
Microsoft (R) Incremental Linker Version 14.27.29111.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj

>.\main.exe
8402693

/O1

>cl /EHsc /O1 main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
Microsoft (R) Incremental Linker Version 14.27.29111.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj

>.\main.exe
666

/O2

>cl /EHsc /O2 main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
Microsoft (R) Incremental Linker Version 14.27.29111.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj

>.\main.exe
666

As you can see, with different compilers and optimization levels, the program outputs 666, 0, or a garbage value. Why does the above happen?

  • 7
    It seems you put a lot of effort into this. Sadly, this is simply [undefined behaviour](https://stackoverflow.com/questions/56979248/why-does-this-simple-program-result-in-puppies-puppies-puppies-to-the-console) meaning that anything and everything can happen. – Quimby Sep 26 '20 at 18:58
  • 1
    6 upvotes for a zero-research post about UB. Something is not right with this site. – super Sep 26 '20 at 19:50
  • Does this answer your question? [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – JaMiT Sep 26 '20 at 22:45

1 Answers1

12

You capture x by reference in the lambda and after leaving f() it becomes a dangling reference as x gets destroyed. You have a classic UB. To avoid it you can capture x by value by writing [x] or [=] instead of [&].

ALX23z
  • 4,456
  • 1
  • 11
  • 18