PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps
אנו ממשיכים לשפר את השימושיות של PVS-Studio. המנתח שלנו זמין כעת ב-Chocolatey, מנהל חבילות עבור Windowsאנו מאמינים שזה יקל על פריסת PVS-Studio, במיוחד בשירותי ענן. כדי להתחיל, בואו נבחן את קוד המקור של Chocolatey. Azure DevOps ישמש כמערכת CI.

להלן רשימה של מאמרים אחרים שלנו בנושא אינטגרציה עם מערכות ענן:

אני ממליץ לך לשים לב למאמר הראשון על אינטגרציה עם Azure DevOps, מכיוון שבמקרה זה כמה נקודות מושמטות כדי לא להיות משוכפלות.

אז, הגיבורים של המאמר הזה:

סטודיו PVS — כלי לניתוח קוד סטטי שנועד לאתר שגיאות ופגיעויות פוטנציאליות בתוכניות שנכתבו ב-C, C++, C# ו-Java. עובד על מערכות 64 סיביות. Windows, Linux и macOS, ויכול לנתח קוד המכוון לפלטפורמות ARM של 32 סיביות, 64 סיביות ומוטמעות. אם אתם מנסים ניתוח קוד סטטי עבור הפרויקטים שלכם בפעם הראשונה, אנו ממליצים להכיר את מאמר כיצד לצפות במהירות באזהרות ה-PVS-Studio המעניינות ביותר ולהעריך את היכולות של כלי זה.

Devure של תכלת - מערך שירותי ענן המכסים במשותף את כל תהליך הפיתוח. פלטפורמה זו כוללת כלים כגון Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, המאפשרים להאיץ את תהליך יצירת התוכנה ולשפר את איכותה.

שוקולד – מנהל חבילות עבור Windows קוד פתוח. מטרת הפרויקט היא להפוך את כל מחזור חיי התוכנה לאוטומטי, החל מהתקנה ועד שדרוגים והסרה, במערכות הפעלה. Windows.

על השימוש בשוקולדי

אתה יכול לראות כיצד להתקין את מנהל החבילות עצמו כאן קשר. תיעוד מלא להתקנת הנתח זמין בכתובת קשר עיין בסעיף התקנה באמצעות פרק מנהל החבילות של שוקולד. אחזור בקצרה על כמה נקודות משם.

פקודה להתקנת הגרסה העדכנית ביותר של הנתח:

choco install pvs-studio

פקודה להתקנת גרסה ספציפית של חבילת PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

כברירת מחדל, רק הליבה של הנתח, רכיב הליבה, מותקנת. ניתן להעביר את כל הדגלים האחרים (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) באמצעות פרמטרי --package.

דוגמה לפקודה שתתקין מנתח עם תוסף עבור Visual Studio 2019:

choco install pvs-studio --package-parameters="'/MSVS2019'"

כעת בואו נסתכל על דוגמה לשימוש נוח בנתח תחת Azure DevOps.

התאמה

הרשו לי להזכיר לכם שישנו סעיף נפרד בנושאים כגון רישום חשבון, יצירת Build Pipeline וסנכרון החשבון שלכם עם פרויקט שנמצא במאגר GitHub. מאמר. ההגדרה שלנו תתחיל מיד בכתיבת קובץ תצורה.

ראשית, בואו נגדיר טריגר הפעלה, המציין שאנו מפעילים רק עבור שינויים ב אב ענף:

trigger:
- master

בשלב הבא, עלינו לבחור מכונה וירטואלית. בשלב זה, זו תהיה סוכן שמתארח על ידי מיקרוסופט עם Windows Server 2019 ו-Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

נעבור לגוף קובץ התצורה (בלוק צעדים). למרות העובדה שלא ניתן להתקין תוכנה שרירותית במכונה וירטואלית, לא הוספתי קונטיינר Docker. אנו יכולים להוסיף את Chocolatey כהרחבה עבור Azure DevOps. כדי לעשות זאת, בוא נלך אל קשר. נְקִישָׁה השג אותו בחינם. לאחר מכן, אם אתה כבר מורשה, פשוט בחר את החשבון שלך, ואם לא, אז עשה את אותו הדבר לאחר ההרשאה.

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

כאן אתה צריך לבחור היכן נוסיף את התוסף וללחוץ על הכפתור התקן.

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

לאחר התקנה מוצלחת, לחץ המשך לארגון:

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

כעת תוכל לראות את התבנית עבור משימת השוקולד בחלון משימות בעת עריכת קובץ תצורה azure-pipelines.yml:

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

לחץ על שוקולדי וראה רשימה של שדות:

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

כאן אנחנו צריכים לבחור להתקין בשטח עם הקבוצות. IN שם קובץ Nuspec ציינו את שם החבילה הנדרשת – pvs-studio. אם לא תציין את הגרסה, תותקן העדכנית, מה שמתאים לנו לחלוטין. בוא נלחץ על הכפתור להוסיף ונראה את המשימה שנוצרה בקובץ התצורה.

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

לאחר מכן, נעבור לחלק העיקרי של הקובץ שלנו:

- task: CmdLine@2
  inputs:
    script: 

כעת עלינו ליצור קובץ עם רישיון המנתח. כאן PVSNAME и PVSKEY - שמות של משתנים שאת ערכיהם אנו מציינים בהגדרות. הם יאחסנו את פרטי הכניסה ואת מפתח הרישיון של PVS-Studio. כדי להגדיר את הערכים שלהם, פתח את התפריט משתנים->משתנה חדש. בואו ניצור משתנים PVSNAME לכניסה ו PVSKEY עבור מפתח הנתח. אל תשכח לסמן את התיבה שמור את הערך הזה בסוד עבור PVSKEY. קוד פקודה:

с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()

בוא נקליק שמור->שמור->הפעל כדי להפעיל את המשימה. בוא נוריד את הדוח על ידי מעבר ללשונית המשימות.

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

פרויקט Chocolatey מכיל רק 37615 שורות של קוד C#. בואו נסתכל על כמה מהשגיאות שנמצאו.

תוצאות מבחן

אזהרה N1

אזהרת מנתח: V3005 המשתנה 'ספק' מוקצה לעצמו. CrytpoHashProviderSpecs.cs 38

public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
  ....
  protected CryptoHashProvider Provider;
  ....
  public override void Context()
  {
    Provider = Provider = new CryptoHashProvider(FileSystem.Object);
  }
}

המנתח זיהה הקצאה של המשתנה לעצמו, וזה לא הגיוני. סביר להניח שבמקום אחד מהמשתנים האלה צריך להיות אחד אחר. ובכן, או שזו טעות הקלדה, וניתן פשוט להסיר את המשימה הנוספת.

אזהרה N2

אזהרת מנתח: V3093 [CWE-480] האופרטור '&' מעריך את שני האופרנדים. אולי במקום זאת יש להשתמש באופרטור '&&' של קצר חשמלי. Platform.cs 64

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.

בפרגמנט הנחשב, מדובר בפגם קל. כן, ניתן לבצע אופטימיזציה של מצב זה על ידי החלפת האופרטור & באופרטור &&, אך מנקודת מבט מעשית, זה לא משפיע על שום דבר. עם זאת, במקרים אחרים, בלבול בין & ו-&& עלול לגרום לבעיות חמורות כאשר הצד הימני של הביטוי מטופל בערכים שגויים/לא חוקיים. לדוגמה, באוסף השגיאות שלנו, מזוהה באמצעות האבחון V3093, יש את המקרה הזה:

if ((k < nct) & (s[k] != 0.0))

גם אם המדד k שגוי, הוא ישמש לגישה לרכיב מערך. כתוצאה מכך, ייושק חריג IndexOutOfRangeException.

אזהרות N3, N4

אזהרת מנתח: V3022 [CWE-571] הביטוי 'shortPrompt' הוא תמיד נכון. InteractivePrompt.cs 101
אזהרת מנתח: V3022 [CWE-571] הביטוי 'shortPrompt' הוא תמיד נכון. InteractivePrompt.cs 105

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

אזהרת מנתח: V3123 [CWE-783] אולי המפעיל '?:' פועל בצורה שונה ממה שהיה צפוי. העדיפות שלו נמוכה יותר מהעדיפות של מפעילים אחרים במצבו. Options.cs 1019

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

אזהרת מנתח: V3022 [CWE-571] הביטוי 'installedPackageVersions.Count != 1' הוא תמיד נכון. NugetService.cs 1405

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);
    }
    ....
  }
  ....
}

יש כאן מצב מקונן מוזר: installedPackageVersions.Count != 1שתמיד יהיה נָכוֹן. לעתים קרובות אזהרה כזו מעידה על שגיאה לוגית בקוד, ובמקרים אחרים היא פשוט מעידה על בדיקה מיותרת.

אזהרה N7

אזהרת מנתח: V3001 יש תתי-ביטויים זהים 'commandArguments.contains("-apikey")' משמאל ומימין ל-'||' מַפעִיל. ArgumentsUtility.cs 42

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 לא הצליחו להחיל את הפרמטר apikey עוד כמה דרכים. בדומה לפרמטרים לעיל, אני יכול להציע את האפשרויות הבאות:

commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");

לשגיאות העתק-הדבק יש סיכוי גבוה להופיע במוקדם או במאוחר בכל פרויקט עם כמות גדולה של קוד מקור, ואחד הכלים הטובים ביותר להילחם בהם הוא ניתוח סטטי.

נ.ב. וכמו תמיד, השגיאה הזו נוטה להופיע בסוף מצב מרובה שורות :). ראה פרסום"אפקט השורה האחרונה".

אזהרה N8

אזהרת מנתח: V3095 [CWE-476] נעשה שימוש באובייקט 'installedPackage' לפני שהוא אומת כנגד null. קווי בדיקה: 910, 917. NugetService.cs 910

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)
  {
    ....
  }
  ....
}

טעות קלאסית: חפץ ראשון חבילה מותקנת נמצא בשימוש ולאחר מכן נבדק ריק. אבחון זה מספר לנו על אחת משתי בעיות בתוכנית: או חבילה מותקנת אף פעם לא שווה ריק, וזה בספק, ואז הסימון מיותר, או שאנחנו עלולים לקבל שגיאה רצינית בקוד - ניסיון לגשת להפניה null.

מסקנה

אז עשינו עוד צעד קטן - עכשיו השימוש ב-PVS-Studio הפך אפילו לקל ונוח יותר. אני גם רוצה לומר ש- Chocolatey הוא מנהל חבילות טוב עם מספר קטן של שגיאות בקוד, שיכולות להיות אפילו פחות בעת שימוש ב- PVS-Studio.

אנחנו מזמינים אותך להוריד ותנסה את PVS-Studio. שימוש קבוע בנתח סטטי ישפר את האיכות והאמינות של הקוד שהצוות שלך מפתח ויעזור למנוע הרבה אפס פגיעות ביום.

נ.ב.

לפני הפרסום שלחנו את המאמר למפתחי Chocolatey והם קיבלו אותה יפה. לא מצאנו שום דבר קריטי, אבל הם, למשל, אהבו את הבאג שמצאנו שקשור למפתח "api-key".

PVS-Studio נמצא כעת ב- Chocolatey: בודק את Chocolatey מתחת ל- Azure DevOps

אם ברצונך לשתף מאמר זה עם קהל דובר אנגלית, אנא השתמש בקישור התרגום: ולדיסלב סטוליארוב. PVS-Studio נמצא כעת ב- Chocolatey: בודק שוקולד תחת Azure DevOps.

מקור: www.habr.com

קנה אירוח אמין לאתרים עם הגנת DDoS, שרתי VPS VDS 🔥 קנה אחסון אתרים אמין עם הגנת DDoS, שרתי VPS VDS | ProHoster