เรายังคงทำให้การใช้ PVS-Studio สะดวกยิ่งขึ้นต่อไป ตัววิเคราะห์ของเราพร้อมใช้งานแล้วใน Chocolatey ซึ่งเป็นตัวจัดการแพ็คเกจสำหรับ Windows เราเชื่อว่าสิ่งนี้จะช่วยอำนวยความสะดวกในการใช้งาน PVS-Studio โดยเฉพาะในบริการคลาวด์ เพื่อไม่ให้ไปไกลเรามาดูซอร์สโค้ดของ Chocolatey ตัวเดียวกันกันดีกว่า Azure DevOps จะทำหน้าที่เป็นระบบ CI
นี่คือรายการบทความอื่นๆ ของเราในหัวข้อการบูรณาการกับระบบคลาวด์:
PVS-Studio สู่คลาวด์: Azure DevOps PVS-Studio สู่คลาวด์: Travis CI PVS-Studio ไปสู่คลาวด์: CircleCI PVS-Studio ไปสู่คลาวด์: GitLab CI/CD
ฉันแนะนำให้คุณใส่ใจกับบทความแรกเกี่ยวกับการผสานรวมกับ Azure DevOps เนื่องจากในกรณีนี้บางจุดจะถูกละเว้นเพื่อไม่ให้ทำซ้ำ
ดังนั้นฮีโร่ของบทความนี้:
เกี่ยวกับการใช้ช็อคโกแลต
คุณสามารถดูวิธีการติดตั้งตัวจัดการแพ็คเกจได้จากที่นี่
คำสั่งให้ติดตั้งตัววิเคราะห์เวอร์ชันล่าสุด:
choco install pvs-studio
คำสั่งเพื่อติดตั้งแพ็คเกจ PVS-Studio เวอร์ชันเฉพาะ:
choco install pvs-studio --version=7.05.35617.2075
ตามค่าเริ่มต้น จะมีการติดตั้งเฉพาะแกนหลักของเครื่องวิเคราะห์ซึ่งเป็นส่วนประกอบหลักเท่านั้น แฟล็กอื่นๆ ทั้งหมด (สแตนด์อโลน, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) สามารถส่งผ่านได้โดยใช้ --package-parameters
ตัวอย่างของคำสั่งที่จะติดตั้งตัววิเคราะห์ด้วยปลั๊กอินสำหรับ Visual Studio 2019:
choco install pvs-studio --package-parameters="'/MSVS2019'"
ตอนนี้เรามาดูตัวอย่างการใช้งานเครื่องวิเคราะห์อย่างสะดวกภายใต้ Azure DevOps
การตั้งค่า
ฉันขอเตือนคุณว่ามีส่วนแยกต่างหากเกี่ยวกับปัญหาต่างๆ เช่น การลงทะเบียนบัญชี การสร้าง Build Pipeline และการซิงโครไนซ์บัญชีของคุณกับโปรเจ็กต์ที่อยู่ในพื้นที่เก็บข้อมูล GitHub
ขั้นแรก มาตั้งค่าทริกเกอร์การเปิดตัว โดยระบุว่าเราจะเปิดใช้งานเฉพาะการเปลี่ยนแปลงเท่านั้น เจ้านาย สาขา:
trigger:
- master
ต่อไปเราต้องเลือกเครื่องเสมือน ในตอนนี้มันจะเป็นเอเจนต์ที่โฮสต์โดย Microsoft พร้อม Windows Server 2019 และ Visual Studio 2019:
pool:
vmImage: 'windows-latest'
มาดูเนื้อหาของไฟล์คอนฟิกูเรชันกัน (block ทำตามขั้นตอน). แม้ว่าคุณจะไม่สามารถติดตั้งซอฟต์แวร์ที่กำหนดเองลงในเครื่องเสมือนได้ แต่ฉันไม่ได้เพิ่มคอนเทนเนอร์ Docker เราสามารถเพิ่ม Chocolatey เป็นส่วนขยายสำหรับ Azure DevOps ได้ โดยเราไปกันเลยที่
ที่นี่คุณต้องเลือกตำแหน่งที่เราจะเพิ่มส่วนขยายแล้วคลิกปุ่ม การติดตั้ง.
หลังจากติดตั้งสำเร็จ คลิก ดำเนินการต่อไปยังองค์กร:
ตอนนี้คุณสามารถดูเทมเพลตสำหรับงาน Chocolatey ได้ในหน้าต่าง งาน เมื่อแก้ไขไฟล์กำหนดค่า สีฟ้า-pipelines.yml:
คลิกที่ Chocolatey และดูรายการฟิลด์:
ที่นี่เราต้องเลือก ติดตั้ง ในสนามร่วมกับทีมงาน ใน ชื่อไฟล์ Nuspec ระบุชื่อของแพ็คเกจที่ต้องการ – pvs-studio หากคุณไม่ระบุเวอร์ชันจะมีการติดตั้งเวอร์ชันล่าสุดซึ่งเหมาะกับเราอย่างสมบูรณ์ มากดปุ่มกัน เพิ่ม และเราจะเห็นงานที่สร้างขึ้นในไฟล์กำหนดค่า
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'
ต่อไป มาดูส่วนหลักของไฟล์ของเรากัน:
- task: CmdLine@2
inputs:
script:
ตอนนี้เราจำเป็นต้องสร้างไฟล์ที่มีลิขสิทธิ์ตัววิเคราะห์ ที่นี่ พีวีเอสNAME и พีวีสกี้ – ชื่อของตัวแปรที่มีค่าที่เราระบุในการตั้งค่า พวกเขาจะจัดเก็บการเข้าสู่ระบบ PVS-Studio และรหัสลิขสิทธิ์ หากต้องการตั้งค่า ให้เปิดเมนู ตัวแปร -> ตัวแปรใหม่. มาสร้างตัวแปรกัน พีวีเอสNAME สำหรับการเข้าสู่ระบบและ พีวีสกี้ สำหรับคีย์ตัววิเคราะห์ อย่าลืมทำเครื่องหมายในช่อง เก็บค่านี้ไว้เป็นความลับ สำหรับ พีวีสกี้. รหัสคำสั่ง:
сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials
–u $(PVSNAME) –n $(PVSKEY)
มาสร้างโปรเจ็กต์โดยใช้ไฟล์ bat ที่อยู่ในที่เก็บ:
сall build.bat
มาสร้างโฟลเดอร์ที่จะจัดเก็บไฟล์พร้อมผลลัพธ์ของตัววิเคราะห์:
сall mkdir PVSTestResults
มาเริ่มวิเคราะห์โครงการกันดีกว่า:
сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
เราแปลงรายงานของเราเป็นรูปแบบ html โดยใช้ยูทิลิตี้PlogСonverter:
сall "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o PVSTestResults .PVSTestResultsChoco.plog
ตอนนี้คุณต้องสร้างงานเพื่อให้สามารถอัปโหลดรายงานได้
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()
ไฟล์การกำหนดค่าที่สมบูรณ์มีลักษณะดังนี้:
trigger:
- master
pool:
vmImage: 'windows-latest'
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'
- task: CmdLine@2
inputs:
script: |
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
credentials –u $(PVSNAME) –n $(PVSKEY)
call build.bat
call mkdir PVSTestResults
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
call "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o .PVSTestResults .PVSTestResultsChoco.plog
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()
คลิกกันได้เลย บันทึก -> บันทึก -> เรียกใช้ เพื่อรันงาน มาดาวน์โหลดรายงานโดยไปที่แท็บงานกัน
โครงการ Chocolatey มีโค้ด C# เพียง 37615 บรรทัด ลองดูข้อผิดพลาดบางส่วนที่พบ
ผลการทดสอบ
คำเตือน N1
คำเตือนจากเครื่องวิเคราะห์:
public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
....
protected CryptoHashProvider Provider;
....
public override void Context()
{
Provider = Provider = new CryptoHashProvider(FileSystem.Object);
}
}
เครื่องวิเคราะห์ตรวจพบการกำหนดตัวแปรให้กับตัวเอง ซึ่งไม่สมเหตุสมผล เป็นไปได้มากว่าแทนที่ตัวแปรตัวใดตัวหนึ่งเหล่านี้ ก็ควรมีตัวอื่นแทน หรือนี่คือการพิมพ์ผิดและสามารถลบการมอบหมายพิเศษออกได้
คำเตือน N2
คำเตือนจากเครื่องวิเคราะห์:
public static PlatformType get_platform()
{
switch (Environment.OSVersion.Platform)
{
case PlatformID.MacOSX:
{
....
}
case PlatformID.Unix:
if(file_system.directory_exists("/Applications")
& file_system.directory_exists("/System")
& file_system.directory_exists("/Users")
& file_system.directory_exists("/Volumes"))
{
return PlatformType.Mac;
}
else
return PlatformType.Linux;
default:
return PlatformType.Windows;
}
}
ความแตกต่างของตัวดำเนินการ & จากผู้ปฏิบัติงาน && คือถ้าด้านซ้ายของนิพจน์คือ เท็จจากนั้นทางด้านขวาจะยังคงถูกคำนวณ ซึ่งในกรณีนี้หมายถึงการเรียกวิธีการที่ไม่จำเป็น system.directory_exists.
ในส่วนที่พิจารณาถือเป็นข้อบกพร่องเล็กน้อย ใช่ เงื่อนไขนี้สามารถปรับให้เหมาะสมได้โดยการแทนที่ตัวดำเนินการ & ด้วยตัวดำเนินการ && แต่จากมุมมองในทางปฏิบัติ สิ่งนี้จะไม่ส่งผลกระทบใดๆ อย่างไรก็ตาม ในกรณีอื่นๆ ความสับสนระหว่าง & และ && อาจทำให้เกิดปัญหาร้ายแรงได้เมื่อทางด้านขวาของนิพจน์ได้รับการปฏิบัติด้วยค่าที่ไม่ถูกต้อง/ไม่ถูกต้อง ตัวอย่างเช่น ในการรวบรวมข้อผิดพลาดของเรา
if ((k < nct) & (s[k] != 0.0))
แม้ว่าดัชนี k ไม่ถูกต้อง จะถูกใช้เพื่อเข้าถึงองค์ประกอบอาร์เรย์ ด้วยเหตุนี้ จึงมีข้อยกเว้นเกิดขึ้น IndexOutOfRangeException.
คำเตือน N3, N4
คำเตือนจากเครื่องวิเคราะห์:
คำเตือนจากเครื่องวิเคราะห์:
public static string
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
....
if (shortPrompt)
{
var choicePrompt = choice.is_equal_to(defaultChoice) //1
?
shortPrompt //2
?
"[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), //3
choice.Substring(1,choice.Length - 1))
:
"[{0}]".format_with(choice.ToUpperInvariant()) //0
:
shortPrompt //4
?
"[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), //5
choice.Substring(1,choice.Length - 1))
:
choice; //0
....
}
....
}
ในกรณีนี้ มีตรรกะแปลก ๆ ที่อยู่เบื้องหลังการทำงานของตัวดำเนินการที่ประกอบไปด้วย มาดูกันดีกว่า: หากตรงตามเงื่อนไขที่ฉันทำเครื่องหมายไว้ด้วยหมายเลข 1 เราจะไปยังเงื่อนไขที่ 2 ซึ่งจะเป็นเสมอ จริงซึ่งหมายความว่าบรรทัดที่ 3 จะถูกดำเนินการ หากเงื่อนไข 1 กลายเป็นเท็จ เราก็จะไปที่บรรทัดที่มีหมายเลข 4 ซึ่งเงื่อนไขจะเป็นเสมอเช่นกัน จริงซึ่งหมายความว่าบรรทัดที่ 5 จะถูกดำเนินการ ดังนั้น เงื่อนไขที่มีเครื่องหมายความคิดเห็น 0 จะไม่เป็นจริง ซึ่งอาจไม่ใช่ตรรกะของการดำเนินการตามที่โปรแกรมเมอร์คาดหวัง
คำเตือน N5
คำเตือนจากเครื่องวิเคราะห์:
private static string GetArgumentName (...., string description)
{
string[] nameStart;
if (maxIndex == 1)
{
nameStart = new string[]{"{0:", "{"};
}
else
{
nameStart = new string[]{"{" + index + ":"};
}
for (int i = 0; i < nameStart.Length; ++i)
{
int start, j = 0;
do
{
start = description.IndexOf (nameStart [i], j);
}
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
....
return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
}
}
การวินิจฉัยใช้งานได้กับบรรทัด:
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)
เนื่องจากเป็นตัวแปร j สองสามบรรทัดด้านบนถูกเตรียมใช้งานเป็นศูนย์ ตัวดำเนินการที่ประกอบไปด้วยจะส่งกลับค่า เท็จ. เนื่องจากเงื่อนไขนี้ เนื้อความของลูปจะถูกดำเนินการเพียงครั้งเดียว สำหรับฉันดูเหมือนว่าโค้ดชิ้นนี้ใช้งานไม่ได้ตามที่โปรแกรมเมอร์ตั้งใจไว้
คำเตือน N6
คำเตือนจากเครื่องวิเคราะห์:
private void remove_nuget_cache_for_package(....)
{
if (!config.AllVersions && installedPackageVersions.Count > 1)
{
const string allVersionsChoice = "All versions";
if (installedPackageVersions.Count != 1)
{
choices.Add(allVersionsChoice);
}
....
}
....
}
มีสภาพซ้อนกันแปลก ๆ ที่นี่: installPackageVersions.Count != 1ซึ่งจะเป็นเช่นนั้นตลอดไป จริง. บ่อยครั้งที่คำเตือนดังกล่าวบ่งชี้ถึงข้อผิดพลาดเชิงตรรกะในโค้ด และในกรณีอื่นๆ คำเตือนดังกล่าวเพียงบ่งชี้ว่ามีการตรวจสอบซ้ำซ้อน
คำเตือน N7
คำเตือนจากเครื่องวิเคราะห์:
public static bool arguments_contain_sensitive_information(string
commandArguments)
{
return commandArguments.contains("-install-arguments-sensitive")
|| commandArguments.contains("-package-parameters-sensitive")
|| commandArguments.contains("apikey ")
|| commandArguments.contains("config ")
|| commandArguments.contains("push ")
|| commandArguments.contains("-p ")
|| commandArguments.contains("-p=")
|| commandArguments.contains("-password")
|| commandArguments.contains("-cp ")
|| commandArguments.contains("-cp=")
|| commandArguments.contains("-certpassword")
|| commandArguments.contains("-k ")
|| commandArguments.contains("-k=")
|| commandArguments.contains("-key ")
|| commandArguments.contains("-key=")
|| commandArguments.contains("-apikey")
|| commandArguments.contains("-api-key")
|| commandArguments.contains("-apikey")
|| commandArguments.contains("-api-key");
}
โปรแกรมเมอร์ที่เขียนโค้ดส่วนนี้คัดลอกและวางสองบรรทัดสุดท้ายแล้วลืมแก้ไข ด้วยเหตุนี้ ผู้ใช้ Chocolatey จึงไม่สามารถใช้พารามิเตอร์ได้ เอปิคีย์ อีกสองสามวิธี เช่นเดียวกับพารามิเตอร์ข้างต้น ฉันสามารถเสนอตัวเลือกต่อไปนี้:
commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");
ข้อผิดพลาดในการคัดลอกและวางมีโอกาสสูงที่จะปรากฏขึ้นไม่ช้าก็เร็วในโปรเจ็กต์ใดๆ ที่มีซอร์สโค้ดจำนวนมาก และหนึ่งในเครื่องมือที่ดีที่สุดในการต่อสู้กับข้อผิดพลาดเหล่านี้คือการวิเคราะห์แบบคงที่
ป.ล. และเช่นเคย ข้อผิดพลาดนี้มีแนวโน้มที่จะปรากฏที่ส่วนท้ายของเงื่อนไขหลายบรรทัด :) ดูสิ่งพิมพ์ "
คำเตือน N8
คำเตือนจากเครื่องวิเคราะห์:
public virtual ConcurrentDictionary<string, PackageResult> get_outdated(....)
{
....
var pinnedPackageResult = outdatedPackages.GetOrAdd(
packageName,
new PackageResult(installedPackage,
_fileSystem.combine_paths(
ApplicationParameters.PackagesLocation,
installedPackage.Id)));
....
if ( installedPackage != null
&& !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion)
&& !config.UpgradeCommand.ExcludePrerelease)
{
....
}
....
}
ข้อผิดพลาดแบบคลาสสิก: คัดค้านก่อน ติดตั้งแพ็คเกจแล้ว ถูกใช้แล้วตรวจสอบ โมฆะ. การวินิจฉัยนี้บอกเราเกี่ยวกับหนึ่งในสองปัญหาในโปรแกรม: อย่างใดอย่างหนึ่ง ติดตั้งแพ็คเกจแล้ว ไม่เคยเท่ากัน โมฆะซึ่งเป็นที่น่าสงสัย จากนั้นการตรวจสอบก็ซ้ำซ้อน หรือเราอาจได้รับข้อผิดพลาดร้ายแรงในโค้ด - ความพยายามที่จะเข้าถึงการอ้างอิงที่เป็นโมฆะ
ข้อสรุป
ดังนั้นเราจึงก้าวไปอีกขั้น - ตอนนี้การใช้ PVS-Studio กลายเป็นเรื่องง่ายและสะดวกยิ่งขึ้น ฉันอยากจะบอกว่า Chocolatey เป็นตัวจัดการแพ็คเกจที่ดีโดยมีข้อผิดพลาดเล็กน้อยในโค้ด ซึ่งอาจน้อยกว่านี้เมื่อใช้ PVS-Studio
เราขอเชิญ
PS
ก่อนที่จะตีพิมพ์ เราได้ส่งบทความไปยังผู้พัฒนา Chocolatey และพวกเขาก็ตอบรับอย่างดี เราไม่พบสิ่งใดที่สำคัญ แต่พวกเขาก็ชอบจุดบกพร่องที่เราพบว่าเกี่ยวข้องกับคีย์ "api-key"
หากคุณต้องการแบ่งปันบทความนี้กับผู้ชมที่พูดภาษาอังกฤษ โปรดใช้ลิงก์การแปล: Vladislav Stolyarov
ที่มา: will.com