في الوقت الحالي ، تعد أنظمة Cloud CI خدمة شائعة جدًا. في هذه المقالة سوف نوضح كيف ، باستخدام الأدوات المتاحة في PVS-Studio ، يمكنك دمج تحليل شفرة المصدر مع نظام CI السحابي باستخدام خدمة Travis CI كمثال.
لماذا ننظر إلى سحب طرف ثالث ولا نصنع غيومنا؟ هناك عدد من الأسباب ، والسبب الرئيسي هو أن SaaS هو إجراء مكلف وصعب إلى حد ما. في الواقع ، يعد دمج تحليل PVS-Studio مباشرة مع نظام أساسي سحابي تابع لجهة خارجية (سواء أكان ذلك منصات مفتوحة مثل CircleCI أو Travis CI أو GitLab أو بعض حلول المؤسسات المتخصصة المستخدمة في شركة واحدة محددة فقط) مهمة بسيطة إلى حد ما. وهذا يعني أنه يمكننا القول أن
PVS-Studio متوفر بالفعل "في السحب" . هناك مسألة مختلفة تمامًا وهي تنظيم وتوفير البنية التحتية لمثل هذا العمل على مدار الساعة طوال أيام الأسبوع. هذه مهمة مختلفة تمامًا ، وليس لدى PVS-Studio أي خطط لتوفير منصة سحابة خاصة بها مباشرة لإجراء التحليل عليها.
معلومات حول البرنامج المستخدم
Travis CI هي خدمة لإنشاء واختبار البرامج التي تستخدم GitHub كتخزين. لا يتطلب Travis CI تغيير رمز البرنامج لاستخدام الخدمة ، فكل الإعدادات تحدث في ملف
.travis.yml الموجود في جذر المخزون.
سنتخذ
LXC (حاويات Linux) كمشروع اختبار للاختبار باستخدام PVS-Studio. إنه نظام ظاهري على مستوى نظام التشغيل لتشغيل مثيلات متعددة لنظام التشغيل Linux على عقدة واحدة.
المشروع صغير ، لكن أكثر من كافٍ للتوضيح. إخراج الأمر cloc:
ملاحظة: يستخدم مطورو LXC بالفعل Travis CI ، لذلك سنتخذ ملف التكوين الخاص بهم كأساس ونقوم بتحريره لأغراضنا.
تعديل
للبدء في Travis CI ،
اتبع الرابط والمصادقة باستخدام حساب GitHub.
في النافذة التي تفتح ، تحتاج إلى تفويض Travis CI.
بعد إذن ، إعادة توجيه إلى صفحة الترحيب "أول مرة هنا؟ يتيح لك البدء! "
، الذي يصف بإيجاز ما يجب القيام به بعد البدء:
- تفعيل المستودعات ؛
- أضف الملف .travis.yml إلى المستودع ؛
- تشغيل البناء الأول.
سنبدأ في تنفيذ هذه النقاط.
لإضافة مستودعنا إلى Travis CI ، انتقل إلى إعدادات الملف الشخصي
عبر الرابط وانقر على زر "تنشيط".
بعد النقر ، يتم فتح نافذة مع اختيار المستودعات التي سيتم منح تطبيق Travis CI حق الوصول إليها.
ملاحظة: لتوفير الوصول إلى المستودع ، يجب أن يكون للحساب حقوق المسؤول عليه.
لقد اخترنا المستودع المرغوب فيه ، ونؤكد هذا التحديد من خلال الزر "قبول وتثبيت" ، وسيتم إعادة توجيهنا إلى صفحة إعدادات الملف الشخصي.
قم بإنشاء المتغيرات التي سنستخدمها على الفور لإنشاء ملف ترخيص المحلل وإرسال تقاريره. للقيام بذلك ، انتقل إلى صفحة الإعدادات - زر "الإعدادات" على يمين المستودع المرغوب.
سيتم فتح نافذة الإعدادات.
وصف قصير للإعدادات:
- القسم "عام" - تحديد مشغلات مهام التشغيل التلقائي ؛
- قسم "الإلغاء التلقائي" - يسمح لك بتكوين التجميع التلقائي للإلغاء ؛
- يتيح لك قسم "متغيرات البيئة" - تحديد متغيرات البيئة التي تحتوي على كل من المعلومات العامة والسرية ، مثل بيانات الاعتماد أو مفاتيح ssh ؛
- قسم "وظائف كرون" - تحديد جدول إطلاق المهمة.
في قسم "متغيرات البيئة" ، نقوم بإنشاء متغيرات
PVS_USERNAME و
PVS_KEY التي تحتوي ، على التوالي ، على اسم المستخدم ومفتاح الترخيص للمحلل الثابت. إذا لم يكن لديك ترخيص PVS-Studio دائم ، فيمكنك
طلب ترخيص تجريبي .
قم بإنشاء المتغيرات
MAIL_USER و
MAIL_PASSWORD فورًا التي تحتوي على اسم المستخدم وكلمة المرور
لصندوق البريد ، والتي
سنستخدمها لإرسال التقارير.
عند بدء المهمة ، يأخذ Travis CI تعليمات من ملف .travis.yml الموجود في جذر المخزون.
باستخدام Travis CI ، يمكننا تشغيل التحليل الثابت مباشرة في الجهاز الظاهري ، أو استخدام حاوية مُعدة مسبقًا لهذا الغرض. لا تختلف نتائج هذه الطرق عن بعضها البعض ، ولكن استخدام حاوية مُعدة مسبقًا يمكن أن يكون مفيدًا ، على سبيل المثال ، إذا كان لدينا بالفعل حاوية مع بعض البيئة المحددة التي تم فيها بناء منتج البرنامج واختباره ، وليس هناك رغبة في استعادة هذه البيئة في Travis CI .
لنقم بإنشاء تكوين لتشغيل المحلل في جهاز افتراضي.
للتجميع والاختبار ، سنستخدم جهازًا افتراضيًا يستند إلى Ubuntu Trusty ، ويمكن العثور على وصفه
هنا .
بادئ ذي بدء ، نشير إلى أن المشروع مكتوب بلغة C وأننا ندرج قائمة المترجمين الذين سنستخدمهم للتجميع:
language: c compiler: - gcc - clang
ملاحظة : إذا حددت أكثر من مترجم ، فسيتم تشغيل المهام بالتوازي مع كل منها. اقرأ المزيد
في الوثائق .
قبل بدء الإنشاء ، نحتاج إلى إضافة مستودع محلل وتثبيت التبعيات وحزم إضافية:
before_install: - sudo add-apt-repository ppa:ubuntu-lxc/daily -y - wget -q -O - https:
قبل بناء المشروع ، تحتاج إلى إعداد البيئة:
script: - ./coccinelle/run-coccinelle.sh -i - git diff --exit-code - export CFLAGS="-Wall -Werror" - export LDFLAGS="-pthread -lpthread" - ./autogen.sh - rm -Rf build - mkdir build - cd build - ../configure --enable-tests --with-distro=unknown
بعد ذلك ، نحتاج إلى إنشاء ملف بترخيص وتشغيل تحليل المشروع.
ينشئ الأمر الأول ملف ترخيص للمحلل. تؤخذ البيانات للمتغيرات
$ PVS_USERNAME و
$ PVS_KEY من إعدادات المشروع.
- pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
يبدأ الأمر التالي في تتبع تجميع المشروع:
- pvs-studio-analyzer trace -- make -j4
بعد أن نبدأ التحليل الثابت.
ملاحظة: عند استخدام ترخيص تجريبي ، يجب عليك تحديد المعلمة -
disableLicenseExpirationCheck .
- pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic -o PVS-Studio-${CC}.log –-disableLicenseExpirationCheck
باستخدام الأمر الأخير ، يتم تحويل ملف نتائج المحلل إلى تقرير html.
- plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
نظرًا لأن TravisCI لا يسمح بتغيير تنسيق إعلامات البريد الإلكتروني ، فسوف نستخدم حزمة البريد الإلكتروني لإرسال التقارير في الخطوة الأخيرة:
- sendemail -t mail@domain.com -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
النص الكامل لملف التكوين لتشغيل المحلل في جهاز افتراضي:
language: c compiler: - gcc - clang before_install: - sudo add-apt-repository ppa:ubuntu-lxc/daily -y - wget -q -O - https:
لتشغيل محلل ثابت في حاوية ، قم أولاً بإنشائه باستخدام Dockerfile التالي:
FROM docker.io/ubuntu:trusty ENV CFLAGS="-Wall -Werror" ENV LDFLAGS="-pthread -lpthread" RUN apt-get update && apt-get install -y software-properties-common wget \ && wget -q -O - https:
في هذه الحالة ، قد يبدو ملف التكوين كما يلي:
before_install: - docker pull docker.io/oandreev/lxc env: - CC=gcc - CC=clang script: - docker run --rm --cap-add SYS_PTRACE -v $(pwd):/pvs -w /pvs docker.io/oandreev/lxc /bin/bash -c " ./coccinelle/run-coccinelle.sh -i && git diff --exit-code && ./autogen.sh && mkdir build && cd build && ../configure CC=$CC && pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic && pvs-studio-analyzer trace -- make -j4 && pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic -o PVS-Studio-$CC.log --disableLicenseExpirationCheck && plog-converter -t html -o PVS-Studio-$CC.html PVS-Studio-$CC.log && sendemail -t mail@domain.com -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"
كما ترون ، في هذه الحالة ، لا نقوم بأي شيء داخل الجهاز الظاهري ، وكل الإجراءات الخاصة بتجميع المشروع واختباره تحدث داخل الحاوية.
ملاحظة : عند بدء تشغيل الحاوية ، يجب عليك تحديد
المعلمة --cap-add SYS_PTRACE أو
- Sececp-opt seccomp: معلمة غير محصورة ، حيث يتم استخدام استدعاء نظام ptrace لتجميع التتبع.
نقوم بتحميل ملف التكوين في جذر المستودع ونرى أن Travis CI تلقى إخطارًا عن وجود تغييرات في المشروع وبدأنا التجميع تلقائيًا.
يمكن الاطلاع على معلومات مفصلة حول تقدم التجميع والتحقق من محلل في وحدة التحكم.
بعد الانتهاء من الاختبارات ، سنتلقى حرفين في البريد: أحدهما مع نتائج التحليل الثابت لبناء المشروع باستخدام gcc ، والثاني مع clang ، على التوالي.
باختصار عن نتائج الاختبار
بشكل عام ، فإن المشروع نظيف تمامًا ، حيث أصدر المحلل 24 تحذيرًا متوسطًا و 46 تحذيرًا فقط. لإظهار العمل ، فكر في بعض الإعلامات المهمة:
الظروف الزائدة في حالة
V590 فكر في فحص
تعبير 'ret! = (- 1) && ret == 1'. التعبير مفرط أو يحتوي على خطأ مطبعي. attach.c 107
#define EOF -1 static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) { .... while (getline(&line, &line_bufsz, proc_file) != -1) { ret = sscanf(line, "CapBnd: %llx", &info->capability_mask); if (ret != EOF && ret == 1)
إذا كان
ret == 1 ، فهو بالتأكيد لا يساوي -1 (EOF). التحقق المفرط من الصحة ،
ret! = EOF يمكن إزالتها.
تم إصدار تحذيرين آخرين:
- V590 فكر في فحص تعبير 'ret! = (- 1) && ret == 1'. التعبير مفرط أو يحتوي على خطأ مطبعي. attach.c 579
- V590 فكر في فحص تعبير 'ret! = (- 1) && ret == 1'. التعبير مفرط أو يحتوي على خطأ مطبعي. attach.c 583
فقدان بت عالية
V784 حجم قناع البت أقل من حجم المعامل الأول. هذا سوف يسبب فقدان أعلى بت. conf.c 1879
struct mount_opt { char *name; int clear; int flag; }; static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t size) { struct mount_opt *mo; for (mo = &mount_opt[0]; mo->name != NULL; mo++) { if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { if (mo->clear) { *flags &= ~mo->flag;
ضمن Linux ، يعد
long متغيرًا صحيحًا 64 بت ،
علامة mo>> متغير عدد صحيح 32 بت. إن استخدام
علامة mo>> كقناع نقطي سينتج عنه فقد 32 بت. صب ضمني من قناع البت إلى متغير عدد صحيح 64 بت بعد إجراء انعكاس bitwise. البتات العالية لهذا القناع ستكون صفرا.
شرح مع مثال:
unsigned long long x; unsigned y; .... x &= ~y;
الكود الصحيح هو:
*flags &= ~(unsigned long)(mo->flag);
أصدر المحلل تحذيرا مماثلا آخر:
- V784 حجم قناع البت أقل من حجم المعامل الأول. هذا سوف يسبب فقدان أعلى بت. Conf.c 1933
دورة مشبوهة
V612 "عودة" غير مشروطة داخل حلقة. conf.c 3477
#define lxc_list_for_each(__iterator, __list) \ for (__iterator = (__list)->next; __iterator != __list; \ __iterator = __iterator->next) static bool verify_start_hooks(struct lxc_conf *conf) { char path[PATH_MAX]; struct lxc_list *it; lxc_list_for_each (it, &conf->hooks[LXCHOOK_START]) { int ret; char *hookname = it->elem; ret = snprintf(path, PATH_MAX, "%s%s", conf->rootfs.path ? conf->rootfs.mount : "", hookname); if (ret < 0 || ret >= PATH_MAX) return false; ret = access(path, X_OK); if (ret < 0) { SYSERROR("Start hook \"%s\" not found in container", hookname); return false; } return true; // <= } return true; }
تبدأ الدورة وعند أول تكرار لها. ربما هذا كان المقصود ، ولكن بعد ذلك يمكن حذف الدورة.
تجاوز حدود مجموعة
V557 مصفوفة غير ممكنة. قد تصل قيمة مؤشر البايتات -1 إلى -1. network.c 2570
static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcname, struct lxc_netdev *netdev, pid_t pid, unsigned int hooks_version) { int bytes; char buffer[PATH_MAX] = {0}; .... bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX); if (bytes < 0) { SYSERROR("Failed to read from pipe file descriptor"); close(pipefd[0]); } else { buffer[bytes - 1] = '\0'; } .... }
تتم قراءة بايت من الإخراج في المخزن المؤقت. في حالة حدوث خطأ ،
ستُرجع الدالة
lxc_read_nointr قيمة سالبة. إذا سارت الأمور على ما يرام ، فسيتم كتابة المحطة الخالية باعتبارها العنصر الأخير. ومع ذلك ، إذا تمت قراءة 0 بايت ، فسيخرج المخزن المؤقت من الحدود ، مما يؤدي إلى سلوك غير محدد.
أصدر المحلل تحذيرا مماثلا آخر:
- V557 مصفوفة غير ممكنة. قد تصل قيمة مؤشر البايتات -1 إلى -1. network.c 2725
تجاوز سعة المخزن المؤقت
V576 تنسيق غير صحيح. النظر في التحقق من الوسيطة الفعلية الثالثة للدالة 'sscanf'. من الخطير استخدام محددات السلسلة دون تحديد مواصفات العرض. تجاوز سعة المخزن المؤقت أمر ممكن. lxc_unshare.c 205
static bool lookup_user(const char *oparg, uid_t *uid) { char name[PATH_MAX]; .... if (sscanf(oparg, "%u", uid) < 1) { if (sscanf(oparg, "%s", name) < 1)
قد يكون استخدام
sscanf في هذه الحالة أمرًا خطيرًا ، لأنه إذا كان طول المخزن المؤقت لـ
oparq أكبر من طول المخزن المؤقت
للاسم ، فسوف ينتقل إلى الخارج عند تكوين المخزن المؤقت
للاسم .
استنتاج
كما رأينا ، يعد إعداد فحص ثابت لمحلل الكود لمشروعنا في السحابة مهمة بسيطة إلى حد ما. للقيام بذلك ، تحتاج فقط إلى إضافة ملف واحد إلى المستودع وقضاء الحد الأدنى من الوقت في إعداد نظام CI. نتيجة لذلك ، نحصل على أداة تتيح لك تحديد الشفرة الإشكالية في مرحلة الكتابة ، ولا تسمح للأخطاء بالوصول إلى المراحل التالية من الاختبار ، حيث يستغرق تصحيحها مزيدًا من الوقت والموارد.
بالطبع ، لا يقتصر استخدام PVS-Studio مع المنصات السحابية على Travis CI. قياسًا على الطريقة الموضحة في المقالة ، مع الحد الأدنى من الاختلافات ، يمكن دمج تحليل PVS-Studio مع حلول CI الشائعة الأخرى المستندة إلى مجموعة النظراء ، مثل CircleCI و GitLab ، إلخ.
روابط مفيدة
- يمكن العثور على معلومات إضافية حول إطلاق PVS-Studio على نظامي التشغيل Linux و MacOS هنا .
- يمكنك أن تقرأ عن إنشاء وتكوين واستخدام الحاويات مع محلل ثابت PVS-Studio المثبت هنا .
- وثائق TravisCI .

إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط الخاص بالترجمة: Oleg Andreev.
PVS-Studio في السحب - تحليل التحليل على ترافيس آي