{"id":410048,"date":"2024-06-29T21:08:05","date_gmt":"2024-06-29T21:08:05","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=410048"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=410048","title":{"rendered":"<span>Unicorns break into RTS: analyzing the OpenRA source code<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/dcf\/749\/5ef\/dcf7495efe14b6c2b391d21c3deff1a8.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/dcf\/749\/5ef\/dcf7495efe14b6c2b391d21c3deff1a8.png\"\/><\/div>\n<p>  This article is about the check of the OpenRA project using the static PVS-Studio analyzer. What is OpenRA? It is an open source game engine designed to create real-time strategies. The article describes the analysis process, project features, and warnings that PVS-Studio has issued. And, of course, here we will discuss some features of the analyzer that made the project checking process more comfortable.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>OpenRA<\/h2>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/5eb\/88d\/c23\/5eb88dc230b02a9f79effc3401ccc649.png\" alt=\"image2.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/5eb\/88d\/c23\/5eb88dc230b02a9f79effc3401ccc649.png\"\/><\/div>\n<p>  The project chosen for the check is a game engine for RTS in the style of games such as Command &amp; Conquer: Red Alert. More information can be found on the <a href=\"http:\/\/www.openra.net\/\">website<\/a>. The source code is written in C# and is available for viewing and using in the <a href=\"https:\/\/github.com\/OpenRA\/OpenRA\">repository<\/a>.<\/p>\n<p>  There were 3 reasons for choosing OpenRA for a review. First, it seems to be of interest to many people. In any case, this applies to the inhabitants of GitHub, since the repository has reached the rating of more than 8 thousand stars. Second, the OpenRA code base contains 1285 files. Usually this amount is quite enough to hope to find interesting warnings in them. And third\u2026 Game engines are cool.<\/p>\n<h2>Redundant warnings<\/h2>\n<p>  I analyzed OpenRA using PVS-Studio and at first was encouraged by the results:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/795\/845\/e87\/795845e8722bff7c57f1c66f5451aeb1.png\" alt=\"image3.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/795\/845\/e87\/795845e8722bff7c57f1c66f5451aeb1.png\"\/><\/div>\n<p>  I decided that among so many High level warnings, I could definitely find a whole lot of different sapid errors. Therefore, based on them, I would write the coolest and most intriguing article \ud83d\ude42 But no such luck!<\/p>\n<p>  One glance at the warnings and everything clicked into place. 1,277 of the 1,306 High level warnings were related to the <a href=\"https:\/\/www.viva64.com\/en\/w\/v3144\/\">V3144<\/a> diagnostic. It gives messages of the type &#171;This file is marked with a copyleft license, which requires you to open the derived source code&#187;. This diagnostic is described in more detail <a href=\"https:\/\/www.viva64.com\/en\/w\/v3144\/\">here<\/a>.<\/p>\n<p>  Obviously, I wasn&#8217;t interested in warnings of such kind, as OpenRA is already an open source project. Therefore, they had to be hidden so that they didn&#8217;t interfere with viewing the rest of the log. Since I used the Visual Studio plugin, it was easy to do so. I just had to right-click on one of the <a href=\"https:\/\/www.viva64.com\/en\/w\/v3144\/\">V3144<\/a> warnings and select &#171;Hide all <a href=\"https:\/\/www.viva64.com\/en\/w\/v3144\/\">V3144<\/a> errors&#187; in the opening menu.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/3f2\/0fd\/4fe\/3f20fd4fea466bc5a86b45d9e32de817.png\" alt=\"image5.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/3f2\/0fd\/4fe\/3f20fd4fea466bc5a86b45d9e32de817.png\"\/><\/div>\n<p>  You can also choose which warnings will be displayed in the log by going to the &#171;Detectable Errors (C#)&#187; section in the analyzer options.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/6e1\/690\/081\/6e1690081d5b6972783e09c78ab36a32.png\" alt=\"image7.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6e1\/690\/081\/6e1690081d5b6972783e09c78ab36a32.png\"\/><\/div>\n<p>  To go to them using the plugin for Visual Studio 2019, click on the top menu Extensions->PVS-Studio->Options.<\/p>\n<h2>Check results<\/h2>\n<p>  After the <a href=\"https:\/\/www.viva64.com\/en\/w\/v3144\/\">V3144<\/a> warnings were filtered out, there were significantly fewer warnings in the log:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/8ce\/498\/19e\/8ce49819ed39a07b3b4ebbd6b58bcacd.png\" alt=\"image8.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/8ce\/498\/19e\/8ce49819ed39a07b3b4ebbd6b58bcacd.png\"\/><\/div>\n<p>  Nevertheless, I managed to find worthy ones among them.<\/p>\n<h3>Meaningless conditions<\/h3>\n<p>  Quite a few positives pointed to unnecessary checks. This may indicate an error, because people usually don&#8217;t write this code intentionally. However, in OpenRA, it often looks as if these unnecessary conditions were added on purpose. For example:<\/p>\n<pre><code class=\"cs\">public virtual void Tick() {   ....    Active = !Disabled &amp;&amp; Instances.Any(i => !i.IsTraitPaused);   if (!Active)     return;    if (Active)   {     ....   } }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;Active&#8217; is always true. SupportPowerManager.cs 206<\/p>\n<p>  PVS-Studio quite rightly notes that the second check is meaningless, because if <i>Active<\/i> is <i>false<\/i>, it won&#8217;t execute. It might be an error, but I think it was written intentionally. What for? Well, why not?<\/p>\n<p>  Perhaps, what we have here is a temporary solution, which was supposed to be refined later. In such cases, it is quite convenient that the analyzer will remind a developer of such shortcomings.<\/p>\n<p>  Let&#8217;s look at another just-in-case check:<\/p>\n<pre><code class=\"cs\">Pair&lt;string, bool>[] MakeComponents(string text) {   ....    if (highlightStart > 0 &amp;&amp; highlightEnd > highlightStart)  \/\/ &lt;=   {     if (highlightStart > 0)                                 \/\/ &lt;=     {       \/\/ Normal line segment before highlight       var lineNormal = line.Substring(0, highlightStart);       components.Add(Pair.New(lineNormal, false));     }        \/\/ Highlight line segment     var lineHighlight = line.Substring(       highlightStart + 1,        highlightEnd - highlightStart \u2013 1     );     components.Add(Pair.New(lineHighlight, true));     line = line.Substring(highlightEnd + 1);   }   else   {     \/\/ Final normal line segment     components.Add(Pair.New(line, false));     break;   }   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;highlightStart > 0&#8217; is always true. LabelWithHighlightWidget.cs 54<\/p>\n<p>  Again, it is obvious that re-checking is completely pointless. The value of <i>highlightStart<\/i> is checked twice, right in neighbouring lines. A mistake? It is possible that in one of the conditions wrong variables are selected for checking. Anyway, it&#8217;s hard to say for sure what&#8217;s going on here. One thing is definitely clear \u2014 the code should be reviewed and corrected. Or there should be an explanation if additional check is still needed for some reason.<\/p>\n<p>  Here is another similar case:<\/p>\n<pre><code class=\"cs\">public static void ButtonPrompt(....) {   ....   var cancelButton = prompt.GetOrNull&lt;ButtonWidget>(     \"CANCEL_BUTTON\"   );   ....    if (onCancel != null &amp;&amp; cancelButton != null)   {     cancelButton.Visible = true;     cancelButton.Bounds.Y += headerHeight;     cancelButton.OnClick = () =>     {       Ui.CloseWindow();       if (onCancel != null)         onCancel();     };      if (!string.IsNullOrEmpty(cancelText) &amp;&amp; cancelButton != null)       cancelButton.GetText = () => cancelText;   }   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3063\/\">V3063<\/a> A part of conditional expression is always true if it is evaluated: cancelButton != null. ConfirmationDialogs.cs 78<\/p>\n<p>  <i>cancelButton<\/i> can be <i>null<\/i> indeed, because the value returned by the <i>GetOrNull<\/i> method is written to this variable. However, it stands to reason that by no means will <i>cancelButton<\/i> turn to <i>null<\/i> in the body of the conditional operator. Yet the check is still present. If you don&#8217;t pay attention to the external condition, you happen to be in a very strange situation. First the variable properties are accessed, and then the developer decides to make sure if there is <i>null<\/i> or not.<\/p>\n<p>  At first, I assumed that the project might be using some specific logic related to overloading the &#171;==&#187; operator. In my opinion, implementing something like this in a project for reference types is a controversial idea. Not to mention the fact that unusual behavior makes it harder for other developers to understand the code. At the same time, it is difficult for me to imagine a situation where you can&#8217;t do without such tricks. Although it is likely that in some specific case this would be a convenient solution.<\/p>\n<p>  In the Unity game engine, for example, the &#171;<i>==<\/i>&#187; operator is redefined for the <i>UnityEngine.Object<\/i> class. The official documentation available by the <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Object-operator_eq.html\">link<\/a> shows that comparing instances of this <i>class<\/i> with null doesn&#8217;t work as usual. Well, the developer probably had reasons for implementing this unusual logic.<\/p>\n<p>  I didn&#8217;t find anything like this in OpenRA :). So if there is any meaning in the <i>null<\/i> checks discussed earlier, it is something else.<\/p>\n<p>  PVS-Studio managed to find a few more similar cases, but there is no need to list them all here. Well, it&#8217;s a bit boring to watch the same triggers. Fortunately (or not), the analyzer was able to find other oddities.<\/p>\n<h3>Unreachable code<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">void IResolveOrder.ResolveOrder(Actor self, Order order) {   ....   if (!order.Queued || currentTransform == null)     return;      if (!order.Queued &amp;&amp; currentTransform.NextActivity != null)     currentTransform.NextActivity.Cancel(self);    .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;!order.Queued &amp;&amp; currentTransform.NextActivity != null&#8217; is always false. TransformsIntoTransforms.cs 44<\/p>\n<p>  Once again, we have a pointless check here. However, unlike the previous ones, this is not just an extra condition, but a real unreachable code. The <i>always true<\/i> checks above didn&#8217;t actually affect the program&#8217;s performance. You can remove them from the code, or you can leave them \u2013 nothing will change.<\/p>\n<p>  Whereas in this case, the strange check results in the fact that a part of the code isn&#8217;t executed. At the same time, it is difficult for me to guess what changes should be made here as an amendment. In the simplest and most preferable scenario, unreachable code simply shouldn&#8217;t be executed. Then there is no mistake. However, I doubt that the programmer deliberately wrote the line just for the sake of beauty.<\/p>\n<h3>Uninitialized variable in the constructor<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public class CursorSequence {   ....   public readonly ISpriteFrame[] Frames;    public CursorSequence(     FrameCache cache,      string name,      string cursorSrc,      string palette,      MiniYaml info   )   {     var d = info.ToDictionary();      Start = Exts.ParseIntegerInvariant(d[\"Start\"].Value);     Palette = palette;     Name = name;      if (       (d.ContainsKey(\"Length\") &amp;&amp; d[\"Length\"].Value == \"*\") ||        (d.ContainsKey(\"End\") &amp;&amp; d[\"End\"].Value == \"*\")     )        Length = Frames.Length - Start;     else if (d.ContainsKey(\"Length\"))       Length = Exts.ParseIntegerInvariant(d[\"Length\"].Value);     else if (d.ContainsKey(\"End\"))       Length = Exts.ParseIntegerInvariant(d[\"End\"].Value) - Start;     else       Length = 1;      Frames = cache[cursorSrc]       .Skip(Start)       .Take(Length)       .ToArray();      ....   } }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3128\/\">V3128<\/a> The &#8216;Frames&#8217; field is used before it is initialized in constructor. CursorSequence.cs 35<\/p>\n<p>  A nasty case. An attempt to get the <i>Length<\/i> property value from an uninitialized variable will inevitably result in the <i>NullReferenceException<\/i>. In a normal situation, it is unlikely that such an error would have gone unnoticed \u2013 yet the inability to create an instance of the class is easily detected. But here the exception will only be thrown if the condition<\/p>\n<pre><code class=\"cs\">(d.ContainsKey(\"Length\") &amp;&amp; d[\"Length\"].Value == \"*\") ||  (d.ContainsKey(\"End\") &amp;&amp; d[\"End\"].Value == \"*\")<\/code><\/pre>\n<p>  is true. <\/p>\n<p>  It is difficult to judge how to correct the code so that everything is fine. I can only assume that the function should look something like this:<\/p>\n<pre><code class=\"cs\">public CursorSequence(....) {   var d = info.ToDictionary();    Start = Exts.ParseIntegerInvariant(d[\"Start\"].Value);   Palette = palette;   Name = name;   ISpriteFrame[] currentCache = cache[cursorSrc];        if (     (d.ContainsKey(\"Length\") &amp;&amp; d[\"Length\"].Value == \"*\") ||      (d.ContainsKey(\"End\") &amp;&amp; d[\"End\"].Value == \"*\")   )      Length = currentCache.Length - Start;   else if (d.ContainsKey(\"Length\"))     Length = Exts.ParseIntegerInvariant(d[\"Length\"].Value);   else if (d.ContainsKey(\"End\"))     Length = Exts.ParseIntegerInvariant(d[\"End\"].Value) - Start;   else     Length = 1;    Frames = currentCache     .Skip(Start)     .Take(Length)     .ToArray();    .... }<\/code><\/pre>\n<p>  In this version, the stated problem is absent, but only the developer can tell to what extent it corresponds to the original idea.<\/p>\n<h3>Potential typo<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public void Resize(int width, int height) {   var oldMapTiles = Tiles;   var oldMapResources = Resources;   var oldMapHeight = Height;   var oldMapRamp = Ramp;   var newSize = new Size(width, height);    ....   Tiles = CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]);   Resources = CellLayer.Resize(     oldMapResources,     newSize,     oldMapResources[MPos.Zero]   );   Height = CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]);   Ramp = CellLayer.Resize(oldMapRamp, newSize, oldMapHeight[MPos.Zero]);     .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3127\/\">V3127<\/a> Two similar code fragments were found. Perhaps, this is a typo and &#8216;oldMapRamp&#8217; variable should be used instead of &#8216;oldMapHeight&#8217; Map.cs 964<\/p>\n<p>  The analyzer detected a suspicious fragment associated with passing arguments to the function. Let&#8217;s look at the calls separately:<\/p>\n<pre><code class=\"cs\">CellLayer.Resize(oldMapTiles,     newSize, oldMapTiles[MPos.Zero]); CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]); CellLayer.Resize(oldMapHeight,    newSize, oldMapHeight[MPos.Zero]); CellLayer.Resize(oldMapRamp,      newSize, oldMapHeight[MPos.Zero]);<\/code><\/pre>\n<p>  Oddly enough, the last call passes <i>oldMapHeight<\/i>, not <i>oldMapRamp<\/i>. Of course, not all such cases are erroneous. It is quite possible that everything is written correctly here. But you will probably agree that this place looks unusual. I&#8217;m inclined to believe that there is an error for sure.<\/p>\n<p>  <i>Note by a colleague <a href=\"https:\/\/www.viva64.com\/en\/b\/a\/andrey-karpov\/\">Andrey Karpov<\/a>. I don&#8217;t see anything strange in this code :). It&#8217;s a classic <a href=\"https:\/\/www.viva64.com\/en\/b\/0260\/\"> last line mistake<\/a>!<\/i><\/p>\n<p>  If there is no error, then one should add some explanation. After all, if a snippet looks like an error, then someone will want to fix it. <\/p>\n<h3>True, true and nothing but true<\/h3>\n<p>  The project revealed very peculiar methods, the return value of which is of the <i>bool<\/i> type. Their uniqueness lies in the fact that they return <i>true<\/i> under any conditions. For example:<\/p>\n<pre><code class=\"cs\">static bool State(   S server,    Connection conn,    Session.Client client,    string s ) {   var state = Session.ClientState.Invalid;   if (!Enum&lt;Session.ClientState>.TryParse(s, false, out state))   {     server.SendOrderTo(conn, \"Message\", \"Malformed state command\");     return true;   }    client.State = state;    Log.Write(     \"server\",      \"Player @{0} is {1}\",     conn.Socket.RemoteEndPoint,      client.State   );    server.SyncLobbyClients();    CheckAutoStart(server);    return true; }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3009\/\">V3009<\/a> It&#8217;s odd that this method always returns one and the same value of &#8216;true&#8217;. LobbyCommands.cs 123<\/p>\n<p>  Is everything OK in this code? Is there an error? It looks extremely strange. Why haven&#8217;t the developer used <i>void<\/i>?<\/p>\n<p>  It&#8217;s not surprising that the analyzer finds such a place strange, but we still have to admit that the programmer actually had a reason to write this way. Which one? <\/p>\n<p>  I decided to check where this method is called and whether its returned <i>always true<\/i> value is used. It turned out that there is only one reference to it in the same class \u2013 in the <i>commandHandlers<\/i> dictionary, which has the type<\/p>\n<pre><code class=\"cs\">IDictionary&lt;string, Func&lt;S, Connection, Session.Client, string, bool>><\/code><\/pre>\n<p>  During the initialization, the following values are added to it<\/p>\n<pre><code class=\"cs\">{\"state\", State}, {\"startgame\", StartGame}, {\"slot\", Slot}, {\"allow_spectators\", AllowSpectators}<\/code><\/pre>\n<p>  and others.<\/p>\n<p>  Here we have a rare (I&#8217;d like to think so) case of static typing that creates problems for us. After all, to make a dictionary in which the values are functions with different signatures\u2026 is at least challenging. <i>commandHandlers<\/i> is only used in the <i>InterpretCommand<\/i> method:<\/p>\n<pre><code class=\"cs\">public bool InterpretCommand(   S server, Connection conn, Session.Client client, string cmd ) {   if (     server == null ||      conn == null ||      client == null ||      !ValidateCommand(server, conn, client, cmd)   )  return false;    var cmdName = cmd.Split(' ').First();   var cmdValue = cmd.Split(' ').Skip(1).JoinWith(\" \");    Func&lt;S, Connection, Session.Client, string, bool> a;   if (!commandHandlers.TryGetValue(cmdName, out a))     return false;    return a(server, conn, client, cmdValue); }<\/code><\/pre>\n<p>  Apparently, the developer intended to have the universal possibility to match strings to certain operations. I think that the chosen method is not the only one, but it is not so easy to offer something more convenient\/correct in such a situation. Especially if you don&#8217;t use <i>dynamic<\/i> or something like that. If you have any ideas about this, please leave comments. I would be interested to look at various solutions to this problem:).<\/p>\n<p>  It turns out that warnings associated with <i>always true<\/i> methods in this class are most likely false. And yet\u2026 What disquiets me here is this &#187;most likely&#187; \ud83d\ude42 One has to really be careful and not miss an actual error among these positives. <\/p>\n<p>  All such warnings should be first carefully checked, and then marked as false if necessary. You can simply do it. You should leave a special comment in the place indicated by the analyzer:<\/p>\n<pre><code class=\"cs\">static bool State(....) \/\/-V3009<\/code><\/pre>\n<p>  There is another way: you can select the warnings that need to be marked as false, and click on &#171;Mark selected messages as False Alarms&#187; in the context menu.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/4f7\/a90\/64b\/4f7a9064be37561dd36d299e47885630.png\" alt=\"image10.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/4f7\/a90\/64b\/4f7a9064be37561dd36d299e47885630.png\"\/><\/div>\n<p>  You can learn more about this topic in the <a href=\"https:\/\/www.viva64.com\/en\/m\/0017\/\">documentation<\/a>.<\/p>\n<h3>Extra check for null?<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">static bool SyncLobby(....) {   if (!client.IsAdmin)   {     server.SendOrderTo(conn, \"Message\", \"Only the host can set lobby info\");     return true;   }    var lobbyInfo = Session.Deserialize(s);    if (lobbyInfo == null)                    \/\/ &lt;=   {     server.SendOrderTo(conn, \"Message\", \"Invalid Lobby Info Sent\");     return true;   }    server.LobbyInfo = lobbyInfo;    server.SyncLobbyInfo();    return true; }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;lobbyInfo == null&#8217; is always false. LobbyCommands.cs 851<\/p>\n<p>  Here we have another method that always returns <i>true<\/i>. However, this time we are looking at a different type of a warning. We have to pore over such places with all diligence, as there is no guarantee that we deal with redundant code. But first things first.<\/p>\n<p>  The <i>Deserialize<\/i> method never returns <i>null<\/i> \u2013 you can easily see this by looking at its code:<\/p>\n<pre><code class=\"cs\">public static Session Deserialize(string data) {   try   {     var session = new Session();     ....     return session;   }   catch (YamlException)   {     throw new YamlException(....);   }   catch (InvalidOperationException)   {     throw new YamlException(....);   } }<\/code><\/pre>\n<p>  For ease of reading, I have shortened the source code of the method. You can see it in full by clicking on the <a href=\"https:\/\/github.com\/OpenRA\/OpenRA\/blob\/f642cead441446e16e565ac855b49186a899c253\/OpenRA.Game\/Network\/Session.cs\">link<\/a>. Or take my word for it that the <i>session<\/i> variable doesn&#8217;t turn to <i>null<\/i> under any circumstances.<\/p>\n<p>  So what do we see at the bottom part? <i>Deserialize<\/i> doesn&#8217;t return <i>null<\/i>, and if something goes wrong, it throws exceptions. The developer who wrote the <i>null<\/i> check after the call was of a different mind, apparently. Most likely, in an exceptional situation, the <i>SyncLobby<\/i> method should execute the code that is currently being executed\u2026 Actually, it is never executed, because <i>lobbyInfo<\/i> is never <i>null<\/i>:<\/p>\n<pre><code class=\"cs\">if (lobbyInfo == null) {   server.SendOrderTo(conn, \"Message\", \"Invalid Lobby Info Sent\");   return true; }<\/code><\/pre>\n<p>  I believe that instead of this &#171;extra&#187; check, the author still needs to use <i>try<\/i>&#8212;<i>catch<\/i>. Or try another tack and write, let&#8217;s say, <i>TryDeserialize<\/i>, which in case of an exceptional situation will return <i>null<\/i>.<\/p>\n<h3>Possible NullReferenceException<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public ConnectionSwitchModLogic(....) {   ....   var logo = panel.GetOrNull&lt;RGBASpriteWidget>(\"MOD_ICON\");   if (logo != null)   {     logo.GetSprite = () =>     {       ....     };   }    if (logo != null &amp;&amp; mod.Icon == null)                    \/\/ &lt;=   {     \/\/ Hide the logo and center just the text     if (title != null)     title.Bounds.X = logo.Bounds.Left;      if (version != null)       version.Bounds.X = logo.Bounds.X;     width -= logo.Bounds.Width;   }   else   {     \/\/ Add an equal logo margin on the right of the text     width += logo.Bounds.Width;                           \/\/ &lt;=   }   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3125\/\">V3125<\/a> The &#8216;logo&#8217; object was used after it was verified against null. Check lines: 236, 222. ConnectionLogic.cs 236<\/p>\n<p>  As for this case, I&#8217;m sure as hell there is an error. We are definitely not looking at &#171;extra&#187; checks, because the <i>GetOrNull<\/i> method can indeed return a null reference. What happens if <i>logo<\/i> is <i>null<\/i>? Accessing the <i>Bounds<\/i> property will result in an exception, which was clearly not part of the developer&#8217;s plans.<\/p>\n<p>  Perhaps, the fragment needs to be rewritten in the following way:<\/p>\n<pre><code class=\"cs\">if (logo != null) {   if (mod.Icon == null)   {     \/\/ Hide the logo and center just the text     if (title != null)     title.Bounds.X = logo.Bounds.Left;      if (version != null)       version.Bounds.X = logo.Bounds.X;     width -= logo.Bounds.Width;   }   else   {     \/\/ Add an equal logo margin on the right of the text     width += logo.Bounds.Width;   } }<\/code><\/pre>\n<p>  This option is quite simple for comprehension, although the additional nesting doesn&#8217;t look too great. As a more comprehensive solution, one could use the null-conditional operator:<\/p>\n<pre><code class=\"cs\">\/\/ Add an equal logo margin on the right of the text width += logo?.Bounds.Width ?? 0; \/\/ &lt;=<\/code><\/pre>\n<p>  By the way, the first version looks more preferable to me. It is easy to read it and triggers no questions. But some developers appreciate brevity quite highly, so I also decided to cite the second version as well :).<\/p>\n<h3>Maybe, OrDefault after all?<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public MapEditorLogic(....) {   var editorViewport = widget.Get&lt;EditorViewportControllerWidget>(\"MAP_EDITOR\");    var gridButton = widget.GetOrNull&lt;ButtonWidget>(\"GRID_BUTTON\");   var terrainGeometryTrait = world.WorldActor.Trait&lt;TerrainGeometryOverlay>();    if (gridButton != null &amp;&amp; terrainGeometryTrait != null) \/\/ &lt;=   {     ....   }    var copypasteButton = widget.GetOrNull&lt;ButtonWidget>(\"COPYPASTE_BUTTON\");   if (copypasteButton != null)   {     ....   }    var copyFilterDropdown = widget.Get&lt;DropDownButtonWidget>(....);   copyFilterDropdown.OnMouseDown = _ =>   {     copyFilterDropdown.RemovePanel();     copyFilterDropdown.AttachPanel(CreateCategoriesPanel());   };    var coordinateLabel = widget.GetOrNull&lt;LabelWidget>(\"COORDINATE_LABEL\");   if (coordinateLabel != null)   {     ....   }    .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3063\/\">V3063<\/a> A part of conditional expression is always true if it is evaluated: terrainGeometryTrait != null. MapEditorLogic.cs 35<\/p>\n<p>  Let&#8217;s delve into this fragment. Note that each time the <i>GetOrNull<\/i> method of the <i>Widget<\/i> class is used, a <i>null<\/i> equality check is performed. However, if <i>Get<\/i> is used, there is no check. This is logical \u2013 the <i>Get<\/i> method doesn&#8217;t return <i>null<\/i>:<\/p>\n<pre><code class=\"cs\">public T Get&lt;T>(string id) where T : Widget {   var t = GetOrNull&lt;T>(id);   if (t == null)     throw new InvalidOperationException(....);   return t; }<\/code><\/pre>\n<p>  If the element is not found, an exception is thrown \u2013 this is reasonable behavior. At the same time, the logical option would be to check the values returned by the <i>GetOrNull<\/i> method for equality to the null reference.<\/p>\n<p>  In the code above, the value returned by the <i>Trait<\/i> method is checked for <i>null<\/i>. Actually it is inside the <i>Trait<\/i> method where <i>Get<\/i> of the <i>TraitDictionary<\/i> class is called:<\/p>\n<pre><code class=\"cs\">public T Trait&lt;T>() {   return World.TraitDict.Get&lt;T>(this); }<\/code><\/pre>\n<p>  Can it be that this <i>Get<\/i> behaves differently from the one we discussed earlier? Well, the classes are different. Let&#8217;s check it out:<\/p>\n<pre><code class=\"cs\">public T Get&lt;T>(Actor actor) {   CheckDestroyed(actor);   return InnerGet&lt;T>().Get(actor); }<\/code><\/pre>\n<p>  The <i>InnerGet<\/i> method returns an instance of <i>TraitContainer&lt;T><\/i>. The <i>Get<\/i> implementation in this class is very similar to <i>Get<\/i> of the <i>Widget<\/i> class:<\/p>\n<pre><code class=\"cs\">public T Get(Actor actor) {   var result = GetOrDefault(actor);   if (result == null)     throw new InvalidOperationException(....);   return result; }<\/code><\/pre>\n<p>  The main similarity is that <i>null<\/i> is never returned here either. If something goes wrong, an <i>InvalidOperationException<\/i> is similarly thrown. Therefore, the <i>Trait<\/i> method behaves the same way.<\/p>\n<p>  Yes, there may just be an extra check that doesn&#8217;t affect anything. Except that it looks strange, but you can&#8217;t say that this code will confuse a reader much. But if the check is needed indeed, then in some cases an exception will be thrown unexpectedly. It is sad.<\/p>\n<p>  So in this fragment it seems more appropriate to call, for example, <i>TraitOrNull<\/i>. However, there is no such method:). But there is <i>TraitOrDefault<\/i>, which is the equivalent of <i>GetOrNull<\/i> for this case.<\/p>\n<p>  There is another similar case related to the <i>Get<\/i> method:<\/p>\n<pre><code class=\"cs\">public AssetBrowserLogic(....) {   ....   frameSlider = panel.Get&lt;SliderWidget>(\"FRAME_SLIDER\");   if (frameSlider != null)   {     ....   }   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;frameSlider != null&#8217; is always true. AssetBrowserLogic.cs 128<\/p>\n<p>  The same as in the code considered earlier, there is something wrong here. Either the check is really unnecessary, or one still needs to call <i>GetOrNull<\/i> instead of <i>Get<\/i>.<\/p>\n<h3>Lost assignment<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public SpawnSelectorTooltipLogic(....) {   ....   var textWidth = ownerFont.Measure(labelText).X;   if (textWidth != cachedWidth)   {     label.Bounds.Width = textWidth;     widget.Bounds.Width = 2 * label.Bounds.X + textWidth; \/\/ &lt;=   }    widget.Bounds.Width = Math.Max(                         \/\/ &lt;=     teamWidth + 2 * labelMargin,      label.Bounds.Right + labelMargin   );   team.Bounds.Width = widget.Bounds.Width;   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3008\/\">V3008<\/a> The &#8216;widget.Bounds.Width&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 78, 75. SpawnSelectorTooltipLogic.cs 78<\/p>\n<p>  It seems that if the <i>textWidth != cachedWidth<\/i> condition is true, <i>widget.Bounds.Width<\/i> must be written to a specific value for this case. However, an assignment made below, regardless of whether this condition is true, makes the string<\/p>\n<pre><code class=\"cs\">widget.Bounds.Width = 2 * label.Bounds.X + textWidth;<\/code><\/pre>\n<p>  pointless. It is likely that the author just forgot to write <i>else<\/i> here:<\/p>\n<pre><code class=\"cs\">if (textWidth != cachedWidth) {   label.Bounds.Width = textWidth;   widget.Bounds.Width = 2 * label.Bounds.X + textWidth; } else {   widget.Bounds.Width = Math.Max(     teamWidth + 2 * labelMargin,     label.Bounds.Right + labelMargin   ); }<\/code><\/pre>\n<p>  <\/p>\n<h3>Checking the default value<\/h3>\n<p>  <\/p>\n<pre><code class=\"cs\">public void DisguiseAs(Actor target) {   ....   var tooltip = target.TraitsImplementing&lt;ITooltip>().FirstOrDefault();   AsPlayer = tooltip.Owner;   AsActor = target.Info;   AsTooltipInfo = tooltip.TooltipInfo;   .... }<\/code><\/pre>\n<p>  <b>Analyzer warning<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3146\/\">V3146<\/a> Possible null dereference of &#8216;tooltip&#8217;. The &#8216;FirstOrDefault&#8217; can return default null value. Disguise.cs 192<\/p>\n<p>  When is <i>FirstOrDefault<\/i> usually used instead of <i>First<\/i>? If the selection is empty, <i>First<\/i> throws an <i>InvalidOperationException<\/i>. <i>FirstOrDefault<\/i> doesn&#8217;t throw an exception, but returns <i>null<\/i> for the reference type. <\/p>\n<p>  The <i>ITooltip<\/i> interface implements various classes in the project. Thus, if <i>target.TraitsImplementing&lt;ITooltip>()<\/i> returns an empty selection, <i>null<\/i> is written to <i>tooltip<\/i>. Accessing the properties of this object, which is executed next, will result in a <i>NullReferenceException<\/i>.<\/p>\n<p>  In cases where the developer is sure that the selection won&#8217;t be empty, it is better to use <i>First<\/i>. If one isn&#8217;t sure, it&#8217;s worth checking the value returned by <i>FirstOrDefault.<\/i> It is rather strange that we don&#8217;t see it here. After all, the values returned by the <i>GetOrNull<\/i> method mentioned earlier were always checked. Why didn&#8217;t they do it here?<\/p>\n<p>  Who knows?.. All right, the developer will answer these questions for sure. In the end, it is the code author who will be fixing it \ud83d\ude42<\/p>\n<h2>Conclusion<\/h2>\n<p>  OpenRA somehow turned out to be a project that was nice and interesting to scan. The developers did a lot of work and didn&#8217;t forget that the source code should be easy to view. Of course, we did find some\u2026 controversies, but one can&#8217;t simply do without them \ud83d\ude42<\/p>\n<p>  At the same time, even with all the effort, alas, developers remain people. Some of the considered warnings are extremely difficult to notice without using the analyzer. It is sometimes difficult to find an error even immediately after writing it. Needless to say, how hard it is to search for error after a long time.<\/p>\n<p>  Obviously, it is much better to detect an error than its consequences. To do this, you can spend hours rechecking a huge number of new sources manually. Well, and have a bit of a look at the old ones \u2014 what if there is an oversight there? Yes, reviews are really useful, but if you have to view a large amount of code, then you stop noticing some things over time. And it takes a lot of time and effort.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/a46\/368\/3fa\/a463683fadadc18c68557b79dea8d3a9.png\" alt=\"image11.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/a46\/368\/3fa\/a463683fadadc18c68557b79dea8d3a9.png\"\/><\/div>\n<p>  Static analysis is just a convenient addition to other methods of checking the quality of source code, such as code review. PVS-Studio will find &#171;simple&#187; (and sometimes tricky) errors instead of a developer, allowing people to focus on more serious issues.<\/p>\n<p>  Yes, the analyzer sometimes gives false positives and is not able to find all the errors. But with it you will save a lot of time and nerves. Yes, it is not perfect and sometimes makes mistakes itself. However, in general, PVS-Studio makes the development process much easier, more enjoyable, and even (unexpectedly!) cheaper.<\/p>\n<p>  In fact, you don&#8217;t need to take my word for it \u2014 it&#8217;s much better to make sure that the above is true yourself. You can use the <a href=\"https:\/\/www.viva64.com\/en\/pvs-studio-download\/\">link<\/a> to download the analyzer and get a trial key. What could be simpler?<\/p>\n<p>  Well, that&#8217;s it for this time. Thanks for your attention! I wish you clean code and an empty error log!<\/p><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/514964\/\"> https:\/\/habr.com\/ru\/articles\/514964\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/dcf\/749\/5ef\/dcf7495efe14b6c2b391d21c3deff1a8.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/dcf\/749\/5ef\/dcf7495efe14b6c2b391d21c3deff1a8.png\"\/><\/div>\n<p>  This article is about the check of the OpenRA project using the static PVS-Studio analyzer. What is OpenRA? It is an open source game engine designed to create real-time strategies. The article describes the analysis process, project features, and warnings that PVS-Studio has issued. And, of course, here we will discuss some features of the analyzer that made the project checking process more comfortable.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-410048","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410048","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=410048"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410048\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=410048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=410048"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=410048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}