python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)

pvs-stdio ue4
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
This is a second article, which focuses on usage of the PVS-Studio analyzer in cloud CI-systems. This time we'll consider the platform Azure DevOps — a cloud CI\CD solution from Microsoft. We'll be analyzing the ShareX project.
这是第二篇文章,重点介绍了在云CI系统中PVS-Studio分析仪的用法。 这次,我们将考虑平台Azure DevOps,这是Microsoft的云CI \ CD解决方案。 我们将分析ShareX项目。
We'll need three components. The first is the PVS-Studio analyzer. The second is Azure DevOps, which we'll integrate the analyzer with. The third is the project that we'll check in order to demonstrate the abilities of PVS-Studio when working in a cloud. So let's get going.
我们需要三个组件。 首先是PVS-Studio分析仪。 第二个是Azure DevOps,我们将其与分析器集成在一起。 第三个是我们将检查的项目,以演示在云中工作时PVS-Studio的功能。 因此,让我们开始吧。
PVS-Studio is a static code analyzer for finding errors and security defects. The tool supports the analysis of C, C++ and C# code. PVS-Studio是用于发现错误和安全缺陷的静态代码分析器。 该工具支持对C,C ++和C#代码的分析。 Azure DevOps. The Azure DevOps platform includes such tools as Azure Pipeline, Azure Board, Azure Artifacts and others that speed up the process of creating software and improve its quality. Azure DevOps 。 Azure DevOps平台包括诸如Azure Pipeline,Azure Board,Azure Artifacts之类的工具,这些工具可加快创建软件的过程并提高其质量。 ShareX is a free app that lets you capture and record any part of the screen. The project is written in C# and is eminently suitable to show configuration of the static analyzer launch. The project source code is available on GitHub.
ShareX是一个免费的应用程序,可让您捕获和记录屏幕的任何部分。 该项目用C#编写,非常适合显示静态分析器启动的配置。 该项目的源代码可在GitHub上找到 。
The output of the cloc command for the ShareX project:
ShareX项目的cloc命令的输出:

Language files blank comment Code
C# 696 20658 24423 102565
MSBuild script 11 1 77 5859
语言 档案 空白 评论
C# 696 20658 24423 102565
MSBuild脚本 11 1个 77 5859
让我们开始配置 (Let's Start the Configuration) To start working in Azure DevOps, let's follow the link and press ?Start free with GitHub?.
要开始在Azure DevOps中工作,请点击链接 ,然后按《免费开始使用GitHub》。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Give the Microsoft application access to the GitHub account data.
向Microsoft应用程序授予对GitHub帐户数据的访问权限。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
You'll have to create a Microsoft account to complete your registration.
您必须创建一个Microsoft帐户才能完成注册。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
After registration, create a project:
注册后,创建一个项目:
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Next, we need to move to ?Pipelines? — ?Builds? and create a new Build pipeline.
接下来,我们需要转到?Pipelines?-?Builds?并创建一个新的Build管道。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
When asked where our code is located, we will answer — GitHub.
当被问及我们的代码位于何处时,我们将回答-GitHub。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Authorize Azure Pipelines and choose the repository with the project, for which we'll configure the static analyzer's run.
授权Azure Pipelines并选择项目的存储库,我们将为其配置静态分析器的运行。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
In the template selection window, choose ?Starter pipeline.?
在模板选择窗口中,选择?启动程序管道?。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
We can run static code analysis of the project in two ways: using Microsoft-hosted or self-hosted agents.
我们可以通过两种方式对项目进行静态代码分析:使用Microsoft托管或自托管代理。
First, we'll be using Microsoft-hosted agents. Such agents are ordinary virtual machines that launch when we run our pipeline. They are removed when the task is done. Usage of such agents allows us not to waste time for their support and updating, but imposes certain restrictions, for example — inability to install additional software that is used to build a project.
首先,我们将使用Microsoft托管的代理。 此类代理是在运行管道时启动的普通虚拟机。 完成任务后将它们删除。 使用此类代理使我们不会浪费时间来支持和更新它们,而是施加了某些限制,例如-无法安装用于构建项目的其他软件。
Let's replace the suggested default configuration for the following one for using Microsoft-hosted agents:
让我们将以下建议的默认配置替换为以下使用Microsoft托管代理的默认配置:
# Setting up run triggers # Run only for changes in the master branch trigger: - master# Since the installation of random software in virtual machines # is prohibited, we'll use a Docker container, # launched on a virtual machine with Windows Server 1803 pool: vmImage: 'win1803' container: microsoft/dotnet-framework:4.7.2-sdk-windowsservercore-1803steps: # Download the analyzer distribution - task: PowerShell@2 inputs: targetType: 'inline' script: 'Invoke-WebRequest -Uri https://files.viva64.com/PVS-Studio_setup.exe -OutFile PVS-Studio_setup.exe' - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | # Restore the project and download dependencies nuget restore .\ShareX.sln # Create the directory, where files with analyzer reports will be saved md .\PVSTestResults # Install the analyzer PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /COMPONENTS=Core #Create the file with configuration and license information "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials -u $(PVS_USERNAME) -n $(PVS_KEY)# Run the static analyzer and convert the report in html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog# Save analyzer reports - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults

注意: (Note: )
according to the
根据
documentation, the container used has to be cached in the image of the virtual machine, but at the time of writing the article it's not working and the container is downloaded every time the task starts, which has a negative impact on the execution timing. 文档中 ,必须将使用的容器缓存在虚拟机的映像中,但是在撰写本文时,该容器不起作用,并且每次任务启动时都会下载该容器,这对执行时间有负面影响。 Let's save the pipeline and create variables which will be used for creating the license file. To do this, open the pipeline edit window and click ?Variables? in the top right corner.
让我们保存管道并创建用于创建许可证文件的变量。 为此,请打开管道编辑窗口,然后单击右上角的“变量”。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Then, add two variables — PVS_USERNAME and PVS_KEY, containing the user name and license key respectively. When creating the PVS_KEY variable don't forget to select ?Keep this value secret? to encrypt values of the variable with a 2048-bit RSA key and to suppress the output of the variable value in the task performance log.
然后,添加两个变量PVS_USERNAMEPVS_KEY ,分别包含用户名和许可证密钥。 创建PVS_KEY变量时,请不要忘记选择“保留此值的秘密”以使用2048位RSA密钥加密变量的值,并禁止在任务性能日志中输出变量值。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Save variables and run the pipeline by clicking ?Run?.
单击“运行”,保存变量并运行管道。
The second option to run the analysis — use a self-hosted agent. We can customize and manage self-hosted agents ourselves. Such agents give more opportunities to install software, needed for building and testing our software product.
运行分析的第二个选项-使用自托管代理。 我们可以自己定制和管理自托管代理。 此类代理为构建和测试我们的软件产品所需的软件提供了更多的安装机会。
Before using such agents, you have to configure them according to the instruction and install and configure the static analyzer.
在使用此类代理之前,您必须根据说明进行配置,并安装和配置静态分析器。
To run the task on a self-hosted agent, we'll replace the suggested configuration with the following:
要在自托管代理上运行任务,我们将建议的配置替换为以下内容:
# Setting up triggers # Run the analysis for master-branch trigger: - master# The task is run on a self-hosted agent from the pool 'MyPool' pool: 'MyPool'steps: - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | # Restore the project and download dependencies nuget restore .\ShareX.sln # Create the directory where files with analyzer reports will be saved md .\PVSTestResults # Run the static analyzer and convert the report in html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog # Save analyzer reports - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults

Once the task is complete, you can download the archive with analyzer reports under the ?Summary? tab or you can use the extension Send Mail that enables to configure emailing or consider another convenient tool on Marketplace.
任务完成后,您可以在“摘要”选项卡下下载带有分析器报告的存档,也可以使用扩展邮件发送邮件来配置电子邮件或考虑Marketplace上的另一种便捷工具。
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
分析结果 (Analysis Results) Now let's look at some bugs found in the tested project, ShareX.
现在,让我们看看在测试的项目ShareX中发现的一些错误。
过多检查 (Excessive checks)
To warm up, let's start with simple flaws in the code, namely, with redundant checks:
为了进行热身,让我们从代码中的简单缺陷开始,即从冗余检查开始:
private void PbThumbnail_MouseMove(object sender, MouseEventArgs e) { .... IDataObject dataObject = new DataObject(DataFormats.FileDrop, new string[] { Task.Info.FilePath }); if (dataObject != null) { Program.MainForm.AllowDrop = false; dragBoxFromMouseDown = Rectangle.Empty; pbThumbnail.DoDragDrop(dataObject, DragDropEffects.Copy | DragDropEffects.Move); Program.MainForm.AllowDrop = true; } .... }

PVS-Studio警告: (PVS-Studio warning: )
V3022 [CWE-571] Expression 'dataObject != null' is always true. TaskThumbnailPanel.cs 415 V3022 [CWE-571]表达式'dataObject!= null'始终为true。 TaskThumbnailPanel.cs 415 Let's pay attention to the check of the dataObject variable for null. Why is it here? dataObject cannot be null in this case, as it's initialized by a reference on a created object. As a result, we have an excessive check. Critical? No. Looks succinct? No. This check is clearly better being removed so as not to clutter the code.
让我们注意检查dataObject变量是否为null 。 为什么在这里? 在这种情况下, dataObject不能为null ,因为它是由对创建的对象的引用初始化的。 结果,我们进行了过多的检查。 危急? 不,看起来简洁吗? 否。最好将其删除,以免使代码混乱。
Let's look at another fragment of code which we can comment in a similar way:
让我们看一下我们可以用类似方式注释的另一段代码:
private static Image GetDIBImage(MemoryStream ms) { .... try { .... return new Bitmap(bmp); .... } finally { if (gcHandle != IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } .... } private static Image GetImageAlternative() { .... using (MemoryStream ms = dataObject.GetData(format) as MemoryStream) { if (ms != null) { try { Image img = GetDIBImage(ms); if (img != null) { return img; } } catch (Exception e) { DebugHelper.WriteException(e); } } } .... }

PVS-Studio警告: (PVS-Studio warning: )
V3022 [CWE-571] Expression 'img != null' is always true. ClipboardHelpers.cs 289 V3022 [CWE-571]表达式'img!= null'始终为true。 剪贴板帮助器289 In the GetImageAlternative method, the img variable is checked that it's not null right after a new instance of the Bitmap class is created. The difference from the previous example here is that we use the GetDIBImage method instead of the constructor to initialize the img variable. The code author suggests that an exception might occur in this method, but he declares only blocks try and finally, omitting catch. Therefore, if an exception occurs, the caller method GetImageAlternative won't get a reference to an object of the Bitmap type, but will have to handle the exception in its own catch block. In this case, the img variable won't be initialized and the execution thread won't even reach the img != null check but will get in the catch block. Consequently, the analyzer did point to an excessive check.
GetImageAlternative方法中,在创建Bitmap类的新实例之后,立即检查img变量是否不为null。 与上一个示例的区别在于,我们使用GetDIBImage方法而不是构造函数来初始化img变量。 代码作者建议在此方法中可能会发生异常,但他只声明tryfinally块,而忽略catch 。 因此,如果发生异常,则调用者方法GetImageAlternative将不会获取对Bitmap类型的对象的引用,而是必须在其自己的catch块中处理该异常。 在这种情况下,将不会初始化img变量,并且执行线程甚至不会到达img!= null检查,但会进入catch块。 因此,分析仪确实指出了过度检查。
Let's consider the following example of a V3022 warning:
让我们考虑以下V3022警告示例:
private void btnCopyLink_Click(object sender, EventArgs e) { .... if (lvClipboardFormats.SelectedItems.Count == 0) { url = lvClipboardFormats.Items[0].SubItems[1].Text; } else if (lvClipboardFormats.SelectedItems.Count > 0) { url = lvClipboardFormats.SelectedItems[0].SubItems[1].Text; } .... }

PVS-Studio警告: (PVS-Studio warning: )
V3022 [CWE-571] Expression 'lvClipboardFormats.SelectedItems.Count > 0' is always true. AfterUploadForm.cs 155 V3022 [CWE-571]表达式'lvClipboardFormats.SelectedItems.Count> 0'始终为true。 AfterUploadForm.cs 155 Let's take a closer look at the second conditional expression. There we check the value of the read-only Count property. This property shows the number of elements in the instance of the collection SelectedItems. The condition is only executed if the Count property is greater than zero. It all would be fine, but in the external if statement Count is already checked for 0. The instance of the SelectedItems collection cannot have the number of elements less than zero, therefore, Count is either equal or greater than 0. Since we've already performed the Count check for 0 in the first if statement and it was false, there's no point to write another Count check for being greater than zero in the else branch.
让我们仔细看看第二个条件表达式。 在那里,我们检查只读Count属性的值。 此属性显示集合SelectedItems的实例中的元素数。 仅当Count属性大于零时才执行该条件。 这一切都将是罚款,但在if语句计数已检查0外部的SelectedItems集合的实例不能有元素的数量小于零,因此, 计数大于0,因为我们已经相等或更大已经在第一个if语句中执行了0的Count检查并且它为false,因此没有必要在else分支中编写另一个大于零的Count检查。
The final example of a V3022 warning will be the following fragment of code:
V3022警告的最终示例将是以下代码片段:
private void DrawCursorGraphics(Graphics g) { .... int cursorOffsetX = 10, cursorOffsetY = 10, itemGap = 10, itemCount = 0; Size totalSize = Size.Empty; int magnifierPosition = 0; Bitmap magnifier = null; if (Options.ShowMagnifier) { if (itemCount > 0) totalSize.Height += itemGap; .... } .... }

PVS-Studio警告: (PVS-Studio warning: )
V3022 Expression 'itemCount > 0' is always false. RegionCaptureForm.cs 1100 V3022表达式“ itemCount> 0”始终为false。 RegionCaptureForm.cs 1100 The analyzer noticed that the condition itemCount > 0 will always be false, as the itemCount variable is declared and at the same time assigned zero above. This variable isn't used anywhere up to the very condition, therefore the analyzer was right about the conditional expression, whose value is always false.
分析器注意到,条件itemCount> 0始终为false,因为声明了itemCount变量并同时在上面将其分配为零。 此变量不会在任何条件下使用,因此分析器对条件表达式的判断正确,其值始终为false。
Well, let's now look at something really sapid.
好吧,现在让我们看一下确实很简单的东西。
理解错误的最好方法是可视化错误 (The best way to understand a bug is to visualize a bug)
It seems to us that a rather interesting error was found in this place:
在我们看来,在这个地方发现了一个相当有趣的错误:
public static void Pixelate(Bitmap bmp, int pixelSize) { .... float r = 0, g = 0, b = 0, a = 0; float weightedCount = 0; for (int y2 = y; y2 < yLimit; y2++) { for (int x2 = x; x2 < xLimit; x2++) { ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight; } } .... ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount)); .... }

I wouldn't like to show all the cards and reveal what our analyzer has found, so let's put it aside for a while.
我不想展示所有卡,也不愿透露分析仪的发现,所以让我们搁置一会儿。
By the name of the method, it is easy to guess what it is doing — you give it an image or a fragment of an image, and it pixelates it. The method's code is quite long, so we won't cite it entirely, but just try to explain its algorithm and explain what kind of a bug PVS-Studio managed to find.
通过该方法的名称,很容易猜出它在做什么—给它提供图像或图像片段,然后将其像素化。 该方法的代码很长,因此我们不会完全引用它,而只是尝试解释其算法并解释PVS-Studio设法找到了哪种错误。
This method receives two parameters: an object of the Bitmap type and the value of the int type that indicates the size of pixelation. The operation algorithm is quite simple:
此方法接收两个参数: 位图类型的对象和指示像素大小的int类型的值。 操作算法非常简单:
1) Divide the received image fragment into squares with the side equal to the size of pixelation. For instance, if we have the pixelation size equal to 15, we'll get a square, containing 15x15=225 pixels.
1)将接收到的图像片段分成正方形,边长等于像素大小。 例如,如果像素大小等于15,我们将得到一个正方形,包含15x15 = 225像素。
2) Further, we traverse each pixel in this square and accumulate the values of the fields Red, Green, Blue and Alpha in intermediate variables, and before that multiply the value of the corresponding color and the alpha channel by the pixelWeight variable, obtained by dividing the Alpha value by 255 (the Alpha variable is of the byte type). Also when traversing pixels we sum up the values, written in pixelWeight into the weightedCount variable. The code fragment that executes the above actions is as follows:
2)此外,我们遍历此正方形中的每个像素,并在中间变量中累加字段RedGreenBlueAlpha的值,然后再将相应颜色和alpha通道的值乘以pixelWeight变量,将Alpha值除以255( Alpha变量为字节类型)。 同样,当遍历像素时,我们对这些值求和,将其以pixelWeight形式写入weightedCount变量中。 执行上述操作的代码片段如下:
ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight;

By the way, note that if the value of the Alpha variable is zero, pixelWeight won't add to the weightedCount variable any value for this pixel. We'll need that in the future.
顺便说一句,请注意,如果Alpha变量的值为零,则pixelWeight不会将该像素的任何值添加到weightedCount变量。 我们将来会需要。
3) After traversing all pixels in the current square, we can make a common ?average? color for this square. The code doing this looks as follows:
3)遍历当前正方形中的所有像素后,我们可以为该正方形制成共同的“平均”颜色。 这样做的代码如下所示:
ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount));

4) Now when we got the final color and wrote it in the averageColor variable, we can again traverse each pixel of the square and assign it a value from averageColor.
4)现在,当我们获得最终的颜色并将其写入averageColor变量中时,我们可以再次遍历正方形的每个像素,并从averageColor为其分配一个值。
5) Go back to the point 2 while we have unhandled squares.
5)当我们有未处理的正方形时,回到点2。
Once again, the weightedCount variable isn't equal to the number of all pixels in a square. For example, if an image contains a completely transparent pixel (zero value in the alpha channel), the pixelWeight variable will be zero for this pixel (0 / 255 = 0). Therefore, this pixel won't effect formation of the weightedCount variable. It's quite logical — there's no point to take into account colors of a completely transparent pixel.
再一次, weightedCount变量不等于一个正方形中所有像素的数量。 例如,如果图像包含一个完全透明的像素(alpha通道中的值为零),则该像素的pixelWeight变量将为零( 0/255 = 0)。 因此,此像素不会影响weightedCount变量的形成。 这是很合逻辑的,没有必要考虑完全透明像素的颜色。
So it all seems reasonable — pixelation must work correctly. And it actually does. That's just not for png images that include pixels with values in the alpha channel below 255 and unequal to zero. Notice the pixelated picture below:
因此,一切似乎都是合理的-像素化必须正常工作。 实际上是这样。 这仅适用于包含像素的png图像,该像素的alpha通道中的值小于255且不等于零。 请注意以下像素化图片:
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
Have you seen the pixelation? Neither have we. Okay, now let's reveal this little intrigue and explain where exactly the bug is hiding in this method. The error crept into the line of the pixelWeight variable computation:
你看过像素化了吗? 我们也没有。 好的,现在让我们揭示一下这种小巧的技巧,并说明该方法将错误确切地隐藏在哪里。 错误蔓延pixelWeight变量计算的行:
float pixelWeight = color.Alpha / 255;

The fact of the matter is that when declaring the pixelWeight variable as float, the code author implied that when dividing the Alpha field by 255, he'll get fractional numbers in addition to zero and one. This is where the problem hides, as the Alpha variable is of the byte type. When diving it by 255, we get an integer value. Only after that it'll be implicitly cast to the float type, meaning that the fractional part gets lost.
问题的事实是,当将pixelWeight变量声明为float时 ,代码作者暗示说,当将Alpha字段除以255时,除零和一外,他还将获得分数。 这是问题隐藏的地方,因为Alpha变量是字节类型。 将其除以255时,我们得到一个整数值。 只有在此之后,它才会隐式转换为float类型,这意味着小数部分会丢失。
It's easy to explain why it's impossible to pixelate png images with some transparency. Since for these pixels values of the alpha channel are in the range 0 < Alpha < 255, the Alpha variable divided by 255 will always result in 0. Therefore, values of the variables pixelWeight, r, g, b, a, weightedCount will also always be 0. As a result, our averageColor will be with zero values in all channels: red — 0, blue — 0, green — 0, alpha — 0. By painting a square in this color, we do not change the original color of the pixels, as the averageColor is absolutely transparent. To fix this error, we just need to explicitly cast the Alpha field to the float type. Fixed version of the code line might look like this:
很容易解释为什么无法以某种透明度对png图像进行像素化。 因为对于这些像素,alpha通道的值在0 Alpha变量除以255将始终为0。因此,变量pixelWeightrgbaweightedCount的值也将始终为0。因此,我们的averageColor在所有通道中都将为零值:红色— 0,蓝色— 0,绿色— 0,alpha —0。通过以此颜色绘制正方形,我们不会更改原始颜色像素,因为averageColor是绝对透明的。 要解决此错误,我们只需要将Alpha字段显式转换为float类型即可。 固定版本的代码行可能如下所示:
float pixelWeight = (float)color.Alpha / 255;

Well, it's high time to cite the message of PVS-Studio for the incorrect code:
好了,是时候为错误的代码引用PVS-Studio的消息了:
PVS-Studio警告: (PVS-Studio warning: )
V3041 [CWE-682] The expression was implicitly cast from 'int' type to 'float' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y; . ImageHelpers.cs 1119 V3041 [CWE-682]表达式从'int'类型隐式转换为'float'类型。 考虑使用显式类型转换以避免丢失小数部分。 例如:double A =(double)(X)/ Y; 。 ImageHelpers.cs 1119 For comparison, let us cite the screenshot of a truly pixelated image, obtained on the corrected application version:
为了进行比较,让我们举一个在校正后的应用程序版本上获得的真实像素化图像的屏幕截图:
python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)
文章图片
潜在的NullReferenceException (Potential NullReferenceException)
public static bool AddMetadata(Image img, int id, string text) { .... pi.Value = https://www.it610.com/article/bytesText; if (pi != null) { img.SetPropertyItem(pi); return true; } .... }

PVS-Studio警告: (PVS-Studio warning: )
V3095 [CWE-476] The 'pi' object was used before it was verified against null. Check lines: 801, 803. ImageHelpers.cs 801 V3095 [CWE-476]在对null进行验证之前使用了'pi'对象。 检查行:801、803。ImageHelpers.cs 801 This code fragment shows that the author expected that the pi variable can be null, that is why before calling the method SetPropertyItem, the check pi != null takes place. It's strange that before this check the property is assigned an array of bytes, because if pi is null, an exception of the NullReferenceException type will be thrown.
此代码段显示作者希望pi变量可以为null ,这就是为什么在调用方法SetPropertyItem之前执行pi!= null的原因 。 奇怪的是,在此检查之前,为属性分配了一个字节数组,因为如果pinull ,则将引发NullReferenceException类型的异常。
A similar situation has been noticed in another place:
在另一个地方也发现了类似的情况:
private static void Task_TaskCompleted(WorkerTask task) { .... task.KeepImage = false; if (task != null) { if (task.RequestSettingUpdate) { Program.MainForm.UpdateCheckStates(); } .... } .... }

PVS-Studio警告: (PVS-Studio warning:)
V3095 [CWE-476] The 'task' object was used before it was verified against null. Check lines: 268, 270. TaskManager.cs 268 V3095 [CWE-476]在验证为空之前使用了“任务”对象。 检查行:268,270。TaskManager.cs 268 PVS-Studio found another similar error. The point is the same, so there is no great need to cite the code fragment, the analyzer message will be enough.
PVS-Studio发现另一个类似的错误。 重点是相同的,因此不需要引用代码片段,分析器消息就足够了。
PVS-Studio警告: (PVS-Studio warning:)
V3095 [CWE-476] The 'Config.PhotobucketAccountInfo' object was used before it was verified against null. Check lines: 216, 219. UploadersConfigForm.cs 216 V3095 [CWE-476]在对null进行验证之前,已使用'Config.PhotobucketAccountInfo'对象。 检查行:216,219。UploadersConfigForm.cs 216 相同的返回值 (The same return value)
A suspicious code fragment was found in the EvalWindows method of the WindowsList class, which returns true in all cases:
WindowsList类的EvalWindows方法中发现了可疑的代码片段,该代码片段在所有情况下均返回true
public class WindowsList { public List IgnoreWindows { get; set; } .... public WindowsList() { IgnoreWindows = new List(); }public WindowsList(IntPtr ignoreWindow) : this() { IgnoreWindows.Add(ignoreWindow); } .... private bool EvalWindows(IntPtr hWnd, IntPtr lParam) { if (IgnoreWindows.Any(window => hWnd == window)) { return true; // <= }windows.Add(new WindowInfo(hWnd)); return true; // <= } }

PVS-Studio警告: (PVS-Studio warning: )
V3009 It's odd that this method always returns one and the same value of 'true'. WindowsList.cs 82 V3009这种方法总是返回一个相同的'true'值,这很奇怪。 WindowsList.cs 82 In seems logical that if in the list named IgnoreWindows there is a pointer with the same name as hWnd, the method must return false.
似乎合乎逻辑的是,如果在名为IgnoreWindows的列表中有一个与hWnd同名的指针,则该方法必须返回false
The IgnoreWindows list can be filled either when calling the constructor WindowsList(IntPtr ignoreWindow) or directly through accessing the property as it's public. Anyway, according to Visual Studio, at the moment in the code this list is not filled. This is another strange place of this method.
可以在调用构造函数WindowsList(IntPtr ignoreWindow)时填充IgnoreWindows列表,也可以通过直接访问该属性的公共属性来填充IgnoreWindows列表。 无论如何,根据Visual Studio,目前在代码中此列表尚未填充。 这是此方法的另一个奇怪的地方。
事件处理程序的不安全调用 (Unsafe call of event handlers)
protected void OnNewsLoaded() { if (NewsLoaded != null) { NewsLoaded(this, EventArgs.Empty); } }

PVS-Studio警告: (PVS-Studio warning: )
V3083 [CWE-367] Unsafe invocation of event 'NewsLoaded', NullReferenceException is possible. Consider assigning event to a local variable before invoking it. NewsListControl.cs 111 V3083 [CWE-367]事件'NewsLoaded'的不安全调用,可能会发生NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 NewsListControl.cs 111 Here a very nasty case might occur. After checking the NewsLoaded variable for null, the method, which handles an event, can be unsubscribed, for example, in another thread. In this case, by the time we get into the body of the if statement, the variable NewsLoaded will already be null. A NullReferenceException might occur when trying to call subscribers from the event NewsLoaded, which is null. It is much safer to use a null-conditional operator and rewrite the code above as follows:
在这里可能会发生非常讨厌的情况。 在将NewsLoaded变量检查为空之后,可以取消订阅处理事件的方法,例如,在另一个线程中。 在这种情况下,当我们进入if语句的主体时,变量NewsLoaded将已经为空。 尝试从事件NewsLoaded调用订户时,可能会发生NullReferenceException ,它为null。 使用空条件运算符并按如下所示重写上面的代码要安全得多:
protected void OnNewsLoaded() { NewsLoaded?.Invoke(this, EventArgs.Empty); }

The analyzer pointed to
分析仪指出
68 (68)
similar fragments. We won't describe them all — they all have a similar call pattern.
类似的片段。 我们不会全部描述它们-它们都有相似的调用模式。
从ToString返回null (Return null from ToString)
Recently I've found out from an interesting article of my colleague that Microsoft doesn't recommend returning null from the overridden method ToString. PVS-Studio is well aware of this:
最近,我从我同事的一篇有趣的文章中发现,Microsoft不建议从重写的方法ToString返回null。 PVS-Studio对此非常了解:
public override string ToString() { lock (loggerLock) { if (sbMessages != null && sbMessages.Length > 0) { return sbMessages.ToString(); }return null; } }

PVS-Studio警告: (PVS-Studio warning: )
V3108 It is not recommended to return 'null' from 'ToSting()' method. Logger.cs 167 V3108不建议从“ ToSting()”方法返回“ null”。 Logger.cs 167 如果不使用,为什么要分配? (Why assigned if not used?)
public SeafileCheckAccInfoResponse GetAccountInfo() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "account/info/?format=json"); .... }

PVS-Studio警告: (PVS-Studio warning: )
V3008 The 'url' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 197, 196. Seafile.cs 197 V3008为 'url'变量连续两次分配值。 也许这是一个错误。 检查行:197,196。Seafile.cs 197 As we can see from the example, when declaring the url variable, it is assigned a value, returned from the method FixPrefix. In the next line, we clear the obtained value even without using it anywhere. We get something similar to dead code: it works, but doesn't effect the result. Most likely, this error is a result of a copy-paste, as such code fragments take place in 9 more methods. As an example, we'll cite two methods with a similar first line:
从示例中可以看出,在声明url变量时,将为其分配一个值,该值是从FixPrefix方法返回的 。 在下一行中,即使没有在任何地方使用它,我们也会清除获得的值。 我们得到了类似于无效代码的东西:它可以工作,但不会影响结果。 此错误最有可能是复制粘贴的结果,因为这样的代码片段在另外9种方法中发生。 举个例子,我们将举两个第一行相似的方法:
public bool CheckAuthToken() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "auth/ping/?format=json"); .... } .... public bool CheckAPIURL() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "ping/?format=json"); .... }

结论 (Conclusions) 【python|pvs-stdio ue4_云中的PVS-Studio(Azure DevOps)】 As we can see, configuration complexity of automatic analyzer checks doesn't depend on a chosen CI-system. It took us literally 15 minutes and several mouse clicks to configure checking of our project code with a static analyzer.
如我们所见,自动分析仪检查的配置复杂性不取决于所选的CI系统。 从字面上看,我们花了15分钟时间和几次鼠标单击来配置使用静态分析器对项目代码的检查。
In conclusion, we invite you to download and try the analyzer on your projects.
最后,我们邀请您下载并在您的项目上试用分析仪 。
翻译自: https://habr.com/en/company/pvs-studio/blog/467357/
pvs-stdio ue4

    推荐阅读