{"id":390142,"date":"2024-06-29T09:03:15","date_gmt":"2024-06-29T09:03:15","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=390142"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=390142","title":{"rendered":"<span>Top-10 Bugs Found in C# Projects in 2020<\/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\/90d\/cb8\/652\/90dcb8652d76ec2ac1788a32d1a056da.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/90d\/cb8\/652\/90dcb8652d76ec2ac1788a32d1a056da.png\"\/><\/div>\n<p>  This tough year, 2020, will soon be over at last, which means it&#8217;s time to look back at our accomplishments! Over the year, the PVS-Studio team has written quite a number of articles covering a large variety of bugs found in open-source projects with the help of PVS-Studio. This 2020 Top-10 list of bugs in C# projects presents the most interesting specimens. Enjoy the reading!<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>How the list was formed<\/h2>\n<p>  This list is composed of what I find the most interesting warnings collected across the articles my teammates and I have written over 2020. The main factor in deciding whether to include a warning or leave it out was the degree of certainty that the warning pointed at an actual issue. Of course, I also took the &#171;appeal&#187; of warnings into account when choosing and ranking them, but this quality is too subjective, so feel free to share your own opinion in the comments.<\/p>\n<p>  I&#8217;ve tried to make this list as varied as possible, in respect to both warnings and projects. The list spans eight projects, and almost every diagnostic rule is included only once \u2013 except <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> and <a href=\"https:\/\/www.viva64.com\/en\/w\/v3106\/\">V3106<\/a>, which are mentioned twice (no, these were not written by me, but they seem to be my favorites). I&#8217;m sure everyone will find something to their taste :).<\/p>\n<h2>Here we go! Top-10!<\/h2>\n<p>  <\/p>\n<h3>10 \u2013 Old new license<\/h3>\n<p>  Our Top-10 list starts with a warning from an <a href=\"https:\/\/www.viva64.com\/en\/b\/0740\/\">article<\/a> by one very nice person, which deals with static analysis of C# projects on Linux and macOS. The RavenDB project is used as an example:<\/p>\n<pre><code class=\"cs\">private static void UpdateEnvironmentVariableLicenseString(....) {   ....   if (ValidateLicense(newLicense, rsaParameters, oldLicense) == false)     return;   .... }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3066\/\">V3066<\/a> Possible incorrect order of arguments passed to &#8216;ValidateLicense&#8217; method: &#8216;newLicense&#8217; and &#8216;oldLicense&#8217;. LicenseHelper.cs(177) Raven.Server<\/p>\n<p>  Why, what&#8217;s wrong here? The code compiles perfectly. Then why does the analyzer insist that we should first pass <i>oldLicense<\/i> and only then <i>newLicense<\/i>? You&#8217;ve guessed it already, haven&#8217;t you? Let&#8217;s take a look at the declaration of <i>ValidateLicense<\/i>:<\/p>\n<pre><code class=\"cs\">private static bool ValidateLicense(License oldLicense,                                      RSAParameters rsaParameters,                                      License newLicense)<\/code><\/pre>\n<p>  Wow, indeed: the old license comes earlier than the new one in the parameter list. Now, can that dynamic analysis of yours catch things like that? \ud83d\ude42 <\/p>\n<p>  Anyway, this is an interesting case. Maybe the order doesn&#8217;t actually matter here, but spots like that should be double checked, don&#8217;t you think?<\/p>\n<h3>9 \u2013 &#8216;FirstOrDefault&#8217; and unexpected &#8216;null&#8217;<\/h3>\n<p>  The 9th place goes to a warning from the article &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0704\/\">Play &#171;osu!&#187;, but Watch Out for Bugs<\/a>&#187; written in the beginning of the year:<\/p>\n<pre><code class=\"cs\">public ScoreInfo CreateScoreInfo(RulesetStore rulesets) {   var ruleset = rulesets.GetRuleset(OnlineRulesetID);    var mods = Mods != null ? ruleset.CreateInstance()                                     .GetAllMods().Where(....)                                    .ToArray() : Array.Empty&lt;Mod>();   .... }<\/code><\/pre>\n<p>  Do you see the bug? You don&#8217;t? But it&#8217;s there! Let&#8217;s see what the analyzer says.<\/p>\n<p>  <b>PVS-Studio&#8217;s diagnostic message:<\/b> <a href=\"https:\/\/www.viva64.com\/en\/w\/v3146\/\">V3146<\/a> [CWE-476] Possible null dereference of &#8216;ruleset&#8217;. The &#8216;FirstOrDefault&#8217; can return default null value. APILegacyScoreInfo.cs 24<\/p>\n<p>  I didn&#8217;t tell you everything at once. Actually, there&#8217;s nothing suspicious about this code \u2013 but only because the <i>FirstOrDefault<\/i> method, which is mentioned in the warning, is located in the <i>GetRuleset<\/i> method&#8217;s declaration:<\/p>\n<pre><code class=\"cs\">public RulesetInfo GetRuleset(int id) =>    AvailableRulesets.FirstOrDefault(....);<\/code><\/pre>\n<p>  Oh my! The method returns <i>RulesetInfo<\/i> if a valid ruleset is found. But what if there&#8217;s no such ruleset? No problem \u2013 here&#8217;s your <i>null<\/i>. This <i>null <\/i>will crash elsewhere, when the program attempts to use the returned value. In this particular case, it&#8217;s the call <i>ruleset.CreateInstance()<\/i>.<\/p>\n<p>  You may wonder, what if that call simply cannot return <i>null<\/i>? What if the sought element is always present in the collection? Well, if the developer is so sure about this, why didn&#8217;t they use <i>First<\/i> rather than <i>FirstOrDefault<\/i>?<\/p>\n<h3>8 \u2013 Python trail<\/h3>\n<p>  The top warning of the lowest three comes from the project RunUO. The <a href=\"https:\/\/www.viva64.com\/en\/b\/0711\/\">article<\/a> was written in February.<\/p>\n<p>  The reported snippet is highly suspicious, though I can&#8217;t tell for sure if it&#8217;s a bug:<\/p>\n<pre><code class=\"cs\">public override void OnCast() {   if ( Core.AOS )   {     damage = m.Hits \/ 2;      if ( !m.Player )       damage = Math.Max( Math.Min( damage, 100 ), 15 );       damage += Utility.RandomMinMax( 0, 15 );   }   else { .... } }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3043\/\">V3043<\/a> The code&#8217;s operational logic does not correspond with its formatting. The statement is indented to the right, but it is always executed. It is possible that curly brackets are missing. Earthquake.cs 57<\/p>\n<p>  Yes \u2013 the indents! It looks as if the line <i>damage += Utility.RandomMinMax( 0, 15 )<\/i> was meant to be executed only when <i>m.Player<\/i> is <i>false<\/i>. That&#8217;s how this code would work if written in Python, where indents not only make the code look neater but also determine its logic. But the C# compiler has a different opinion! And I wonder what the developer has to say about this.<\/p>\n<p>  Actually, there are only two possible scenarios. Either the braces are indeed missing here and the code&#8217;s logic has gone all awry, or this code is fine but you can be sure someone will eventually come and &#171;fix&#187; this spot, mistaking it for a bug.<\/p>\n<p>  I may be wrong, and maybe there are cases when patterns like that are legit. If you know anything about this, please let me know in the comments \u2013 I&#8217;m really eager to figure this out.<\/p>\n<h3>7 \u2013 Perfect, or Perfect, that is the question!<\/h3>\n<p>  Ranking warnings is getting harder. Meanwhile, here&#8217;s another warning from the <a href=\"https:\/\/www.viva64.com\/en\/b\/0704\/\">article on osu!<\/a>.<\/p>\n<p>  How long will it take you to spot the bug?<\/p>\n<pre><code class=\"cs\">protected override void CheckForResult(....) {   ....   ApplyResult(r =>   {     if (   holdNote.hasBroken         &amp;&amp; (result == HitResult.Perfect || result == HitResult.Perfect))       result = HitResult.Good;     ....   }); }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3001\/\">V3001<\/a> There are identical sub-expressions &#8216;result == HitResult.Perfect&#8217; to the left and to the right of the &#8216;||&#8217; operator. DrawableHoldNote.cs 266<\/p>\n<p>  Not long, I suppose, because you just need to read the warning. That&#8217;s what developers who are friends with static analysis usually do :). You could argue about the previous cases, but this one is definitely a bug. I&#8217;m not sure which of the elements of <i>HitResult<\/i> exactly should be used instead of the second <i>Perfect<\/i> (or the first, for that matter), but the current logic is obviously wrong. Well, that&#8217;s not a problem: now that the bug is found, it can be fixed easily.<\/p>\n<h3>6 \u2013 null shall (not) pass!<\/h3>\n<p>  The 6-th place is awarded to a very cool warning found in Open XML SDK. The check of this project is covered <a href=\"https:\/\/www.viva64.com\/en\/b\/0777\/\">here<\/a>.<\/p>\n<p>  The developer wanted to make sure that a property wouldn&#8217;t be able to return <i>null<\/i> even if assigned it explicitly. This is a great feature indeed, which helps guarantee that you won&#8217;t get <i>null<\/i> no matter what. The bad news is, it&#8217;s broken here:<\/p>\n<pre><code class=\"cs\">internal string RawOuterXml {   get => _rawOuterXml;    set   {     if (string.IsNullOrEmpty(value))     {       _rawOuterXml = string.Empty;     }      _rawOuterXml = value;   } }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3008\/\">V3008<\/a> The &#8216;_rawOuterXml&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 164, 161. OpenXmlElement.cs 164<\/p>\n<p>  As you can see, <i>_rawOuterXml<\/i> will be assigned <i>value<\/i> anyway, <i>null<\/i> or not. A brief glance at this snippet may mislead you into thinking that the property will never get <i>null<\/i> \u2013 the check won&#8217;t let it! Well, if you do think so, you risk discovering a <i>NullReferenceException<\/i> instead of presents under the Christmas tree \ud83d\ude41<\/p>\n<h3>5 \u2013 An ambush in an array with a nested array<\/h3>\n<p>  The 5th specimen on this list comes from the project TensorFlow.NET, which I <a href=\"https:\/\/www.viva64.com\/en\/b\/0725\/\">checked personally<\/a> (and it&#8217;s a very strange one, I should tell you). <\/p>\n<p>  By the way, you can follow <a href=\"https:\/\/twitter.com\/Nikita30005701\">me on Twitter<\/a> if you like learning about interesting bugs in real C# projects. I&#8217;ll be sharing examples of unusual warnings and code snippets, many of which, unfortunately, won&#8217;t be included in the articles. See you on Twitter! \ud83d\ude42<\/p>\n<p>  Okay, let&#8217;s get back to the warning:<\/p>\n<pre><code class=\"cs\">public TensorShape(int[][] dims) {   if(dims.Length == 1)   {     switch (dims[0].Length)     {       case 0: shape = new Shape(new int[0]); break;       case 1: shape = Shape.Vector((int)dims[0][0]); break;       case 2: shape = Shape.Matrix(dims[0][0], dims[1][2]); break; \/\/ &lt;=       default: shape = new Shape(dims[0]); break;     }   }   else   {     throw new NotImplementedException(\"TensorShape int[][] dims\");   } }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3106\/\">V3106<\/a> Possibly index is out of bound. The &#8216;1&#8217; index is pointing beyond &#8216;dims&#8217; bound. TensorShape.cs 107<\/p>\n<p>  I actually found it hard to decide which place to rank this warning because it&#8217;s nice but so are the rest. Anyway, let&#8217;s try to figure out what&#8217;s going on in this code. <\/p>\n<p>  If the number of arrays in <i>dims<\/i> is other than 1, a <i>NotImplementedException<\/i> is thrown. But what if that number is exactly 1? The program will proceed to check the number of elements in this &#171;nested array&#187;. Note what happens when that number is 2. Unexpectedly, <i>dims[1][2]<\/i> is passed as an argument to the <i>Shape.Matrix<\/i> constructor. Now, how many elements were there in <i>dims<\/i>?<\/p>\n<p>  Right, exactly one \u2013 we&#8217;ve just checked this! An attempt to get a second element from an array that contains only one will result in throwing an <i>IndexOutOfRangeException<\/i>. This is obviously a bug. But what about the fix \u2013 is it as obvious?<\/p>\n<p>  The first solution that comes to mind is to change <i>dims[1][2]<\/i> to <i>dims[0][2]<\/i>. Will it help? Not a bit! You&#8217;ll get the same exception, but this time the issue relates to the fact that in this branch the number of elements is 2. Did the developer make two mistakes at once indexing the array? Or maybe they meant to use some other variable? God knows\u2026 The analyzer&#8217;s job is to find the bug; fixing it is the job of the programmer who let it through, or their teammates.<\/p>\n<h3>4 \u2013 A property of a non-existent object<\/h3>\n<p>  Here&#8217;s another warning from <a href=\"https:\/\/www.viva64.com\/en\/b\/0754\/\">the article about OpenRA<\/a>. Perhaps it deserves a higher place, but I ranked it 4th. That&#8217;s a great result, too! Let&#8217;s see what PVS-Studio says about this code:<\/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>PVS-Studio&#8217;s diagnostic message<\/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>  What should we look for in this code? Well, for one thing, note that <i>logo<\/i> may well be assigned <i>null<\/i>. This is hinted at by the numerous checks as well as the name of the <i>GetOrNull<\/i> method, whose return value is written to <i>logo<\/i>. If so, let&#8217;s trace the sequence of events assuming that <i>GetOrNull<\/i> returns <i>null<\/i>. It starts off well, but then we hit the check <i>logo != null &amp;&amp; mod.Icon == null<\/i>. Execution naturally goes down the <i>else<\/i> branch\u2026 where we attempt to access the <i>Bounds<\/i> property of the variable storing the <i>null<\/i>, and then \u2013 KNOCK-KNOCK! He knocks boldly at the door who brings <i>NullReferenceException<\/i>.<\/p>\n<h3>3 \u2013 Schr\u00f6dinger&#8217;s element<\/h3>\n<p>  We have finally reached the three topmost winners. Ranked 3rd is a bug found in Nethermind \u2013 the check is covered in an intriguingly titled article &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0737\/\">Single line code or check of Nethermind using PVS-Studio C# for Linux<\/a>&#171;. This bug is incredibly simple yet invisible to the human eye, especially in a project that big. Do you think the rank is fair?<\/p>\n<pre><code class=\"cs\">public ReceiptsMessage Deserialize(byte[] bytes) {   if (bytes.Length == 0 &amp;&amp; bytes[0] == Rlp.OfEmptySequence[0])     return new ReceiptsMessage(null);     .... }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3106\/\">V3106<\/a> Possibly index is out of bound. The &#8216;0&#8217; index is pointing beyond &#8216;bytes&#8217; bound. Nethermind.Network ReceiptsMessageSerializer.cs 50<\/p>\n<p>  I guess it would be cool if you could pick up the first thing from an empty box, but in this case, you&#8217;ll only get an <i>IndexOutOfRangeException<\/i>. One tiny mistake in the operator leads to incorrect behavior or even a crash. <\/p>\n<p>  Obviously, the &#8216;&amp;&amp;&#8217; operator must be replaced with &#8216;||&#8217; here. Logic errors like this are not uncommon, especially in complex constructs. That&#8217;s why it&#8217;s very handy to have an automatic checker to catch them.<\/p>\n<h3>2 \u2013 Less than 2 but larger than 3<\/h3>\n<p>  Here&#8217;s another warning from RavenDB. As a reminder, the results of checking this project (as well as other matters) are discussed in <a href=\"https:\/\/www.viva64.com\/en\/b\/0740\/\">this article<\/a>. <\/p>\n<p>  Meet the second-place winner on our 2020 Top-10 list of bugs:<\/p>\n<pre><code class=\"cs\">private OrderByField ExtractOrderByFromMethod(....) {   ....   if (me.Arguments.Count &lt; 2 &amp;&amp; me.Arguments.Count > 3)     throw new InvalidQueryException(....);   .... }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;me.Arguments.Count &lt; 2 &amp;&amp; me.Arguments.Count > 3&#8217; is always false. Probably the &#8216;||&#8217; operator should be used here. QueryMetadata.cs(861) Raven.Server<\/p>\n<p>  We have already looked at examples of unexpectedly thrown exceptions. Now, this case is just the opposite: an expected exception will never be thrown. Well, it still might but not until somebody invents a number less than 2 but larger than 3.<\/p>\n<p>  I won&#8217;t be surprised if you disagree with my ranking, but I do like this warning more than all the previous ones. Yes, it&#8217;s astonishingly simple and can be fixed by simply modifying the operator. That, by the way, is exactly what the message passed to the <i>InvalidQueryException <\/i>constructor hints at: &#171;Invalid ORDER BY &#8216;spatial.distance(from, to, roundFactor)&#8217; call, expected 2-3 arguments, got &#187; + <i>me.Arguments.Count<\/i>.<\/p>\n<p>  Yes, it&#8217;s just a blunder, but nobody had noticed and fixed it \u2013 at least not until we discovered it with PVS-Studio. This reminds me that programmers, no matter how skilled, are still only humans (unfortunately?). And for whatever reasons, humans, no matter their qualification, will once in a while overlook even silly mistakes like this. Sometimes a bug shows up right away; sometimes it takes a long-long time before the user gets a warning about an incorrect call of ORDER BY.<\/p>\n<h3>1 \u2013 Quotation marks: +100% to code security<\/h3>\n<p>  Yippee! Meet the leader \u2013 the warning that I believe to be the most interesting, funny, cool, etc. It was found in the ONLYOFFICE project discussed in one of the most recent articles \u2013 &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0783\/\">ONLYOFFICE Community Server: how bugs contribute to the emergence of security problems<\/a>&#171;.<\/p>\n<p>  Now, I want you to read the saddest story ever about an <i>ArgumentException<\/i> never-to-be-thrown:<\/p>\n<pre><code class=\"cs\">public void SetCredentials(string userName, string password, string domain) {   if (string.IsNullOrEmpty(userName))   {     throw new ArgumentException(\"Empty user name.\", \"userName\");   }   if (string.IsNullOrEmpty(\"password\"))   {     throw new ArgumentException(\"Empty password.\", \"password\");   }    CredentialsUserName = userName;   CredentialsUserPassword = password;   CredentialsDomain = domain; }<\/code><\/pre>\n<p>  <b>PVS-Studio&#8217;s diagnostic message<\/b>: <a href=\"https:\/\/www.viva64.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;string.IsNullOrEmpty(&#171;password&#187;)&#8217; is always false. SmtpSettings.cs 104<\/p>\n<p>  Ranking the warnings wasn&#8217;t easy, but I knew from the very beginning that this one was going to be the leader. A slightest tiny typo in a tiny, simple, and neat function has broken the code \u2013 and neither IDE highlighting, nor code review, nor the good old common sense helped catch it in good time. Yet PVS-Studio managed to figure out even this tricky bug, which experienced developers failed to notice.<\/p>\n<p>  The devil is in the details, as usual. Wouldn&#8217;t it be nice to have all such details checked automatically? It sure would! Let developers do what analyzers cannot \u2013 create new cool and safe applications; enjoy creative freedom without bothering about an extra quotation mark in a variable check. <\/p>\n<h2>Conclusion<\/h2>\n<p>  Picking ten most interesting bugs from this year&#8217;s articles was easy. It was ranking them that proved to be the most difficult part. On the one hand, some of the warnings better showcase some of PVS-Studio&#8217;s advanced techniques. On the other hand, some of the bugs are just fun to look at. Many of the warnings here could be swapped places \u2013 for example, 2 and 3.<\/p>\n<p>  Do you think this list should be entirely different? You can actually draw up your own: just follow <a href=\"https:\/\/www.viva64.com\/en\/tags\/?page=1&amp;q=csharp\">this link<\/a> to see the list of articles checked by our team and choose the tastiest warnings to your liking. Share your 2020 tops in the comments \u2013 I&#8217;d love to take a look at them. Think your list can beat mine?<\/p>\n<p>  Of course, whether one warning is more interesting than another is always a matter of taste. Personally, I believe the significance of a warning should be estimated based on whether it encourages the programmer to change anything in the problem code. It was this quality that I was keeping in mind when composing my list. I chose warnings that referred to those spots in code that I believe would look better if found and fixed through the use of static analysis. Besides, anyone can always try PVS-Studio on their own or someone else&#8217;s projects. Just follow <a href=\"https:\/\/www.viva64.com\/en\/pvs-studio-download\/\">this link<\/a>, download the version that suits you most, and fill out a small form to get a trial license.<\/p>\n<p>  That&#8217;s all for today. Thank you for reading, and see you soon!<\/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\/534832\/\"> https:\/\/habr.com\/ru\/articles\/534832\/<\/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\/90d\/cb8\/652\/90dcb8652d76ec2ac1788a32d1a056da.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/90d\/cb8\/652\/90dcb8652d76ec2ac1788a32d1a056da.png\"\/><\/div>\n<p>  This tough year, 2020, will soon be over at last, which means it&#8217;s time to look back at our accomplishments! Over the year, the PVS-Studio team has written quite a number of articles covering a large variety of bugs found in open-source projects with the help of PVS-Studio. This 2020 Top-10 list of bugs in C# projects presents the most interesting specimens. Enjoy the reading!  <\/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-390142","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390142","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=390142"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390142\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=390142"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=390142"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=390142"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}