MSVC’s Code Analysis Key Events are a useful tool for quickly getting to the root-cause of your static analysis warnings. This blog post highlights how Key Events may be used with warning C26800
Use of a moved from object
to quickly narrow down the problematic code.
C26800 warning recap
Warning C26800 catches code that attempts to use an object that is in a moved-from state:
#include <iostream>
int main()
{
std::string string_owner = "this string will be moved!";
std::string new_string_owner = std::move(string_owner);
std::cout << string_owner << std::endl; // Warning C26800 Use of a moved from object: ''string_owner'' (lifetime.1).
}
Instead of this string will be moved!
, the print statement in the above example will produce an empty output line when run.
The move from string_owner
into new_string_owner
happens on the line immediately preceding its use in the print statement, so it’s instantly clear why the output is incorrect. But this is a trivial example. Real world code is rarely this straightforward.
A more complex example, sans Key Events
Consider a more convoluted example. The following code defines a function that is not only significantly longer than in the first code snippet, but is also littered with all sorts of intervening business logic (represented by // ...
).
#include <string>
void take_ownership(std::string&&) { /* ... */ }
void use_string(std::string) { /* ... */ }
void my_buggy_function(bool some_condition, bool some_other_condition)
{
std::string my_string{ "this is a string!" };
bool my_flag{ false };
// ...
if (some_condition)
{
take_ownership(std::move(my_string)); // (a)
}
// ...
if (some_other_condition) // (b)
{
my_flag = true;
// ...
my_string = "the string is reset"; // (c)
// ...
}
// ...
if (my_flag && !some_other_condition) // (d)
{
take_ownership(std::move(my_string)); // (e)
}
// ...
use_string(my_string); // Use of a moved from object: ''my_string'' (lifetime.1). (f)
}
As in the simple example, a developer tasked with solving this bug will be looking to answer the question: where is my_string
moved? A natural approach would likely be to start on line (f)
, and to scan backwards through the code. This process would look something like:
- Starting at the warning location and looking a few lines up, the
take_ownership(std::move(my_string));
on line(e)
immediately offers itself up as the culprit. To realize that this is a red-herring requires evaluating the condition on line(d)
, which requires tracing even higher up into the function’s depths, delving further into the confusing business logic. - Eventually, once satisfied that the move on line
(e)
is actually unreachable (oops!), the developer recommences the upwards traversal, eventually landing on themove
on line(a)
. But not before noticing the write tomy_string
on line(c)
. - The developer must now solve the puzzle of why this re-assignment (on line
(c)
) is not preventing the warning all the way down on line(f)
. - After spending far too long running back and forth through the code, the developer finally convinces themselves that it might be possible for the condition on line
(b)
to be false, thus skipping the reset on line(c)
. The mystery is finally solved.
There must be an easier way. Enter Key Events.
Solution made simple with Key Events
As of Visual Studio 17.5 Preview 1, Key Events have been enabled for the warning C26800. Using the Microsoft SARIF Viewer extension, this check can now precisely explain its assumptions and reasoning to the curious developer, all via inline annotations in the buggy code!
These Key Events offer precisely the troublesome code path that the developer was searching for and (eventually) arrived at via manual inspection of the function’s code. Notably, we see that the check:
- is concerned with the move on line
(a)
, helpfully noting that its guarding conditionsome_condition
could betrue
- points out that there is nothing stopping the conditions on line
(b)
and(d)
from beingfalse
The buggy control flow leading to the usage of the moved-from my_string
variable is therefore immediately made clear to the satisfied developer, and the investigation time is greatly reduced.
Summary
Prior to the addition of Key Events to MSVC’s warning C26800, complex code made it hard to debug and get to the root-cause of the warning. Now, with Key Events enabled by default for warning C26800, developers can much more easily identify and resolve instances of use-after-free warnings in their code. This feature was enabled in Visual Studio 17.5 Preview 1, so please download a recent version and try it out. You can share your thoughts and comments with us through Developer Community, Twitter (@VisualC), or via email at visualcpp@microsoft.com.
0 comments