วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
Travis CI เป็นบริการเว็บแบบกระจายสำหรับการสร้างและทดสอบซอฟต์แวร์ที่ใช้ GitHub เป็นการโฮสต์ซอร์สโค้ด นอกเหนือจากสถานการณ์การทำงานข้างต้นแล้ว คุณสามารถเพิ่มสถานการณ์ของคุณเองได้ด้วยตัวเลือกการกำหนดค่าที่ครอบคลุม ในบทความนี้ เราจะกำหนดค่า Travis CI ให้ทำงานกับ PVS-Studio โดยใช้ตัวอย่างโค้ด PPSSPP

การแนะนำ

Travis CI เป็นบริการเว็บสำหรับการสร้างและทดสอบซอฟต์แวร์ โดยปกติจะใช้ร่วมกับแนวทางปฏิบัติในการบูรณาการอย่างต่อเนื่อง

PPSSPP - โปรแกรมจำลองคอนโซลเกม PSP โปรแกรมสามารถจำลองการเปิดตัวเกมใด ๆ จากดิสก์อิมเมจสำหรับ Sony PSP โปรแกรมนี้เปิดตัวเมื่อวันที่ 1 พฤศจิกายน 2012 PPSSPP ได้รับอนุญาตภายใต้ GPL v2 ใครๆ ก็สามารถปรับปรุงได้ รหัสที่มาของโครงการ.

พีวีเอส-สตูดิโอ — ตัววิเคราะห์โค้ดแบบคงที่สำหรับการค้นหาข้อผิดพลาดและช่องโหว่ที่อาจเกิดขึ้นในโค้ดโปรแกรม สำหรับการเปลี่ยนแปลงในบทความนี้ เราจะเปิดตัว PVS-Studio ไม่ใช่ในเครื่องของนักพัฒนา แต่เปิดตัวบนคลาวด์ และค้นหาข้อผิดพลาดใน PPSSPP

การตั้งค่า Travis CI

เราจะต้องมีพื้นที่เก็บข้อมูลบน GitHub ซึ่งเป็นที่ตั้งของโปรเจ็กต์ที่เราต้องการ รวมถึงคีย์สำหรับ PVS-Studio (คุณจะได้รับ รหัสทดลองใช้ หรือ ฟรีสำหรับโครงการโอเพ่นซอร์ส).

ไปที่เว็บไซต์กันเถอะ Travis CI. หลังจากการอนุญาตโดยใช้บัญชี GitHub ของคุณ เราจะเห็นรายการพื้นที่เก็บข้อมูล:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
สำหรับการทดสอบ ฉันแยก PPSSPP

เราเปิดใช้งานพื้นที่เก็บข้อมูลที่เราต้องการรวบรวม:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
ในขณะนี้ Travis CI ไม่สามารถสร้างโครงการของเราได้เนื่องจากไม่มีคำแนะนำในการสร้าง ถึงเวลากำหนดค่าแล้ว

ในระหว่างการวิเคราะห์ ตัวแปรบางตัวจะมีประโยชน์สำหรับเรา เช่น คีย์สำหรับ PVS-Studio ซึ่งไม่พึงประสงค์ที่จะระบุในไฟล์การกำหนดค่า ดังนั้นเรามาเพิ่มตัวแปรสภาพแวดล้อมโดยใช้การตั้งค่าบิลด์ใน Travis CI:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
เราจำเป็นต้องใช้:

  • PVS_USERNAME - ชื่อผู้ใช้
  • PVS_KEY - คีย์
  • MAIL_USER - อีเมลที่จะใช้ส่งรายงาน
  • MAIL_PASSWORD - รหัสผ่านอีเมล

สองอันสุดท้ายเป็นทางเลือก สิ่งเหล่านี้จะถูกใช้เพื่อส่งผลทางไปรษณีย์ หากคุณต้องการแจกจ่ายรายงานด้วยวิธีอื่น คุณไม่จำเป็นต้องระบุ

ดังนั้นเราจึงได้เพิ่มตัวแปรสภาพแวดล้อมที่เราต้องการ:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
ตอนนี้เรามาสร้างไฟล์ .travis.yml และวางไว้ที่รูทของโปรเจ็กต์ PPSSPP มีไฟล์การกำหนดค่าสำหรับ Travis CI อยู่แล้ว อย่างไรก็ตาม มันใหญ่เกินไปและไม่เหมาะกับตัวอย่างโดยสิ้นเชิง ดังนั้นเราจึงต้องทำให้มันง่ายขึ้นอย่างมาก และเหลือเพียงองค์ประกอบพื้นฐานเท่านั้น

ขั้นแรก เรามาระบุภาษา เวอร์ชันของ Ubuntu Linux ที่เราต้องการใช้ในเครื่องเสมือน และแพ็คเกจที่จำเป็นสำหรับบิลด์:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

แพ็คเกจทั้งหมดที่อยู่ในรายการจำเป็นสำหรับ PPSSPP โดยเฉพาะ

ตอนนี้เราระบุเมทริกซ์แอสเซมบลี:

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"
      env: PPSSPP_BUILD_TYPE=Linux

เพิ่มเติมเล็กน้อยเกี่ยวกับส่วนนี้ เมทริกซ์. ใน Travis CI มีสองวิธีในการสร้างตัวเลือกบิวด์ วิธีแรกคือการระบุรายการคอมไพเลอร์ ประเภทระบบปฏิบัติการ ตัวแปรสภาพแวดล้อม ฯลฯ หลังจากนั้นเมทริกซ์ของชุดค่าผสมที่เป็นไปได้ทั้งหมดจะถูกสร้างขึ้น ประการที่สองคือข้อบ่งชี้ที่ชัดเจนของเมทริกซ์ แน่นอน คุณสามารถรวมทั้งสองแนวทางนี้เข้าด้วยกันและเพิ่มกรณีและปัญหาที่ไม่ซ้ำใคร หรือในทางกลับกัน ให้แยกออกโดยใช้ส่วนนี้ ไม่รวม. คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ใน เอกสารของทราวิส CI.

สิ่งที่เหลืออยู่คือการให้คำแนะนำการประกอบเฉพาะโครงการ:

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

Travis CI ช่วยให้คุณสามารถเพิ่มคำสั่งของคุณเองสำหรับช่วงต่างๆ ของชีวิตของเครื่องเสมือนได้ ส่วน ก่อน_ติดตั้ง ดำเนินการก่อนที่จะติดตั้งแพ็คเกจ แล้ว ติดตั้งซึ่งตามหลังการติดตั้งแพ็คเกจจากรายการ addons.aptซึ่งเราได้ระบุไว้ข้างต้น การชุมนุมเองก็เกิดขึ้นที่ ต้นฉบับ. หากทุกอย่างเป็นไปด้วยดีเราก็จะพบว่าตัวเองเข้ามา after_success (ในส่วนนี้เราจะเรียกใช้การวิเคราะห์แบบคงที่) ขั้นตอนเหล่านี้ไม่ใช่ขั้นตอนทั้งหมดที่สามารถแก้ไขได้ หากคุณต้องการเพิ่มเติม คุณควรตรวจสอบ เอกสารของทราวิส CI.

เพื่อความสะดวกในการอ่าน คำสั่งต่างๆ จะถูกวางไว้ในสคริปต์แยกต่างหาก .travis.shซึ่งวางไว้ที่รูทโปรเจ็กต์

ดังนั้นเราจึงได้ไฟล์ดังต่อไปนี้ .travis.yml:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

ก่อนที่จะติดตั้งแพ็คเกจ เราจะทำการอัพเดตโมดูลย่อย สิ่งนี้จำเป็นสำหรับการสร้าง PPSSPP มาเพิ่มฟังก์ชันแรกกัน .travis.sh (สังเกตส่วนขยาย):

travis_before_install() {
  git submodule update --init --recursive
}

ตอนนี้เรามาถึงการตั้งค่าการเปิดตัว PVS-Studio อัตโนมัติใน Travis CI โดยตรง ก่อนอื่นเราต้องติดตั้งแพ็คเกจ PVS-Studio บนระบบ:

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}

ที่จุดเริ่มต้นของฟังก์ชัน travis_install เราติดตั้งคอมไพเลอร์ที่เราต้องการโดยใช้ตัวแปรสภาพแวดล้อม แล้วถ้าเป็นตัวแปร $PVS_วิเคราะห์ เก็บมูลค่า ใช่ (เราระบุไว้ในส่วน env ในระหว่างการกำหนดค่า build matrix) เราจะติดตั้งแพ็คเกจ pvs-สตูดิโอ. นอกจากนี้ยังระบุแพ็คเกจด้วย libio-socket-ssl-perl и libnet-ssleay-perlอย่างไรก็ตาม สิ่งเหล่านี้จำเป็นสำหรับการส่งผลลัพธ์ทางไปรษณีย์ ดังนั้นจึงไม่จำเป็นหากคุณเลือกวิธีอื่นในการส่งรายงานของคุณ

ฟังก์ชัน ดาวน์โหลด_แตกไฟล์ ดาวน์โหลดและแตกไฟล์เก็บถาวรที่ระบุ:

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

ถึงเวลารวมโครงการกันแล้ว สิ่งนี้เกิดขึ้นในส่วน ต้นฉบับ:

travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}

อันที่จริง นี่คือการกำหนดค่าดั้งเดิมที่เรียบง่าย ยกเว้นบรรทัดเหล่านี้:

if [ "$PVS_ANALYZE" = "Yes" ]; then
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi

ในโค้ดส่วนนี้เรากำหนดไว้ ซม แฟล็กสำหรับส่งออกคำสั่งการคอมไพล์ นี่เป็นสิ่งจำเป็นสำหรับตัววิเคราะห์โค้ดแบบคงที่ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในบทความ “วิธีรัน PVS-Studio บน Linux และ macOS"

หากการชุมนุมสำเร็จเราก็ไปถึง after_successโดยที่เราทำการวิเคราะห์แบบคงที่:

travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}

มาดูบรรทัดต่อไปนี้ให้ละเอียดยิ่งขึ้น:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                -o PVS-Studio-${CC}.log 
                                --disableLicenseExpirationCheck
plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html

บรรทัดแรกจะสร้างไฟล์ลิขสิทธิ์จากชื่อผู้ใช้และคีย์ที่เราระบุไว้ตั้งแต่ต้นเมื่อตั้งค่าตัวแปรสภาพแวดล้อม Travis CI

บรรทัดที่สองเริ่มการวิเคราะห์โดยตรง ธง -เจ กำหนดจำนวนเธรดสำหรับการวิเคราะห์ แฟล็ก -ล บ่งบอกถึงใบอนุญาต ธง -o กำหนดไฟล์สำหรับส่งออกบันทึกและแฟล็ก -disableLicenseExpirationCheck จำเป็นสำหรับเวอร์ชันทดลองใช้งาน เนื่องจากเป็นค่าเริ่มต้น pvs-studio-analyzer จะเตือนผู้ใช้ว่าใบอนุญาตกำลังจะหมดอายุ เพื่อป้องกันไม่ให้สิ่งนี้เกิดขึ้น คุณสามารถระบุแฟล็กนี้ได้

ไฟล์บันทึกมีเอาต์พุตดิบที่ไม่สามารถอ่านได้หากไม่มีการแปลง ดังนั้นคุณต้องทำให้ไฟล์สามารถอ่านได้ก่อน ให้เราส่งบันทึกผ่าน แปลงปลั๊กและผลลัพธ์จะเป็นไฟล์ html

ในตัวอย่างนี้ ฉันตัดสินใจส่งรายงานทางไปรษณีย์โดยใช้คำสั่ง ส่งอีเมล.

เป็นผลให้เราได้รับไฟล์ดังต่อไปนี้ .travis.sh:

#/bin/bash

travis_before_install() {
  git submodule update --init --recursive
}

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}
travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}
travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}
set -e
set -x

$1;

ตอนนี้ถึงเวลาผลักดันการเปลี่ยนแปลงไปยังที่เก็บ git หลังจากนั้น Travis CI จะรันบิลด์โดยอัตโนมัติ คลิกที่ “ppsspp” เพื่อไปที่รายงานบิลด์:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
เราจะเห็นภาพรวมของรุ่นปัจจุบัน:

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP
หากการสร้างเสร็จสมบูรณ์ เราจะได้รับอีเมลพร้อมผลการวิเคราะห์แบบคงที่ แน่นอนว่าการส่งจดหมายไม่ใช่วิธีเดียวในการรับรายงาน คุณสามารถเลือกวิธีการดำเนินการใดก็ได้ แต่สิ่งสำคัญคือต้องจำไว้ว่าหลังจากสร้างเสร็จแล้ว คุณจะไม่สามารถเข้าถึงไฟล์ของเครื่องเสมือนได้

สรุปข้อผิดพลาด

เราได้ทำส่วนที่ยากที่สุดสำเร็จแล้ว ตอนนี้ขอให้แน่ใจว่าความพยายามทั้งหมดของเราคุ้มค่า ลองดูจุดที่น่าสนใจจากรายงานการวิเคราะห์แบบคงที่ที่ส่งถึงฉันทางไปรษณีย์ (ฉันไม่ได้ระบุไว้เพื่ออะไร)

การเพิ่มประสิทธิภาพที่เป็นอันตราย

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  memset( &ctx, 0, sizeof( sha1_context ) );
}

คำเตือน PVS-สตูดิโอ: V597 คอมไพเลอร์สามารถลบการเรียกใช้ฟังก์ชัน 'memset' ซึ่งใช้ในการล้างบัฟเฟอร์ 'sum' ควรใช้ฟังก์ชัน RtlSecureZeroMemory() เพื่อลบข้อมูลส่วนตัว sha1.cpp 325

โค้ดชิ้นนี้อยู่ในโมดูลแฮชที่ปลอดภัย แต่มีข้อบกพร่องด้านความปลอดภัยที่ร้ายแรง (ซีดับบลิว-14). ลองดูที่รายการชุดประกอบที่สร้างขึ้นเมื่อรวบรวมเวอร์ชัน Debug:

; Line 355
  mov r8d, 20
  xor edx, edx
  lea rcx, QWORD PTR sum$[rsp]
  call memset
; Line 356

ทุกอย่างเป็นไปตามลำดับและฟังก์ชั่น เมมเซ็ต ถูกดำเนินการดังนั้นจึงเขียนทับข้อมูลสำคัญใน RAM อย่างไรก็ตามอย่าเพิ่งดีใจ มาดูรายการประกอบของเวอร์ชันวางจำหน่ายพร้อมการปรับให้เหมาะสม:

; 354  :
; 355  :  memset( sum, 0, sizeof( sum ) );
; 356  :}

ดังที่เห็นได้จากรายการ คอมไพลเลอร์ละเลยการโทร เมมเซ็ต. นี่เป็นเพราะความจริงที่ว่าในฟังก์ชั่น sha1 หลังจากการโทร เมมเซ็ต ไม่มีการอ้างอิงถึงโครงสร้างอีกต่อไป กะรัต. ดังนั้น คอมไพลเลอร์ไม่เห็นประเด็นในการเสียเวลาของโปรเซสเซอร์ในการเขียนทับหน่วยความจำที่ไม่ได้ใช้ในอนาคต คุณสามารถแก้ไขได้โดยใช้ฟังก์ชัน RtlSecureZeroMemory หรือ ที่คล้ายกัน ถึงเธอ.

แก้ไข:

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  RtlSecureZeroMemory(&ctx, sizeof( sha1_context ) );
} 

การเปรียบเทียบที่ไม่จำเป็น

static u32 sceAudioOutputPannedBlocking
             (u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    if (leftvol >= 0) {
      chans[chan].leftVolume = leftvol;
    }
    if (rightvol >= 0) {
      chans[chan].rightVolume = rightvol;
    }
    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

คำเตือน PVS-สตูดิโอ: V547 นิพจน์ 'leftvol >= 0' เป็นจริงเสมอ sceAudio.cpp 120

ให้ความสนใจกับสาขาอื่นเป็นอันดับแรก if. รหัสจะถูกดำเนินการหากเงื่อนไขทั้งหมดเท่านั้น ซ้ายปริมาณ > 0xFFFF || rightvol > 0xFFFF || ซ้ายปริมาตร < 0 || ขวาปริมาตร < 0 จะกลายเป็นเรื่องเท็จ ดังนั้นเราจึงได้รับข้อความต่อไปนี้ ซึ่งจะเป็นจริงสำหรับสาขาอื่น: ปริมาตรซ้าย <= 0xFFFF, ขวาปริมาตร <= 0xFFFF, ปริมาตรซ้าย >= 0 и ขวาวอล >= 0. สังเกตสองข้อความสุดท้าย มันสมเหตุสมผลหรือไม่ที่จะตรวจสอบเงื่อนไขที่จำเป็นสำหรับการดำเนินการโค้ดชิ้นนี้?

ดังนั้นเราจึงสามารถลบคำสั่งตามเงื่อนไขเหล่านี้ได้อย่างปลอดภัย:

static u32 sceAudioOutputPannedBlocking
(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    chans[chan].leftVolume = leftvol;
    chans[chan].rightVolume = rightvol;

    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

อีกสถานการณ์หนึ่ง มีข้อผิดพลาดบางอย่างซ่อนอยู่หลังเงื่อนไขที่ซ้ำซ้อนเหล่านี้ บางทีพวกเขาไม่ได้ตรวจสอบสิ่งที่จำเป็น

Ctrl+C Ctrl+V โต้กลับ

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfData) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

V501 มีนิพจน์ย่อยที่เหมือนกัน '!Memory::IsValidAddress(psmfData)' ทางด้านซ้ายและทางด้านขวาของ '||' ตัวดำเนินการ scePsmf.cpp 703

ให้ความสนใจกับการตรวจสอบภายใน if. คุณไม่คิดว่ามันแปลกที่เราตรวจสอบว่าที่อยู่นั้นถูกต้องหรือไม่? psmfData, สองเท่า? ดังนั้นสิ่งนี้จึงดูแปลกสำหรับฉัน... อันที่จริง แน่นอนว่านี่เป็นการพิมพ์ผิด และแนวคิดก็คือการตรวจสอบพารามิเตอร์อินพุตทั้งสอง

ตัวเลือกที่ถูกต้อง:

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfStruct) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

ตัวแปรที่ถูกลืม

extern void ud_translate_att(
  int size = 0;
  ....
  if (size == 8) {
    ud_asmprintf(u, "b");
  } else if (size == 16) {
    ud_asmprintf(u, "w");
  } else if (size == 64) {
    ud_asmprintf(u, "q");
  }
  ....
}

คำเตือน PVS-สตูดิโอ: V547 นิพจน์ 'size == 8' จะเป็นเท็จเสมอ syn-att.c 195

ข้อผิดพลาดนี้อยู่ในโฟลเดอร์ ต่อจึงไม่เกี่ยวข้องกับโครงการมากนัก แต่พบจุดบกพร่องก่อนที่ฉันจะสังเกตเห็น ดังนั้นฉันจึงตัดสินใจทิ้งมันไป ท้ายที่สุด บทความนี้ไม่ได้เกี่ยวกับการตรวจสอบข้อผิดพลาด แต่เกี่ยวกับการบูรณาการกับ Travis CI และไม่มีการกำหนดค่าของเครื่องวิเคราะห์ใดๆ

ตัวแปร ขนาด เริ่มต้นได้ด้วยค่าคงที่ อย่างไรก็ตาม มันไม่ได้ถูกใช้เลยในโค้ด จนถึงตัวดำเนินการ ifซึ่งแน่นอนว่าให้ เท็จ ในขณะที่ตรวจสอบเงื่อนไขเพราะอย่างที่เราจำได้ ขนาด เท่ากับศูนย์ การตรวจสอบครั้งต่อไปก็ไม่สมเหตุสมผลเช่นกัน

เห็นได้ชัดว่าผู้เขียนส่วนของโค้ดลืมเขียนทับตัวแปร ขนาด ก่อนหน้านั้น.

หยุด

นี่คือจุดที่เราอาจจบลงด้วยความผิดพลาด วัตถุประสงค์ของบทความนี้คือเพื่อสาธิตการทำงานของ PVS-Studio ร่วมกับ Travis CI และไม่วิเคราะห์โครงการอย่างละเอียดที่สุด หากคุณต้องการข้อผิดพลาดที่ใหญ่กว่าและสวยงามมากขึ้น คุณสามารถชื่นชมข้อผิดพลาดเหล่านั้นได้เสมอ ที่นี่ :)

ข้อสรุป

การใช้บริการเว็บเพื่อสร้างโปรเจ็กต์ร่วมกับการฝึกวิเคราะห์ส่วนเพิ่มช่วยให้คุณพบปัญหามากมายทันทีหลังจากรวมโค้ด อย่างไรก็ตาม การสร้างเพียงครั้งเดียวอาจไม่เพียงพอ ดังนั้นการตั้งค่าการทดสอบร่วมกับการวิเคราะห์แบบคงที่จะช่วยปรับปรุงคุณภาพของโค้ดได้อย่างมาก

ลิงค์ที่มีประโยชน์

วิธีกำหนดค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP

หากคุณต้องการแบ่งปันบทความนี้กับผู้ชมที่พูดภาษาอังกฤษ โปรดใช้ลิงก์การแปล: Maxim Zvyagintsev วิธีการตั้งค่า PVS-Studio ใน Travis CI โดยใช้ตัวอย่างของตัวจำลองคอนโซลเกม PSP.

ที่มา: will.com

เพิ่มความคิดเห็น