{"id":406225,"date":"2024-06-29T18:48:09","date_gmt":"2024-06-29T18:48:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=406225"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=406225","title":{"rendered":"<span>Re-checking PascalABC.NET<\/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<p>Welcome all fans of clean code! Today we analyze the PascalABC.NET project. In 2017, we already found errors in this project. We used two static analysis tools (more precisely, plugins for SonarQube): SonarC# and PVS-Studio. Today, we analyze this project with the latest version of the PVS-Studio analyzer for C#. Let&#8217;s see what errors we can find today, especially when our analyzer has become more advanced and got new features: it can find more exquisite errors and potential vulnerabilities.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/408\/757\/4c6\/4087574c6e88dae04f2e2620d2830e13.png\" alt=\"0912_PascalABCNET_2\/image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/408\/757\/4c6\/4087574c6e88dae04f2e2620d2830e13.png\"\/><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"introduction\">Introduction<\/h2>\n<p>  <\/p>\n<p>I have an interesting story about PascalABC.NET. Right after we published &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/csharp\/0492\/\">Analysis of PascalABC.NET using SonarQube plugins: SonarC# and PVS-Studio<\/a>&#171;, we accidentally crossed paths with the developers at one conference. It looked like we did it on purpose: wrote an article about errors found in their project and went to the conference to discuss those errors with the developers. Of course, we never planned that, it was a coincidence. But it was funny. After that I was considering the idea of re-checking the project, but I didn&#8217;t have time for that. Now the time has come.<\/p>\n<p>  <\/p>\n<p>PascalABC.NET is a modern implementation of the Pascal language on .NET. You can visit <a href=\"http:\/\/pascalabc.net\/\">the project&#8217;s website<\/a> to read the description and see that the project is developing. The latest version 3.8.1 was released in August 2021. Good news \u2014 it&#8217;s no point in re-checking the &#171;abandoned&#187; project. This was an additional motivation to write this article. A developing project means that old errors are fixed, and the new ones appear.<\/p>\n<p>  <\/p>\n<p>For analysis, I took the <a href=\"https:\/\/github.com\/pascalabcnet\/pascalabcnet\">source code from GitHub<\/a> from 10.12.2021. Note that while I was writing the article the code may have changed. Please take this fact into account if you&#8217;re going to check the source of PascalABC.NET yourself. By the way, you can easily <a href=\"https:\/\/pvs-studio.com\/pvs-studio\/try-free\/?utm_source=habr&amp;utm_medium=articles&amp;utm_content=pascalabc&amp;utm_term=link_try-free\">request<\/a> the PVS-Studio trial version. Don&#8217;t forget about our new feature &#171;<a href=\"https:\/\/pvs-studio.com\/en\/docs\/manual\/6532\/\">Best Warnings<\/a>&#187; which immediately shows the most interesting errors. This is important when you work with such large projects.<\/p>\n<p>  <\/p>\n<p>Unfortunately, many errors found in 2017 were never fixed. After publishing an article, we always send bug reports to the developers. However, only developers can fix those errors. This was an additional problem, since I had to exclude old errors from the report. Despite this, when re-checking the project, we managed to find some new and interesting errors. You can see them below.<\/p>\n<p>  <\/p>\n<h2 id=\"errors\">Errors<\/h2>\n<p>  <\/p>\n<p>Let&#8217;s start with classic \u2014 copy-paste errors. Unbelievable, but developers make such errors over and over again. This means PVS-Studio will definitely have a job to do. Besides, such errors show an important advantage of static analysis tools: constant attention to detail. People don&#8217;t always have it due to fatigue and other reasons.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3001\/\">V3001<\/a> There are identical sub-expressions to the left and to the right of the &#8216;||&#8217; operator. NETGenerator.cs 461<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class CompilerOptions {   public enum PlatformTarget { x64, x86, AnyCPU,     dotnet5win, dotnet5linux, dotnet5macos };   .... } .... bool IsDotnet5() {   return      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5win ||      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5linux ||      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5linux; }<\/code><\/pre>\n<p>  <\/p>\n<p>In this code fragment the developer re-compares the <em>IsDotnet5()<\/em> method with the value of enumeration <em>CompilerOptions.PlatformTarget.dotnet5linux<\/em>. If we look at the declaration of the <em>PlatformTarget<\/em> enumeration, we can assume that the code should look like this:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">bool IsDotnet5() {   return      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5win ||      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5linux ||      comp_opt.platformtarget ==       CompilerOptions.PlatformTarget.dotnet5macos; }<\/code><\/pre>\n<p>  <\/p>\n<p>Note that the code was formatted for readability. In the original version the entire <em>return<\/em> expression is written in one line.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3001\/\">V3001<\/a> There are identical sub-expressions &#8216;ctn2.compiled_type == TypeFactory.ObjectType&#8217; to the left and to the right of the &#8216;||&#8217; operator. NETGenerator.cs 8518<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void AssignToDereferenceNode(....) {   ....   if (.... &amp;&amp; (ctn2.compiled_type == TypeFactory.ObjectType ||       (ctn2.compiled_type == TypeFactory.ObjectType ||        ctn2.compiled_type.IsInterface)))   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Here the developer compares the same value with the <em>TypeFactory.ObjectType<\/em> value. The code was formatted once again. In the original version the <em>if<\/em> expression was written in one line. I think it&#8217;s quite difficult for a person to notice problems in such code. It&#8217;s hard to say how to fix this error, since the <em>TypeFactory<\/em> class has a lot of fields.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3001\/\">V3001<\/a> There are identical sub-expressions &#8216;SK == SymKind.field&#8217; to the left and to the right of the &#8216;||&#8217; operator. LightScopeHelperClasses.cs 30<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public enum SymKind { var, field, param, procname, funcname,                       classname, recordname, interfacename }; .... public class SymInfoSyntax {   public override string ToString()   {     ....     if (SK == SymKind.var ||          SK == SymKind.field ||          SK == SymKind.field ||          SK == SymKind.param)     ....   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>One of the comparisons <em>SK == SymKind.field<\/em> has a mistake in it. It should contain a different value of the <em>SymKind<\/em> enumeration. Maybe the developer who wrote this code fragment could explain what&#8217;s going on.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3004\/\">V3004<\/a> [CWE-691] The &#8216;then&#8217; statement is equivalent to the &#8216;else&#8217; statement. SymbolTable.cs 870<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private Scope FindClassScope(Scope scope) {   while (scope != null &amp;&amp; !(scope is ClassScope))       if(scope is ClassMethodScope)         scope = scope.TopScope;       else         scope = scope.TopScope;   return scope; }<\/code><\/pre>\n<p>  <\/p>\n<p>Different error pattern, same copy-paste: both code blocks of the <em>if<\/em> operator are identical. Here we also need the developer to inspect and fix this error.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3005\/\">V3005<\/a> The &#8216;e&#8217; variable is assigned to itself. generics.cs 430<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static type_node determine_type(....) {   ....   try   {     return ....;   }   catch(Exception e)   {     e = e;   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>A bit weird code. It could be a copy-paste error, as well as an attempt to suppress a warning about an unused variable. Or it could be the consequence of refactoring. Perhaps earlier there was some external <em>e<\/em> variable relative to the <em>catch<\/em> block, and it was then deleted. Anyway, the code looks sloppy.<\/p>\n<p>  <\/p>\n<p>Besides copy-paste errors, I found other problems in the PascalABC.NET code.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3022\/\">V3022<\/a> [CWE-570] Expression &#8216;t != null&#8217; is always false. Visitor.cs 598<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public void prepare_collection(....) {   myTreeNode t;   ....   if (t == null)   {     ....     if (t != null)       t.Nodes.Add(tn);     else       nodes.Add(tn);     ....   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Did this happen after refactoring? Was the developer overly cautious or simply inattentive? As a result, the <em>then<\/em> branch of <em>t.Nodes.Add(tn)<\/em> in the <em>if<\/em> block is never executed. The code needs to be fixed.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3027\/\">V3027<\/a> [CWE-476] The variable &#8216;fn.return_value_type&#8217; was utilized in the logical expression before it was verified against null in the same logical expression. NetHelper.cs 1109<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static function_node get_conversion(....) {   ....   function_node fn = si.sym_info as function_node;   if (.... || fn.return_value_type.original_generic == to || ....       &amp;&amp; fn.return_value_type != null &amp;&amp; ....)   {     return fn;   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The <em>fn.return_value_type<\/em> variable is dereferenced without <em>null<\/em> check. The author supposed that the variable could be <em>null<\/em> because it&#8217;s checked explicitly.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3032\/\">V3032<\/a> [CWE-835] Waiting on this expression is unreliable, as compiler may optimize some of the variables. Use volatile variable(s) or synchronization primitives to avoid this. RemoteCompiler.cs 407<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">CompilerState compilerState = CompilerState.Reloading; .... public string Compile() {   ....   compilerState = CompilerState.CompilationStarting;   ....   while (compilerState != CompilerState.Ready)     Thread.Sleep(5);   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>An interesting error related to the compiler features. The problem may show itself in the release version: due to optimizations the <em>while<\/em> loop will be infinite. The peculiarities of this error and the fixing options are described in the <a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3032\/\">V3032<\/a> documentation.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3043\/\">V3043<\/a> [CWE-483] 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. Compiler.cs 2196<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public string Compile() {   ....   int n = 1;   try   {     n = 2;     ....     if (File.Exists(pdb_file_name))       File.Delete(pdb_file_name);       n = 5;     ....   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>It may seem that expression <em>n = 5<\/em> relates to the <em>if<\/em> block, but it&#8217;s not. The code was badly formatted. This warning is just an example. A rare mistake that doesn&#8217;t lead to error in this case. But this isn&#8217;t always like that. There is a <a href=\"https:\/\/pvs-studio.com\/en\/blog\/examples\/\">section<\/a> on our website with a list of errors found in projects. This list has errors found with V3043 among many others. One of the V3043 errors listed there is from the PascalABC.NET project. I described it when I first checked the project in 2017. This error is similar to other errors, but it&#8217;s more dangerous. You can click on the <a href=\"https:\/\/pvs-studio.com\/en\/blog\/examples\/v3043\/\">link<\/a> and look at this error. Just scroll down a little to get to PascalABC.NET.<\/p>\n<p>  <\/p>\n<p>Before proceeding to the next error, I suggest you look at the code fragment and find an error yourself:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static typed_expression   GetTempFunctionNodeForTypeInference(....) {   ....   for (int i = 0; i &lt; def.formal_parameters.params_list.Count; i++)   {      ....     for (int j = 0;       j &lt; def.formal_parameters.params_list[i].idents.idents.Count;       j++)     {       var new_param = new common_parameter(....,         visitor.get_location(           def.formal_parameters.params_list[i].idents.idents[0]));       ....     }   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Have you found it? To be honest, even with the analyzer warning I didn&#8217;t immediately understand the problem. And yes, the code was formatted for readability. The original version was less readable. Here&#8217;s the analyzer&#8217;s warning: <a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3102\/\">V3102<\/a> Suspicious access to element of &#8216;def.formal_parameters.params_list[i].idents.idents&#8217; object by a constant index inside a loop. LambdaHelper.cs 402<\/p>\n<p>  <\/p>\n<p>Look closely at the calculation of the <em>new_param<\/em> variable&#8217;s value. All iterations of the nested loop use access to the zero element of list def.formal_parameters.params_list[i].idents.idents[0]. Everything points out that the <em>j<\/em> index should have been used instead of 0.<\/p>\n<p>  <\/p>\n<p>Below is the last error I wanted to show you.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v3146\/\">V3146<\/a> [CWE-476] Possible null dereference. The &#8216;symbolInfo.FirstOrDefault()&#8217; can return default null value. SystemLibInitializer.cs 112<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class SymbolInfo {   .... } .... List&lt;TreeConverter.SymbolInfo> symbolInfo = null; .... public List&lt;TreeConverter.SymbolInfo> SymbolInfo {   get   {     if (symbolInfo != null &amp;&amp; ....)     {       if (symbolInfo.FirstOrDefault().sym_info is common_type_node)         ....     }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>Look at the condition of the second <em>if<\/em> block. The <em>symbolInfo<\/em> reference was checked for <em>null<\/em> earlier, no questions here. However, the developers forgot that the <em>FirstOrDefault()<\/em> method may return the default value (null) for the <em>SymbolInfo<\/em> type if the <em>symbolInfo<\/em> list does not contain any element. This will cause problems when we access the <em>sym_info<\/em> property by a null reference.<\/p>\n<p>  <\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>  <\/p>\n<p>This is a small article. But this doesn&#8217;t mean that PascalABC.NET has few errors. I described the most of those errors in 2017, but the developers never fixed them. After the last check the analyzer issued 400 warnings on the High level. On the Medium level \u2014 1364 warnings. There are many same-type errors among them, so I see no point in describing them. The readers can see it themselves if they decide to check the PascalABC.NET project with <a href=\"https:\/\/pvs-studio.com\/pvs-studio\/try-free\/?utm_source=habr&amp;utm_medium=articles&amp;utm_content=pascalabc&amp;utm_term=link_try-free\">PVS-Studio<\/a> and search for errors I described in this and <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/csharp\/0492\/\">previous<\/a> articles.<\/p>\n<p>  <\/p>\n<p>In fact, late bug fixes in open-source code are a common problem. My teammate Andrey Karpov even wrote an article about that: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0900\/\">1000 eyes that don&#8217;t want to check open-source code<\/a>&#171;.<\/p>\n<p>  <\/p>\n<p>I must also note that during the analysis I realized that the use of the analyzer can be inefficient and inconvenient from time to time. Indeed, it&#8217;s really difficult to search for real errors among thousands of warnings. Besides, old errors aren&#8217;t fixed, and the analyzer warnings are not suppressed. I don&#8217;t think developers would want to do such hard work. I understand them. <\/p>\n<p>  <\/p>\n<p>In our opinion, the point of the static analyzer is in regular checks. The code must be checked right after it was written. If the analyzer finds errors in the code, they must be immediately fixed.<\/p>\n<p>  <\/p>\n<p>Let me remind you that modern static analyzers, including PVS-Studio, have a lot of opportunities for convenient work with large projects. Especially at the implementation stage with a large codebase. In this case, we recommend using suppression of all old warnings and working only with those issued for the new code (incremental analysis). Old errors can be corrected little by little, and they won&#8217;t be displayed in the analyzer report. You can read about these features in articles &#171;<a href=\"https:\/\/pvs-studio.com\/en\/docs\/manual\/0032\/\">Baselining analysis results (suppressing warnings for existing code)<\/a>&#187; and &#171;<a href=\"https:\/\/pvs-studio.com\/en\/docs\/manual\/0024\/\">Incremental analysis mode in PVS-Studio<\/a>&#171;.<\/p>\n<p>  <\/p>\n<p>Now I finish this article and wish you all clean code. Good luck.<\/p>\n<\/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\/647643\/\"> https:\/\/habr.com\/ru\/articles\/647643\/<\/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<p>Welcome all fans of clean code! Today we analyze the PascalABC.NET project. In 2017, we already found errors in this project. We used two static analysis tools (more precisely, plugins for SonarQube): SonarC# and PVS-Studio. Today, we analyze this project with the latest version of the PVS-Studio analyzer for C#. Let&#8217;s see what errors we can find today, especially when our analyzer has become more advanced and got new features: it can find more exquisite errors and potential vulnerabilities.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/408\/757\/4c6\/4087574c6e88dae04f2e2620d2830e13.png\" alt=\"0912_PascalABCNET_2\/image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/408\/757\/4c6\/4087574c6e88dae04f2e2620d2830e13.png\"\/><\/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-406225","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/406225","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=406225"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/406225\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=406225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=406225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=406225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}