Frama-C中止无效的用户输入

时间:2018-04-24 20:02:49

标签: frama-c

我是Frama-c的新手,当我尝试打开C源文件时,我遇到了一个问题。

The error shows as 
"fatal error: event.h: No such file or directory. Compilation terminated".

[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing)

[kernel] Parsing WorkSpace/bipbuffer.c (with preprocessing)

[kernel] user error: failed to run: gcc -E -C -I.  -dD -D__FRAMAC__  -nostdinc -D__FC_MACHDEP_X86_32 -I/usr/share/frama-c/libc -o '/tmp/bipbuffer.ce6d077.i' '/home/xxx/WorkSpace/bipbuffer.c'    you may set the CPP environment variable to select the proper preprocessor command or use the option "-cpp-command".

[kernel] user error: stopping on file "/home/xxx/WorkSpace/bipbuffer.c" that has errors. Add'-kernel-msg-key pp' for preprocessing command.

所以基本上我试图打开一个C源文件,但它返回一个这样的错误。我也尝试过其他非常简单的C文件,比如hello world和其他切片函数,效果很好。

我认为这是因为我没有'event.h'的依赖项,但在安装libevent依赖项后它仍然会返回这些错误。我不确定是否需要手动为frama-c

设置依赖关系的路径

以下是我要打开的C文件(源链接:https://memcached.org/)的一部分:

#include "stdio.h"
#include <stdlib.h>

/* for memcpy */
#include <string.h>

#include "bipbuffer.h"

static size_t bipbuf_sizeof(const unsigned int size)
{
    return sizeof(bipbuf_t) + size;
}

int bipbuf_unused(const bipbuf_t* me)
{
    if (1 == me->b_inuse)
        /* distance between region B and region A */
        return me->a_start - me->b_end;
    else
        return me->size - me->a_end;
}
......

谢谢,

3 个答案:

答案 0 :(得分:2)

使用C源代码的编译器和其他工具需要知道在哪里找到头文件。它们有一些自动显示的标准位置,但Frama-C比普通编译器中的(和不同的)更少。

您需要找出安装event.h的位置,然后将-cpp-extra-args "-I /path/to/directory/"之类的内容传递给Frama-C。仅传递目录名称,不包括名称event.h本身。

答案 1 :(得分:2)

除了Isabelle Newbie的回答之外,我还要指出,其版本为recently announced的Floma-C的Chlorine版本提供了一个新选项-json-compilation-database,试图阅读要从a compilation database传递给预处理器的参数。

这样的数据库可以由cmake直接生成,但是有基于make的项目的解决方案,例如你引用的项目,特别是bear,它拦截了发起的命令通过make来构建数据库。

答案 2 :(得分:1)

此处详细介绍了如何继续使用Frama-C 17 Chlorine的新-json-compilation-database选项,以及额外的脚本list_files.py(不在测试版中,但是将在最终的17版本中提供,可以下载here):

  1. 使用Frama-C获取要分析的源文件,运行./configure,如果可能,尝试禁用外部库中的可选依赖项;例如,一些代码库包括基于库/系统功能的可用性的可选依赖项,但具有后备选项(使用标准C库或POSIX函数)。你给Frama-C的次数越多,分析它的机会就越大,所以如果这些外部库不是必需的,排除它们可能有助于获得更多的东西。代码,应该有所帮助。这通常在config.h文件中以通常名为HAVE_*的宏中可见。

  2. 编译并安装Build EAR或一些等效工具以获取compile_commands.json文件。

  3. 运行bear make(或带有标记CMAKE_EXPORT_COMPILE_COMMANDS的cmake)以获取compile_commands.json文件。

  4. 在包含list_files.py的目录中运行上述compile_commands.json,以获取编译期间使用的C源列表。

  5. 运行Frama-C(17 Chlorine或更新版本),为其提供上一步中找到的源列表,以及选项-json-compilation-database .来解析compile_commands.json,并希望获得适当的预处理标志。

  6. 理想情况下,这应该足够了,但在实践中,这已经不够了。特别是由于存在外部库和非C99,非POSIX功能,总是需要以下步骤。

    6。包含外部库

    在此步骤中,Frama-C会抱怨缺少event.h。您必须自己包含此库的标题。 注意:由于多个特定于体系结构的定义,尤其是/usr/include等文件,直接从bits/*.h复制标题 可能无法正常工作。

    相反,请考虑下载外部库并准备它们(例如至少运行./configure)。然后通过-cpp-extra-args="-I <path/to/your/sources/for/libevent.h>/include"手动添加额外的include目录。

    7。包含缺少的非POSIX标头

    可能缺少一些其他标头,特别是GNU或BSD特定的来源(例如sysexits.h)。获取这些标头并在必要时添加它们。这种情况下的错误消息来自预处理器(gcc),与此类似:

    memcached.c:51:10: fatal error: sysexits.h: No such file or directory
     #include <sysexits.h>
              ^~~~~~~~~~~~
    compilation terminated.
    

    8。缺少非POSIX类型和常量的定义

    此时,所有必需的标头都应该可用,但使用Frama-C进行解析可能仍会失败。这是由于使用了非POSIX类型定义(例如caddr_tstruct ling),非POSIX常量(例如MAXPATHLENSOCK_NONBLOCKNI_MAXSERV) 。错误消息通常类似于以下内容:

    [kernel] memcached.c:3261: Failure: Cannot resolve variable MAXPATHLEN
    

    通过点击/usr/include中可用的内容,常常很容易手动提供常量。

    另一方面,

    类型定义可能需要在正确的位置进行一些复制粘贴,特别是如果它们依赖于其他也缺少的类型。这一步很难实现自动化,但一旦习惯了某些特定的错误信息,就会相对简单。

    例如,以下错误消息与缺少的类型定义(caddr_t)相关:

    [kernel] Parsing memcached.c (with preprocessing)
    [kernel] memcached.c:1074: 
      syntax error:
      Location: line 1074, between columns 38 and 47, before or at token: c
      1072          *hdr++ = 0;
      1073          *hdr++ = 0;
      1074          assert((void *) hdr == (caddr_t)c->msglist[i].msg_iov[0].iov_base + UDP_HEADER_SIZE);
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      1075      }
      1076
    

    请注意,c之前的令牌为(caddr_t),从未定义过(通常定义为void *char *)。

    以下错误消息与不完整的类型有关,即某个地方使用但未定义的struct

    [kernel] memcached.c:5811: User Error: 
      variable `ling' has initializer but incomplete type
    

    这意味着从未定义变量ling的类型,即struct linger(非POSIX)。在这种情况下,我们可以从/usr/include/bits/socket.h

    复制它
    struct linger
      {
        int l_onoff;            /* Nonzero to linger on close.  */
        int l_linger;           /* Time to linger.  */
      };
    

    注意:如果Frama-C的libc中缺少POSIX常量/定义,请考虑通知其开发人员,或在Frama-C的Github中提出pull请求。 < / p>

    9。修复不兼容和缺失的函数原型

    解析可能在上一步之后成功,但由于功能原型不兼容,它可能仍然失败。例如,您可能会得到:

    [kernel] User Error: Incompatible declaration for usleep:
      different integer types int and unsigned int
      First declaration was at assoc.c:238
      Current declaration is at items.c:1573
    

    这是先前发出警告的结果:

    [kernel:typing:implicit-function-declaration] slabs.c:1150: Warning: 
      Calling undeclared function usleep. Old style K&R code?
    

    这意味着函数usleep被调用,但它没有原型,因此Frama-C使用了&#34;隐式int&#34;的前C99约定:它生成了这样的原型,但后来在代码中,找到了usleep的实际声明,其类型为 not int。因此错误。

    为防止出现这种情况,您需要确保正确包含usleep原型。由于 POSIX.1-2008,您需要定义/取消定义相应的宏(请参阅unistd.h),或添加自己的原型。

    最后,这应该允许Frama-C解析文件并构建AST。

    然而,还有几个缺少的原型;我们很幸运,没有与实际声明相冲突。理想情况下,当没有更多消息(例如implicit-function-declaration和类似警告)时,您将考虑解析阶段。

    memcached中缺少的一些原型(例如getsubopt)是POSIX,应该集成到Frama-C的标准库中。其他人可能会成为非标准存根的小型库的一部分,可以重复用于其他软件。

    为未来重用提供结果

    成功完成此类开源库的解析阶段足以考虑将它们集成到this repository of open source case studies中,以便将来的用户可以开始他们的分析而无需重做所有这些步骤。 (存储库面向Eva,但不仅限于:解析对所有Frama-C插件都很有用。