هذه المقالة هي سلسلة من المنشورات حول استخدام PVS-Studio في الأنظمة السحابية. هذه المرة سوف ننظر إلى محلل بالتزامن مع GitLab CI ، منتج من GitLab Inc. يتيح لك دمج محلل ثابت في نظام CI تحديد الأخطاء فور انتهاء مرحلة إنشاء المشروع ، وهو وسيلة فعالة للغاية لتقليل تكلفة اكتشاف الأخطاء.
قائمة مقالاتنا الأخرى حول الاندماج في أنظمة CI السحابية:
معلومات حول البرنامج المستخدم
GitLab هي خدمة عبر الإنترنت لإدارة المستودعات. يمكن استخدامه مباشرة في المتصفح على الموقع الرسمي عن طريق تسجيل حساب ، أو تثبيته ونشره على الخادم الخاص بك.
PVS-Studio عبارة عن أداة لتحليل الشفرات الثابتة مصممة للكشف عن الأخطاء ونقاط الضعف المحتملة في البرامج المكتوبة بلغات C و C ++ و C # و Java. إنه يعمل على أنظمة 64 بت على Windows و Linux و macOS ويمكنه تحليل الكود المخصص لأنظمة ARM 32 بت و 64 بت والمضمنة. إذا كانت هذه هي المرة الأولى التي تحاول فيها تحليل الكود الثابت لاختبار مشاريعك ، نوصيك بقراءة
المقال حول كيفية رؤية تحذيرات PVS-Studio الأكثر إثارة للاهتمام وتقييم إمكانيات هذه الأداة بسرعة.
سيتم استخدام مشروع OBS لإظهار تشغيل محلل ثابت في السحابة.
Open Broadcaster Software عبارة عن مجموعة
برامج مجانية ومفتوحة المصدر لتسجيل الفيديو وتدفقه. يوفر OBS القدرة على الاعتراض من الأجهزة والمصادر في الوقت الحقيقي ، وتكوين المشهد ، فك التشفير والتسجيل والبث. يتم نقل البيانات بشكل رئيسي من خلال بروتوكول المراسلة في الوقت الحقيقي ، ويمكن نقل البيانات إلى أي مصدر يدعم RTMP - يحتوي البرنامج على إعدادات مسبقة جاهزة للبث المباشر إلى منصات البث الأكثر شعبية.
تعديل
للبدء في تطبيق GitLab ، انتقل إلى الموقع وانقر على زر
التسجيل :
يمكنك التسجيل عن طريق ربط حسابات هذه الخدمات مثل: GitHub ، Twitter ، Google ، BitBucket ، Saleforce أو ببساطة عن طريق ملء النموذج الذي يفتح. بعد التفويض ، تلتقي GitLab بنا باقتراح لإنشاء مشروع:
قائمة المنصات التي يمكنك الاستيراد منها:
من أجل الوضوح ، قم بإنشاء مشروع فارغ:
بعد ذلك ، نحتاج إلى تحميل مشروعنا إلى المستودع الذي تم إنشاؤه. يتم ذلك باستخدام المطالبات التي تظهر في نافذة المشروع الذي تم إنشاؤه.
عند بدء المهمة ، يأخذ GitLab CI التعليمات من
ملف .gitlab-ci.yml . يمكنك إضافته إما بالنقر فوق الزر "
إعداد CI / CD" ، أو ببساطة إنشائه في المستودع المحلي وتحميله إلى الموقع. سوف نستخدم الخيار الأول:
دعنا نصنع غلافًا بسيطًا للبرنامج النصي:
image: debian job: script:
قم بتنزيل الأداة المساعدة للبريد الإلكتروني والمحلل ، والتي سنحتاج إليها في المستقبل:
- apt-get update && apt-get -y install wget gnupg - wget -O - https:
بعد ذلك ، قم بتثبيت التبعيات والأدوات المساعدة لبناء OBS:
- apt-get -y install build-essential cmake make pkg-config libx11-dev libgl1-mesa-dev libpulse-dev libxcomposite-dev libxinerama-dev libv4l-dev libudev-dev libfreetype6-dev libfontconfig-dev qtbase5-dev libqt5x11extras5-dev libx264-dev libxcb-xinerama0-dev libxcb-shm0-dev libjack-jackd2-dev libcurl4-openssl-dev libavcodec-dev libqt5svg5 libavfilter-dev libavdevice-dev libsdl2-dev ffmpeg qt5-default qtscript5-dev libssl-dev qttools5-dev qttools5-dev-tools qtmultimedia5-dev libqt5svg5-dev libqt5webkit5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-jackd2-dev libxrandr-dev libqt5xmlpatterns5-dev libqt5xmlpatterns5 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls28-dev libselinux1-dev linux-libc-dev libtool autotools-dev libio-socket-ssl-perl libnet-ssleay-perl ca-certificates
نحتاج الآن إلى إنشاء ملف برخصة محلل ، افتراضيًا ، سيتم إنشاء ملف PVS-Studio.lic في دليل ../.config/PVS-Studio. في هذه الحالة ، يمكن حذف ملف الترخيص من معلمات إطلاق محلل ، وسيتم التقاطه تلقائيًا:
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
هنا
PVS_NAME و
PVS_KEY هما اسماء المتغيرات التي نحدد قيمها في الإعدادات. سيقومون بتخزين تسجيل الدخول PVS-Studio ومفتاح الترخيص. لتعيين قيمهم ، انتقل إلى: الإعدادات> CI / CD> المتغيرات.
بناء المشروع باستخدام cmake:
- cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On /builds/Stolyarrrov/obscheck/ - make -j4
ثم قم بتشغيل المحلل:
- pvs-studio-analyzer analyze -o PVS-Studio.log
سوف
PVS-Studio.log تخزين نتائج التحليل. ملف التقرير الناتج غير مخصص للقراءة ، ولجعله في متناول الجميع للعين البشرية ، نحتاج إلى أداة plog-Converter. هذا البرنامج يحول سجل المحلل إلى صيغ مختلفة. لسهولة القراءة ، سنحول إلى تنسيق html:
- plog-converter -t html PVS-Studio.log -o PVS-Studio.html
يمكن تحميل التقرير باستخدام
المصنوعات اليدوية ، لكننا سنستخدم طريقة بديلة ونرسل الملف بنتائج المحلل إلى البريد باستخدام أداة إرسال البريد الإلكتروني:
- sendemail -t $MAIL_TO -u "PVS-Studio report, commit:GITLAB_COMMIT" -m "PVS-Studio report, commit:GITLAB_COMMIT" -s $GMAIL_PORT -o tls=auto -f $MAIL_FROM -xu $MAIL_FROM -xp $MAIL_FROM_PASS -a PVS-Studio.log PVS-Studio.html
Full .gitlab-ci.yml:
image: debian job: script: - apt-get update && apt-get -y install wget gnupg - wget -O - https:
انقر على زر
الالتزام التغييرات . إذا فعلنا كل شيء بشكل صحيح ، فسوف نرى النقش:
تكوين GitLab CI هذا صالح. لتتبع التقدم المحرز ، انتقل إلى علامة التبويب
CI / CD> خطوط الأنابيب.انقر على
التوالي . سنرى نافذة الجهاز الظاهري التي يعمل عليها ملف التكوين الخاص بنا. بعد مرور بعض الوقت ، تلقينا الرسالة:
نجحت الوظيفة.لذلك ، حان الوقت للذهاب إلى البريد وفتح ملف HTML مع التحذيرات.
نتائج التحقق من الصحة
دعونا الآن نلقي نظرة على بعض التحذيرات الواردة في التقرير والتي تشير إلى وجود أخطاء في مشروع Open Broadcaster Software لإظهار جوهر تحليل الشفرة الثابتة. الغرض من هذه المقالة هو وصف مبادئ التفاعل بين PVS-Studio و GitLab CI / CD ، لذلك لم تتم كتابة سوى بعض أجزاء التعليمات البرمجية المثيرة للاهتمام التي تحتوي على أخطاء. نحن على استعداد لمنح ترخيص مؤقت لمؤلفي المشروع ، وإذا رغبوا في ذلك ، يمكنهم إجراء تحليل أكثر شمولاً للمشروع. أو يمكنهم الاستفادة من أحد
خيارات الترخيص المجاني لبرنامج PVS-Studio.
يمكن للجميع أيضًا
الحصول على مفتاح تجريبي بشكل مستقل لاستكشاف إمكانيات PVS-Studio وفحص مشاريعهم.
لذلك ، دعونا نلقي نظرة على بعض أمثلة الأخطاء الموجودة في Open Broadcaster Software.
تحذير N1V547 التعبير 'back_size' صحيح دائمًا. circlebuf.h (138)
struct circlebuf { .... size_t capacity; }; static inline void circlebuf_place(struct circlebuf *cb, size_t position,....,const void *data, size_t size) { .... size_t data_end_pos; data_end_pos = position + size; if (data_end_pos > cb->capacity) { size_t back_size = data_end_pos - cb->capacity; if (back_size) { memcpy((uint8_t *)cb->data + position, data, loop_size); } .... }
انتبه إلى السطر:
إذا كانت (data_end_pos> cb-> السعة) ، فإن تحقيق الشرط سيعني أن حجم
الخلفية المتغير ، المحدد في السطر أدناه ، سيكون دائمًا أكبر من الصفر ، لأن أصغر حجمًا من الواضح أنه أكبر من الطرح ، مما يعني أن الشرط هو سطر آخر أدناه ، وسوف يكون دائما
صحيحا . الشرط الزائد ليس ضارًا جدًا عندما يكون رمزًا يعدل البيانات الموجودة تحته.
تحذيرات N2 ، N3V629 خذ بعين الاعتبار فحص تعبير '1 << المسافة البادئة. تحويل البت لقيمة 32 بت مع توسع لاحق إلى نوع 64 بت. profiler.c (610)
static void profile_print_entry(uint64_t active, unsigned indent, ....) { .... active &= (1 << indent) - 1; .... }
يبدو مزيج العمليات على أنواع 32 بت و 64 بت مشبوهًا هنا. أولاً ، يتم حساب القناع باستخدام أنواع 32 بت (تعبير
(1 << المسافة البادئة) - 1 ) ، ثم يتم توسيعه ضمنيًا إلى نوع 64 بت في التعبير
النشط & = .... على الأرجح ، عند حساب القناع ، تم افتراض استخدام أنواع 64 بت.
النسخة الصحيحة من الكود:
active &= ((uint64_t)(1) << indent) - 1;
أو:
active &= (1ull << indent) - 1;
أيضًا ، توجد نسخة طبق الأصل من
مقطع الكود هذا ، والذي أصدر المحلل أيضًا تحذيرًا بشأنه:
V629 خذ بعين الاعتبار فحص تعبير "المسافة البادئة 1". تحويل البت لقيمة 32 بت مع توسع لاحق إلى نوع 64 بت. profiler.c (719)
تحذير N4V761 تم العثور على أربعة كتل مماثلة من النص. "obs-audio-controls.c" (353)
static float get_true_peak(....) { .... peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); .... }
أربع كتل متطابقة. دائمًا تقريبًا ، يشير هذا الرمز إلى خطأ في
نسخ اللصق . على الأرجح ، يجب استدعاء هذه الوظائف باستخدام وسيطات مختلفة. حتى لو لم يكن كذلك ، يبدو هذا الرمز غريبًا. الحل الجيد هو كتابة كتلة مرة واحدة ولفها في حلقة:
for(size_t i = 0; i < 3; i++) { peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); }
تحذير N5V560 جزء من التعبير الشرطي خطأ دائمًا: '! Modifiers'. obs-hotkey.c (662)
typedef struct obs_key_combination obs_key_combination_t; struct obs_key_combination { uint32_t modifiers; obs_key_t key; }; static inline void load_binding(....) { obs_key_combination_t combo = {0}; uint32_t *modifiers = &combo.modifiers; load_modifier(modifiers, data, "shift", INTERACT_SHIFT_KEY); load_modifier(modifiers, data, "control", INTERACT_CONTROL_KEY); load_modifier(modifiers, data, "alt", INTERACT_ALT_KEY); load_modifier(modifiers, data, "command", INTERACT_COMMAND_KEY); if (!modifiers && (combo.key == OBS_KEY_NONE || combo.key >= OBS_KEY_LAST_VALUE)) { .... } .... }
تعريف الدالة
load_modifier :
static inline void load_modifier(uint32_t *modifiers, obs_data_t *data, const char *name, uint32_t flag) { if (obs_data_get_bool(data, name)) *modifiers |= flag; }
كما نرى ،
المعدلات هي مؤشر يتم تهيئته باستخدام عنوان حقل
المعدلات لهيكل
التحرير والسرد . نظرًا لأن قيمتها لا تتغير إلى مكان التحقق ، فستظل غير صفرية. علاوة على ذلك - بين مكان التهيئة والتحقق ، يتم استخدام المؤشر عند استدعاء وظيفة
load_modifier ، حيث يتم
إلغاء تحديدها . وفقًا لذلك ، فإن التحقق من
! Modifiers ليس له معنى ، لأن نتيجة للمشغل
&&&&& سنشعر دائمًا
بالخطأ عند تقييم تعبير منطقي. أعتقد أن المبرمج أراد التحقق من قيمة الأعداد الصحيحة الموجودة في العنوان المخزّن في مؤشر
المعدلات ، ولكن نسيت إلغاء تحديد هذا المؤشر.
أي يبدو لي أن الشيك يجب أن يكون مثل هذا:
if (!*modifiers && ....) : if (!combo.modifiers && ....)
تحذير N6V575 يتم تمرير المؤشر الفارغ المحتمل في وظيفة "strncpy". تفقد الحجة الأولى. خطوط الفحص: 2904 ، 2903. rtmp.c (2904)
static int PublisherAuth(....) { .... ptr = malloc(r->Link.app.av_len + pubToken.av_len); strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len); .... }
غالبًا ما يكون هذا الرمز غير آمن لأنه لا يأخذ في الاعتبار أن
malloc يمكنه إرجاع مؤشر فارغ. في حالة إرجاع
malloc NULL ،
سيحدث سلوك غير معرف في هذه الحالة ، لأن الوسيطة الأولى إلى
strncpy ستكون
NULL .
يمكنك قراءة المزيد حول سبب أهمية التحقق من قيمة الإرجاع للدالة
malloc في
المقالة المقابلة.تحذيرات N7 ، N8 ، N9دعونا نحاول تخمين الحالات التي قد تحدث فيها حسابات خاطئة:
class OBSProjector : public OBSQTDisplay { .... float sourceX, sourceY, ....; .... } .... void OBSProjector::OBSRenderMultiview(....) { OBSProjector *window = (OBSProjector *)data; .... auto calcBaseSource = [&](size_t i) { switch (multiviewLayout) { case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: window->sourceX = (i % 6) * window->scenesCX; window->sourceY = window->pvwprgCY + (i / 6) * window->scenesCY; break; case MultiviewLayout::VERTICAL_LEFT_8_SCENES: window->sourceX = window->pvwprgCX; window->sourceY = (i / 2) * window->scenesCY; if (i % 2 != 0) { window->sourceX += window->scenesCX; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: window->sourceX = 0; window->sourceY = (i / 2) * window->scenesCY; if (i % 2 != 0) { window->sourceX = window->scenesCX; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (i < 4) { window->sourceX = (float(i) * window->scenesCX); window->sourceY = 0; } else { window->sourceX = (float(i - 4) * window->scenesCX); window->sourceY = window->scenesCY; } break; default:
تحذيرات المحلل:
- V636 تم التعبير عن التعبير "i / 6" ضمنيًا من النوع "size_t" إلى النوع "float". النظر في استخدام يلقي نوع واضح لتجنب فقدان جزء كسور. مثال: double A = (double) (X) / Y؛ window-projector.cpp (330)
- V636 تم التعبير عن التعبير "i / 2" ضمنيًا من النوع "size_t" إلى النوع "float". النظر في استخدام يلقي نوع واضح لتجنب فقدان جزء كسور. مثال: double A = (double) (X) / Y؛ window-projector.cpp (334)
- V636 تم التعبير عن التعبير "i / 2" ضمنيًا من النوع "size_t" إلى النوع "float". النظر في استخدام يلقي نوع واضح لتجنب فقدان جزء كسور. مثال: double A = (double) (X) / Y؛ window-projector.cpp (340)
الجواب الصحيح: في تلك التي لا يلقي
طفو . في التعبيرات التي يوضحها لنا المحلل ، يحدث تقسيم صحيح. قد لا يعمل هذا الرمز تمامًا كما هو متوقع من المبرمج.
استنتاج
كما نرى ، فإن دمج محلل ثابت PVS-Studio في مشروع GitLab الخاص بك هو أمر بسيط للغاية. للقيام بذلك ، ما عليك سوى كتابة ملف تكوين واحد ووضعه في مستودع التخزين السحابي الخاص بك. نظرًا لحقيقة أن GitLab لديها آلة افتراضية مدمجة خاصة بها ، فنحن لسنا بحاجة حتى لقضاء الكثير من الوقت لتكوين نظام CI. سيسمح لك التحقق من الكود بتحديد المشاكل فور الإنشاء ، مما سيساعد في حلها عندما يكون التعقيد وتكلفة التعديلات ضئيلاً.

إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط الخاص بالترجمة: فلاديسلاف ستولياروف.
PVS-Studio in the Clouds: GitLab CI / CD .