Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is string_view really promoting use-after-free errors?

According to an article (here and there) this code is an erroneous use-after free example:

#include <iostream>
#include <string>
#include <string_view>

int main() {
  std::string s = "Hellooooooooooooooo ";
  std::string_view sv = s + "World\n";
  std::cout << sv;
}

In the article it is stated that the string s will be freed when the string_view is used! This goes against my debugging experience. But I'm asking you to confirm/verify/check this.

In my experience, stack/scope variables are freed (calling the destructor would be a far more correct wording) at the exit of the scope. This means that in this case, this would happen AFTER the std::cout << sv;

However I have never used string_view, so I don't know about any internal mechanics of this object.

If indeed it is a dangerous behaviour, could you explain it? Otherwise, I'd be glad to read the confirmation that scope variables destructors are called only at the exit of the current scope, naturally, or when an exception is thrown, interrupting the thread in the current scope.


EDIT: After the first two answers, it is really a use-after-free usage.

Subsidiary question: Do you think we could add a move constructor with the delete keyword in the definition of string_view so as to forbid that?

like image 285
Stephane Rolland Avatar asked Apr 22 '19 07:04

Stephane Rolland


2 Answers

The problem with this code...

std::string_view sv = s + "World\n";

... is that sv is not set to s but to a nameless temporary created by the expression s + "world\n". That temporary is destroyed immediately after the whole expression ends (at the semicolon).

So yes, this is a "use after free" type error.

If you want to extend the life of that temporary you have to assign it to a variable that will maintain it - like a new std::string object:

std::string sv = s + "World\n"; // copy the temporary to new storage in sv

A std::string_view is merely a "view" onto a string, it is not a string in itself. It is only valid as long as the string it "looks" at is valid.

There is another quirk here too. You can also bind the temporary to a const reference which extends the life of temporaries:

std::string const& sv = s + "World\n"; // just keep the temporary living

Why is initializing a std::string_view from a temporary allowed?

I can not speak for the standards committee, but my suspicion would be that std::string_view is expected to be used as a function parameter so that temporaries can be passed into a function (like with a const ref). Obviously the lifetime is fine for that scenario.

If we forbade initialization from temporaries then a major use of std::string_view would be negated. You would be forced to create a new std::string (or binding to a const ref) before calling a function making the process awkward.

like image 146
Galik Avatar answered Nov 15 '22 14:11

Galik


The expression s + “World\n” results in a temporary object. The lifetime of this temporary std::string is just long enough to initialise sv. The memory that sv refers to is freed immediately after it is initialised (when the temporary object is destroyed).

like image 31
Indiana Kernick Avatar answered Nov 15 '22 14:11

Indiana Kernick