Travis CI нь GitHub-ийг эх кодын байршуулалт болгон ашигладаг програм хангамжийг бүтээх, турших зориулалттай тараагдсан вэб үйлчилгээ юм. Дээрх үйлдлийн хувилбаруудаас гадна тохиргооны өргөн сонголтуудын ачаар та өөрийн хувилбарыг нэмж болно. Энэ нийтлэлд бид Travis CI-г PPSSPP кодын жишээ ашиглан PVS-Studio-тэй ажиллахаар тохируулах болно.
Танилцуулга
Travis CI-г тохируулж байна
Бидэнд хэрэгтэй төсөл байгаа GitHub дээр хадгалах газар, мөн PVS-Studio-ийн түлхүүр хэрэгтэй болно (та авах боломжтой)
Сайт руугаа орцгооё
Туршилтын хувьд би PPSSPP-г салаав.
Бид цуглуулахыг хүсч буй агуулахыг идэвхжүүлдэг:
Одоогоор Travis CI манай төслийг барьж чадахгүй, учир нь барилга барих заавар байхгүй. Тиймээс тохиргоо хийх цаг болжээ.
Шинжилгээний явцад зарим хувьсагч нь бидэнд ашигтай байх болно, жишээлбэл, PVS-Studio-ийн түлхүүр, үүнийг тохиргооны файлд зааж өгөхийг хүсэхгүй байна. Тиймээс Travis CI дээр бүтээх тохиргоог ашиглан орчны хувьсагчдыг нэмье:
Бидэнд:
- PVS_USERNAME - хэрэглэгчийн нэр
- PVS_KEY - түлхүүр
- MAIL_USER - тайланг илгээхэд ашиглах имэйл
- MAIL_PASSWORD - имэйлийн нууц үг
Сүүлийн хоёр нь сонголттой. Эдгээр нь үр дүнг шуудангаар илгээхэд ашиглагдана. Хэрэв та тайланг өөр аргаар тараахыг хүсвэл тэдгээрийг зааж өгөх шаардлагагүй.
Тиймээс бид шаардлагатай орчны хувьсагчдыг нэмсэн:
Одоо файл үүсгэцгээе .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-д бүтээх сонголтуудыг үүсгэх хоёр арга байдаг: эхнийх нь хөрвүүлэгчдийн жагсаалт, үйлдлийн системийн төрөл, орчны хувьсагч гэх мэтийг зааж өгөх бөгөөд үүний дараа бүх боломжит хослолуудын матриц үүсдэг; хоёр дахь нь матрицын тодорхой заалт юм. Мэдээжийн хэрэг, та эдгээр хоёр аргыг нэгтгэж, өвөрмөц тохиолдол нэмж болно, эсвэл эсрэгээр нь хэсгийг ашиглан хасаж болно. хасах. Та энэ талаар дэлгэрэнгүй уншиж болно
Төсөлд зориулсан угсралтын зааварчилгааг өгөхөд л үлддэг.
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бидний дээр дурдсан. Чуулган өөрөө явагддаг скрипт. Хэрэв бүх зүйл сайхан болсон бол бид өөрсдийгөө олно амжилтын дараа (энэ хэсэгт бид статик дүн шинжилгээ хийх болно). Эдгээр нь өөрчилж болох бүх алхам биш, хэрэв танд илүү их зүйл хэрэгтэй бол та үүнийг анхаарч үзээрэй
Уншихад хялбар болгохын тулд тушаалуудыг тусдаа скрипт дээр байрлуулсан .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
}
Одоо бид Travis CI-д PVS-Studio-г автоматаар эхлүүлэхээр шууд ирлээ. Эхлээд бид 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_ANALYZE үнэ цэнийг хадгалдаг Тийм (бид үүнийг хэсэгт заасан энхтайван матрицын тохиргоо хийх үед) бид багцыг суулгана pvs-studio. Үүнээс гадна багцуудыг мөн зааж өгсөн болно 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
Кодын энэ хэсэгт бид тохируулсан смаке эмхэтгэлийн командуудыг экспортлох туг. Энэ нь статик кодын анализаторт зайлшгүй шаардлагатай. Та энэ талаар дэлгэрэнгүйг " нийтлэлээс уншиж болно.
Хэрэв чуулган амжилттай болсон бол бид хүрэх болно амжилтын дараа, бид статик шинжилгээ хийдэг:
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 орчны хувьсагчдыг тохируулах үед бидний заасан хэрэглэгчийн нэр болон түлхүүрээс лицензийн файл үүсгэдэг.
Хоёр дахь мөрөнд шууд шинжилгээг эхлүүлнэ. туг -ж дүн шинжилгээ хийх хэлхээний тоог тохируулна, туг -л лиценз, далбааг заана -о логуудыг гаргах файл болон тугийг тодорхойлдог -LicenseExpirationCheck-ийг идэвхгүй болгох туршилтын хувилбаруудад шаардлагатай, учир нь анхдагчаар 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" дээр дарна уу:
Бид одоогийн барилгын тоймыг харах болно:
Хэрэв угсралт амжилттай дууссан бол бид статик шинжилгээний үр дүн бүхий имэйл хүлээн авах болно. Мэдээжийн хэрэг, шуудангаар илгээх нь тайлан хүлээн авах цорын ганц арга зам биш юм. Та хэрэгжүүлэх ямар ч аргыг сонгож болно. Гэхдээ угсралтын ажил дууссаны дараа виртуал машины файлуудад хандах боломжгүй гэдгийг санах нь чухал юм.
Алдааны хураангуй
Бид хамгийн хэцүү хэсгийг амжилттай дуусгалаа. Одоо бидний бүх хүчин чармайлт үнэ цэнэтэй гэдэгт итгэлтэй байцгаая. Надад шуудангаар ирсэн статик шинжилгээний тайлангаас зарим сонирхолтой зүйлийг харцгаая (би үүнийг зүгээр л зааж өгсөнгүй).
Аюултай оновчлол
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-Studio анхааруулга:
Энэ кодын хэсэг нь аюулгүй хэш модульд байрладаг боловч аюулгүй байдлын ноцтой алдаатай (
; 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 дуудлагын дараа санах ой бүтцэд хамаарахгүй ctx. Тиймээс хөрвүүлэгч ирээдүйд ашиглагдахгүй санах ойг дарж бичихэд процессорын цагийг дэмий үрэх нь утгагүй гэж үздэг. Та функцийг ашиглан үүнийг засах боломжтой 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-Studio анхааруулга:
Эхнийх нь else салбарт анхаарлаа хандуулаарай if. Бүх нөхцөл хангагдсан тохиолдолд кодыг гүйцэтгэнэ leftvol > 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");
}
....
}
Дотор нь шалгахад анхаарлаа хандуулаарай 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-Studio анхааруулга:
Энэ алдаа нь хавтсанд байрладаг ext, тиймээс төсөлд үнэхээр хамааралгүй, гэхдээ алдаа нь намайг анзаарахаас өмнө олдсон тул би үүнийг орхихоор шийдсэн. Эцсийн эцэст, энэ нийтлэл нь алдааг хянах тухай биш, харин Travis CI-тэй нэгтгэх тухай бөгөөд анализаторын тохиргоо хийгдээгүй болно.
Хувьсах хэмжээ нь тогтмолоор эхлүүлсэн боловч оператор хүртэл кодонд огт ашиглагддаггүй if, энэ нь мэдээжийн хэрэг өгдөг хуурамч нөхцөл байдлыг шалгах явцад, учир нь бидний санаж байгаагаар хэмжээ тэгтэй тэнцүү. Дараагийн шалгалтууд нь бас утгагүй болно.
Кодын фрагментийн зохиогч хувьсагчийг дарж бичихээ мартсан бололтой хэмжээ өмнө нь.
Зогс
Энд л бид алдаа оноогоо дуусгах байх. Энэхүү нийтлэлийн зорилго нь PVS-Studio-ийн ажлыг Travis CI-тэй хамтран харуулах бөгөөд төслийг аль болох нарийвчлан шинжлэхгүй байх явдал юм. Хэрэв та илүү том, илүү үзэсгэлэнтэй алдаа гаргахыг хүсч байвал тэдгээрийг үргэлж биширч чадна
дүгнэлт
Нэмэлт дүн шинжилгээ хийх практикийн хамт төслүүдийг бүтээхэд вэб үйлчилгээг ашиглах нь кодыг нэгтгэсний дараа олон асуудлыг олох боломжийг танд олгоно. Гэсэн хэдий ч, нэг бүтэц хангалтгүй байж болох тул статик анализын хамт тестийг тохируулах нь кодын чанарыг мэдэгдэхүйц сайжруулах болно.
Ашигтай холбоосууд
Linux болон macOS дээр PVS-Studio-г эхлүүлж байна Docker дээр PVS-Studio-г эхлүүлж байна Travis CI баримт бичиг
Хэрэв та энэ нийтлэлийг англи хэлээр ярьдаг үзэгчидтэй хуваалцахыг хүсвэл орчуулгын холбоосыг ашиглана уу: Максим Звягинцев.
Эх сурвалж: www.habr.com