{"id":22745,"date":"2019-01-28T11:48:35","date_gmt":"2019-01-28T19:48:35","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/?p=22745"},"modified":"2019-02-18T17:47:24","modified_gmt":"2019-02-18T17:47:24","slug":"new-code-analysis-checks-in-visual-studio-2019-use-after-move-and-coroutine","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/new-code-analysis-checks-in-visual-studio-2019-use-after-move-and-coroutine\/","title":{"rendered":"New Code Analysis Checks in Visual Studio 2019: use-after-move and coroutine"},"content":{"rendered":"<p><a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Visual Studio 2019 Preview 2<\/a> is an exciting release for the C++ code analysis team. In this release, we shipped a new set of experimental rules that help you catch bugs in your codebase, namely: use-after-move and coroutine checks. This article provides an overview of the new rules and how you can enable them in your project.<\/p>\n<h2>Use-after-move check<\/h2>\n<p>C++11 introduced move semantics to help write performant code by replacing some expensive copy operations with cheaper move operations. With the new capabilities of the language, however, we have new ways to make mistakes. It\u2019s important to have the tools to help find and fix these errors.<\/p>\n<p>To understand what these errors are, let&#8217;s look at the following code example: MyType m<span class=\"token punctuation\">;<\/span> <span class=\"token function\">consume<\/span><span class=\"token punctuation\">(<\/span>std<span class=\"token operator\">::<\/span><span class=\"token function\">move<\/span><span class=\"token punctuation\">(<\/span>m<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> m<span class=\"token punctuation\">.<\/span><span class=\"token function\">method<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<pre class=\"lang:cpp decode=true \">MyType m;\r\nconsume(std::move(m));\r\nm.method();\r\n<\/pre>\n<p>Calling <code>consume<\/code> will move the internal representation of <code>m<\/code>. According to the standard, the move constructor must leave <code>m<\/code> in a valid state so it can be safely destroyed. However, we can\u2019t rely on what that state is. We shouldn\u2019t call any methods on <code>m<\/code> that have preconditions, but we can safely reassign <code>m<\/code>, since the assignment operator does not have a precondition on the left-hand side. Therefore, the code above is likely to contain latent bugs. The use after move check is intended to find exactly such code, when we are using a moved-from object in a possibly unintended way.<\/p>\n<p>There are several interesting things happening in the above example:<\/p>\n<ul>\n<li><code>std::move<\/code> does not actually move <code>m<\/code>. It\u2019s only cast to a rvalue reference. The actual move happens inside the function <code>consume<\/code>.<\/li>\n<li>The analysis is not inter-procedural, so we will flag the code above even if <code>consume<\/code> is not actually moving <code>m<\/code>. This is intentional, since we shouldn\u2019t be using rvalue references when moving is not involved \u2013 it\u2019s plain confusing. We recommend rewriting such code in a cleaner way.<\/li>\n<li>The check is path sensitive, so it will follow the flow of execution and avoid warning on code like the one below.\n<pre class=\"lang:cpp decode=true\">Y y;\r\nif (condition)\r\n  consume(std::move(y));\r\nif (!condition)\r\n  y.method();<\/pre>\n<\/li>\n<\/ul>\n<p>In our analysis, we basically track what\u2019s happening with the objects.<\/p>\n<ul>\n<li>If we reassign a moved-from object it is no longer moved from.<\/li>\n<li>Calling a clear function on a container will also cleanse the \u201cmoved-from\u201dness from the container.<\/li>\n<li>We even understand what \u201cswap\u201d does, and the code example below works as intended:\n<pre class=\"lang:cpp decode=true\">Y y1, y2;\r\nconsume(std::move(y1));\r\nstd::swap(y1, y2);\r\ny1.method();\u202f\u202f \/\/ No warning, this is a valid object due to the swap above.\r\ny2.method();\u202f\u202f \/\/ Warning, y2 is moved-from.<\/pre>\n<\/li>\n<\/ul>\n<h2>Coroutine related checks<\/h2>\n<p><a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2018\/n4736.pdf\">Coroutines<\/a> are not standardized yet but they are well on track to become standard. They are the generalizations of procedures and provide us with a useful tool to deal with some concurrency related problems.<\/p>\n<p>In C++, we need to think about the lifetimes of our objects. While this can be a challenging problem on its own, in concurrent programs, it becomes even harder.<\/p>\n<p>The code example below is error prone. Can you spot the problem?<\/p>\n<pre class=\"lang:cpp decode=true\">std::future async_coro(int &amp;counter)\r\n{\r\n  Data d = co_await get_data();\r\n  ++counter;\r\n}\r\n<\/pre>\n<p>This code is safe on its own, but it\u2019s extremely easy to misuse. Let\u2019s look at a potential caller of this function:<\/p>\n<pre class=\"lang:cpp decode=true\">int c;\r\nasync_coro(c);\r\n<\/pre>\n<p>The source of the problem is that <code>async_coro<\/code> is suspended when <code>get_data<\/code> is called. While it is suspended, the flow of control will return to the caller and the lifetime of the variable <code>c<\/code> will end. By the time <code>async_coro<\/code> is resumed the argument reference will point to dangling memory.<\/p>\n<p>To solve this problem, we should either take the argument by value or allocate the integer on the heap and use a shared pointer so its lifetime will not end too early.<\/p>\n<p>A slightly modified version of the code is safe, and we will not warn:<\/p>\n<pre class=\"lang:cpp decode=true\">std::future async_coro(int &amp;counter)\r\n{\r\n  ++counter;\r\n  Data d = co_await get_data();\r\n}\r\n<\/pre>\n<p>Here, we\u2019ll only use the <code>counter<\/code> before suspending the coroutine. Therefore, there are no lifetime issues in this code. While we don\u2019t warn for the above snippet, we recommend against writing clever code utilizing this behavior since it\u2019s more prone to errors as the code evolves. One might introduce a new use of the argument after the coroutine was suspended.<\/p>\n<p>Let\u2019s look at a more involved example:<\/p>\n<pre class=\"lang:cpp decode=true\">int x = 5;\r\nauto bad = [x]() -&gt; std::future {\r\n  co_await coroutine();\r\n  printf(\"%d\\n\", x);\r\n};\r\nbad();\r\n<\/pre>\n<p>In the code above, we capture a variable by value. However, the closure object which contains the captured variable is allocated on the stack. When we call the lambda <code>bad<\/code>, it will eventually be suspended. At that time, the control flow will return to the caller and the lifetime of captured <code>x<\/code> will end. By the time the body of the lambda is resumed, the closure object is already gone. Usually, it\u2019s error prone to use captures and coroutines together. We will warn for such usages.<\/p>\n<p>Since coroutines are not part of the standard yet, the semantics of these examples might change in the future. However, the currently implemented version in both Clang and MSVC follows the model described above.<\/p>\n<p>Finally, consider the following code:<\/p>\n<pre class=\"lang:cpp decode=true\">generator mutex_acquiring_generator(std::mutex&amp; m) {\r\n  std::lock_guard grab(m);\r\n  co_yield 1;\r\n}\r\n<\/pre>\n<p>In this snippet, we yield a value while holding a lock. Yielding a value will suspend the coroutine. We can\u2019t be sure how long the coroutine will remain suspended. There\u2019s a chance we will hold the lock for a very long time. To have good performance and avoid deadlocks, we want to keep our critical sections short. We will warn for the code above to help with potential concurrency related problems.<\/p>\n<h2>Enabling the new checks in the IDE<\/h2>\n<p>Now that we have talked about the new checks, it\u2019s time to see them in action. The section below describes the step-by-step instructions for how to enable the new checks in your project for Preview 2 builds.<\/p>\n<p>To enable these checks, we go through two basic steps. First, we select the appropriate ruleset and second, we run code analysis on our file\/project.<\/p>\n<h3>Use after free<\/h3>\n<ol>\n<li>Select: Project &gt; Properties &gt; Code Analysis &gt; General &gt; C++ Core Check Experimental Rules.\n<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ExperimentalRuleset1.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22755\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ExperimentalRuleset1.png\" alt=\"Screenshot of the Code Analysis properties page that shows the C++ Core Check Experimental Rules ruleset selected.\" width=\"1614\" height=\"889\" \/><\/a><\/li>\n<li>Run code analysis on the source code by right clicking on File &gt; Analyze &gt; Run code analysis on file.<\/li>\n<li>Observe warning C26800 in the code snippet below:\n<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/UseOfMovedObject1.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22765\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/UseOfMovedObject1.png\" alt=\"Screenshot showing &quot;use of a moved from object&quot; warning\" width=\"1426\" height=\"857\" \/><\/a><\/li>\n<\/ol>\n<h3>Coroutine related checks<\/h3>\n<ol>\n<li>Select: Project &gt; Properties &gt; Code Analysis &gt; General &gt; Concurrency Rules.<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ConcurrencyRules1.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22775\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ConcurrencyRules1.png\" alt=\"Screenshot of the Code Analysis properties page that shows the Concurrency Rules ruleset selected.\" width=\"1641\" height=\"957\" \/><\/a><\/li>\n<li>Run code analysis on the source code by right clicking on File &gt; Analyze &gt; Run code analysis on file.<\/li>\n<li>Observe warning C26810 in the code snippet below:<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/LifetimeWarning11.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22785\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/LifetimeWarning11.png\" alt=\"Screenshot showing a warning that the lifetime of a captured variable might end before a coroutine is resumed.\" width=\"1752\" height=\"765\" \/><\/a><\/li>\n<li>Observe warning C26811 in the code snippet below:<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/LifetimeWarning21.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22795\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/LifetimeWarning21.png\" alt=\"Screenshot showing a warning that the lifetime of a variable might end before the coroutine is resumed.\" width=\"1792\" height=\"840\" \/><\/a><\/li>\n<li>Observe warning C26138 in the code snippet below:<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/SuspendingCoroutine1.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22805\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/SuspendingCoroutine1.png\" alt=\"Screenshot shows a warning that we are suspending a coroutine while holding a lock.\" width=\"1621\" height=\"810\" \/><\/a><\/li>\n<\/ol>\n<h2>Wrap Up<\/h2>\n<p>We\u2019d love to hear from you about your experience of using these new checks in your codebase, and also for you to tell us what sorts of checks you\u2019d like to see from us in the future releases of VS. If you have suggestions or problems with these checks \u2014 or any Visual Studio feature \u2014 either <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/ide\/how-to-report-a-problem-with-visual-studio-2017\">Report a Problem<\/a> or post on <a href=\"https:\/\/developercommunity.visualstudio.com\/spaces\/62\/index.html\">Developer Community<\/a> and let us know. We&#8217;re also on Twitter at <a href=\"https:\/\/twitter.com\/visualc\">@VisualC<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Visual Studio 2019 Preview 2 is an exciting release for the C++ code analysis team. In this release, we shipped a new set of experimental rules that help you catch bugs in your codebase, namely: use-after-move and coroutine checks. This article provides an overview of the new rules and how you can enable them in [&hellip;]<\/p>\n","protected":false},"author":324,"featured_media":22804,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[270,256],"tags":[119],"class_list":["post-22745","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcement","category-experimental","tag-code-analysis"],"acf":[],"blog_post_summary":"<p>Visual Studio 2019 Preview 2 is an exciting release for the C++ code analysis team. In this release, we shipped a new set of experimental rules that help you catch bugs in your codebase, namely: use-after-move and coroutine checks. This article provides an overview of the new rules and how you can enable them in [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/22745","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/324"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=22745"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/22745\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/22804"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=22745"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=22745"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=22745"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}