2

After reading the answer in Similar Question, I am still wodering why this code snippet doesn't get segment fault. The temporary object "data" shoule be release after leaving the scope. But apparently, "data" is not released. Can somebody help me? Thank you

#include <iostream>
#include <string>
#include <thread>
using namespace std;

void thfunc(string &data)
{
    for (;;)
    {
        cout << data << endl;
    }
}

int main()
{
    {
        string data = "123";
        std::thread th1(thfunc, std::ref(data));
        th1.detach();
    }

    for (;;)
    {
        cout << "main loop" << endl;
    }

    return 0;
}

Similar Question

Community
  • 1
  • 1
George
  • 35
  • 4

1 Answers1

7

The temporary object is released per the standard, leading to undefined behavior. An implementation may do anything, including keeping the object's bytes in stack memory until they are overwritten, which allows your code to (incorrectly) work.

When I disassembled the binary produced by my compiler (clang++ 9.0.1) I noticed that the stack pointer was not "regressed" when the block containing data ended, thus preventing it from being overwritten when cout << "main loop" << endl; resulted in function calls.

Furthermore, due to short string optimization, the actual ASCII "123" is stored within the std::string object itself and not in a heap-allocated buffer.

The draft standard says the following:

6.6.4.3 Automatic storage duration

Block-scope variables not explicitly declared static, thread_local, or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits.

Experimentally, if I make the string long enough to disable short string optimization, the program still silently works since the bytes in the buffer happen to remain intact in my experiment. If I enable ASAN, I get a correct heap use-after-free warning, because the bytes were freed at the end of the string's lifetime, yet were accessed through an illegal use of a pointer to the now-destructed string.

Community
  • 1
  • 1
nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • @TedLyngmo I'm reading through the spec to be 100% sure from a language-lawyer standpoint, but for this example (where the scope of `data` is made smaller with braces) it should be a no-go. – nanofarad Apr 24 '20 at 01:31
  • @TedLyngmo To the best of my knowledge, lifetime extension isn't at play here; it [only applies](https://abseil.io/tips/107) when we're dealing with assigning a reference to a temporary (e.g. a return value). Here we have a non-temporary going out of scope at a certain point. – nanofarad Apr 24 '20 at 01:36
  • 1
    @TedLyngmo Not a problem! – nanofarad Apr 24 '20 at 01:37
  • I think you covered all my questions in your updated answer. Great! – Ted Lyngmo Apr 24 '20 at 01:49