Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pass rvalue to std::move and bind rvalue refence to it generate stack-use-after-scope error in ASAN

Tags:

c++

stdmove

considering this code snippet

#include <iostream>
int foo() {
  int a;
  return a;
}
int main() {
  auto &&ret = std::move(foo());
  std::cout << ret;
}

compile with ASAN g++ -fsanitize=address -fno-omit-frame-pointer -g -std=c++17 main.cpp -o main, run ./main shows error

==57382==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00016b3cb480 at pc 0x000104a37e68 bp 0x00016b3cb450 sp 0x00016b3cb448
READ of size 4 at 0x00016b3cb480 thread T0
    #0 0x104a37e64 in main main.cpp:8
    #1 0x104a75084 in start+0x200 (dyld:arm64e+0x5084)

But if I remove reference after auto, this piece of code can compile and run without an error given by ASAN. What I don't understand is that if std::move returns a reference to the object it is given, then that object, which is a temporary created by foo() in this example, will be destroyed after std::move function call return, so whether it is bind to rvalue reference or assigned to a new value should be invalid, because that temporary is already destroyed after move operation, right? Then why ASAN doesn't give an error in second case.

---------------------update----------------

 #include <iostream>
    int foo() {
      int a = 1;
      return a;
    }
    int main() {
      auto &&ret = std::move(foo());
      std::cout << ret;
    }

if I don't compile with ASAN, this code will actually run without an error, it doesn't trigger segmentation fault or anything, and print 1 which is the same as a in foo funtion. and from the answers below I learned that the temporary is destroyed after auto &&ret = std::move(foo()); right? Is this an undefined behavior?

like image 613
codesavesworld Avatar asked Sep 18 '25 19:09

codesavesworld


1 Answers

Assigning a prvalue (such as an int) to an auto&& variable will enable lifetime extension. The temporary will exist as long as your variable exists.

Passing a prvalue to std::move() will convert the prvalue (int) to an xvalue (int&&). Lifetime extension no longer applies, and the temporary is destroyed before reaching std::cout << ret;

This is why the presence of your std::move is triggering stack-use-after-scope. The move is preventing lifetime extension.

The lesson: you likely never want to pass a prvalue (a temporary) to std::move.

like image 70
Drew Dormann Avatar answered Sep 20 '25 10:09

Drew Dormann