PVS-Studio走向云端-在Travis CI上启动分析

目前,云CI系统是一项非常受欢迎的服务。 在本文中,我们将介绍如何使用PVS-Studio提供的现有工具,以Travis CI服务为例,将源代码分析与Cloud CI平台集成。

图片1


为什么我们要看第三方云而不是自己做? 原因有很多,主要原因是SaaS是一个相当昂贵且困难的过程。 实际上,将PVS-Studio分析与第三方云平台直接集成(无论是CircleCI,Travis CI,GitLab之类的开放平台,还是仅在一个特定公司中使用的某些专业企业解决方案)都是相当简单而琐碎的任务。 也就是说,我们可以说PVS-Studio已经“在云端”可用 。 完全不同的问题是24/7全天候工作的组织和基础设施的提供。 这是完全不同的任务,PVS-Studio没有计划直接提供自己的云平台来在其上运行分析。

有关所用软件的信息


Travis CI是用于构建和测试使用GitHub作为存储的软件的服务。 Travis CI不需要更改程序代码即可使用该服务,所有设置都在存储库根目录中的.travis.yml文件中进行。

我们将把LXC (Linux容器)作为一个测试项目,以使用PVS-Studio进行测试。 它是一个操作系统级虚拟化系统,用于在单个节点上运行Linux操作系统的多个实例。

该项目很小,但足以演示。 cloc命令的输出:
语言能力
档案
空白
评论
代号
ç
124
11937
6758
50836
C / C ++标题
65岁
1117
3676
3774
注意: LXC开发人员已经在使用Travis CI,因此我们将以他们的配置文件为基础并对其进行编辑。

客制化


要开始使用Travis CI,请点击链接并使用Gi​​tHub帐户进行身份验证。

图片17

在打开的窗口中,您需要授权Travis CI。

图片16

授权后,重定向到欢迎页面“第一次来这里? 让您开始吧!” 简要介绍了下一步需要做什么:

  • 激活存储库;
  • 将.travis.yml文件添加到存储库中;
  • 运行第一个版本。

图片18

我们将开始执行这些要点。

要将我们的存储库添加到Travis CI,请通过链接转到配置文件设置,然后单击“激活”按钮。

图片19

单击后,将打开一个窗口,其中包含可供Travis CI应用程序访问的存储库。
注意:要提供对存储库的访问权限,该帐户必须具有该存储库的管理员权限。

图片38

我们选择所需的存储库,单击“批准并安装”按钮确认选择,然后我们将被重定向回配置文件设置页面。

立即创建用于创建分析器许可证文件并发送其报告的变量。 为此,请转到设置页面-所需存储库右侧的“设置”按钮。

图片39

设置窗口将打开。

图片41

设置的简短说明:

  • “常规”部分-设置自动运行任务的触发器;
  • “自动取消”部分-允许您配置自动取消装配;
  • “环境变量”部分-允许您定义包含公共和机密信息(例如凭据,ssh密钥)的环境变量;
  • “ Cron Jobs”部分-设置任务启动时间表。

在“环境变量”部分中,我们创建PVS_USERNAMEPVS_KEY变量,分别包含静态分析器的用户名和许可证密钥。 如果您没有永久性的PVS-Studio许可证,则可以申请试用许可证

图片5

立即创建包含邮箱用户名和密码的变量MAIL_USERMAIL_PASSWORD ,我们将使用它们发送报告。

图片4

启动任务后,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://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 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates 

在构建项目之前,您需要准备环境:

 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包在最后一步发送报告:

 - 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://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 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates 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-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 PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html - 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 

要在容器中运行静态分析器,请首先使用以下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://files.viva64.com/etc/pubkey.txt | sudo apt-key add - \ && wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list \ && apt-get update \ && apt-get install -yqq coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio git libtool autotools-dev automake pkg-config clang make libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates \ && rm -rf /var/lib/apt/lists/* 

在这种情况下,配置文件可能如下所示:

 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--security-opt seccomp:unconfined参数 ,因为ptrace系统调用用于编译跟踪。

我们将配置文件加载到存储库的根目录中,然后看到Travis CI收到有关项目中存在更改的通知,并自动启动了程序集。

可以在控制台中查看有关组装进度和分析仪验证的详细信息。

图片2

测试完成后,我们将在邮件中收到2个字母:一个带有使用gcc构建项目的静态分析结果,第二个带有clang。

简要介绍一下测试结果


总的来说,该项目非常干净,分析仪仅发出24次严重警告和46次平均警告。 为了演示这项工作,请考虑几个有趣的通知:

if中的冗余条件


V590考虑检查'ret!=(-1)&& ret == 1'表达式。 表达式过多或打印错误。 附件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) // <= { found = true; break; } } .... } 

如果ret == 1 ,那么它绝对不等于-1(EOF)。 验证过多, ret!= EOF可以删除。

发出了另外两个警告:

  • V590考虑检查'ret!=(-1)&& ret == 1'表达式。 表达式过多或打印错误。 附件579
  • V590考虑检查'ret!=(-1)&& ret == 1'表达式。 表达式过多或打印错误。 附件c.583

高位丢失


V784位掩码的大小小于第一个操作数的大小。 这将导致丢失更高的位。 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; /* If opt is found in mount_opt, set or clear flags. * Otherwise append it to data. */ for (mo = &mount_opt[0]; mo->name != NULL; mo++) { if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { if (mo->clear) { *flags &= ~mo->flag; // <= } else { *flags |= mo->flag; } return; } } .... } 

在Linux下, long是64位整数变量, mo->标志是32位整数变量。 使用mo->标志作为位掩码将导致丢失32个最高有效位。 在按位求反后,将位掩码隐式转换为64位整数变量。 此掩码的高位将为零。

举例说明:

 unsigned long long x; unsigned y; .... x &= ~y; 

图片3


正确的代码是:

 *flags &= ~(unsigned long)(mo->flag); 

分析仪发出了另一个类似的警告:

  • V784位掩码的大小小于第一个操作数的大小。 这将导致丢失更高的位。 1933年

可疑周期


V612循环内无条件的“返回”。 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。 网络.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函数将返回负值。 如果一切顺利,则将null终端写入最后一个元素。 但是,如果读取0字节,则缓冲区将超出范围,这将导致未定义的行为。

分析仪发出了另一个类似的警告:

  • V557阵列欠载是可能的。 “字节-1”索引的值可能达到-1。 网络.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) { /* not a uid -- perhaps a username */ if (sscanf(oparg, "%s", name) < 1) // <= { free(buf); return false; } .... } .... } 

在这种情况下使用sscanf可能会很危险,因为如果oparq缓冲区的长度大于名称缓冲区的长度,则在形成名称缓冲区时它将消失

结论


如我们所见,在云中为我们的项目设置静态代码分析器检查是一项相当简单的任务。 为此,您只需要向存储库中添加一个文件,并花费最少的时间来设置CI系统。 结果,我们得到了一个工具,该工具使您可以在编写阶段识别出有问题的代码,并且不允许错误进入下一阶段的测试,在该阶段的纠正将花费更多的时间和资源。

当然,结合使用PVS-Studio和云平台不限于Travis CI。 与本文中描述的方法类似,PVS-Studio分析可以与其他流行的基于云的CI解决方案(例如CircleCI,GitLab等)集成在一起,并且差异最小。

有用的链接


  • 可以在此处找到有关在Linux和MacOS上启动PVS-Studio的其他信息。
  • 您可以在此处阅读有关使用已安装的PVS-Studio静态分析器创建,配置和使用容器的信息
  • TravisCI文档



如果您想与讲英语的读者分享这篇文章,请使用翻译链接:Oleg Andreev。 云中的PVS-Studio-在Travis CI上运行分析

Source: https://habr.com/ru/post/zh-CN458072/


All Articles