Splint无法检查指向堆栈变量的指针的maxSet

时间:2015-03-27 14:57:35

标签: c lint splint

我有一个程序可以执行以下操作:

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

int f(char *result)
{
    if (result != NULL)
    {
        *result = 'a';
    }
    return 0;
}

int main ()
{
    char s = 0;
    (void)f(&s);
    printf("f gave %c\n", s);
    return 1;
}

我传递一个指向函数的指针,取消引用它并存储一些东西。 Splint报告说它无法解析f:

中的maxSet(result) >= 0约束
test.c: (in function f)
test.c:8:9: Possible out-of-bounds store: *result
    Unable to resolve constraint:
    requires maxSet(result @ test.c:8:10) >= 0
     needed to satisfy precondition:
    requires maxSet(result @ test.c:8:10) >= 0
  A memory write may write to an address beyond the allocated buffer. (Use
  -boundswrite to inhibit warning)

&s指向堆栈上的单个字符,因此它应该具有1的maxSet而不添加任何注释。为什么Splint抱怨?

1 个答案:

答案 0 :(得分:1)

据我所知,splint报告它无法使用任何不可验证地指向实际缓冲区或数组的指针来验证约束。这看起来很奇怪,因为似乎没有理由说它不能处理相当于1的数组的单个变量,但似乎是这样。

例如,使用以下代码:

int main (void)
{
    int a = 5;
    int b[1] = {6};
    int * pa = &a;
    int * pb = b;

    char c = (char) 0;
    char d[1] = {(char) 0};
    char * pc = &c;
    char * pd = d;

    *pa  = 6;       /*  maxSet warning  */
    *pb  = 7;       /*  No warning      */
    *b   = 8;       /*  No warning      */

    *pc = 'b';      /*  maxSet warning  */
    *pd = 'c';      /*  No warning      */
    *d  = 'd';      /*  No warning      */

    return 0;
}

splint给出以下输出:

paul@thoth:~/src/sandbox$ splint -nof +bounds sp.c
Splint 3.1.2 --- 20 Feb 2009

sp.c: (in function main)
sp.c:15:5: Possible out-of-bounds store: *pa
    Unable to resolve constraint:
    requires maxSet(&a @ sp.c:7:16) >= 0
     needed to satisfy precondition:
    requires maxSet(pa @ sp.c:15:6) >= 0
  A memory write may write to an address beyond the allocated buffer. (Use
  -boundswrite to inhibit warning)
sp.c:19:5: Possible out-of-bounds store: *pc
    Unable to resolve constraint:
    requires maxSet(&c @ sp.c:12:17) >= 0
     needed to satisfy precondition:
    requires maxSet(pc @ sp.c:19:6) >= 0

Finished checking --- 2 code warnings
paul@thoth:~/src/sandbox$ 

取消引用指向(一个元素)数组的第一个字符的指针,并取消引用数组名称本身,两者都不会产生错误,但取消引用一个指向单个变量的指针,{{1} }和char。似乎是一种好奇的行为,但它的本质是什么。

顺便说一下,在int函数中,您无法真正推断f()result指向的内容。虽然当你只是孤立地看待这两个函数时,main()显然应该指出什么应该是一个有效的引用,就splint而言,可以对result进行更多的调用。来自其他翻译单元,并且不知道那些案例中f可能指向哪些内容,因此它只需要获取result所带来的信息。本身。

例如,在这里:

f()
由于这个原因,

splint将警告static void f(char * pc) { if ( pc ) { *pc = 'E'; /* maxSet warning */ } } int main(void) { char c[25] = "Oysters and half crowns."; *c = 'U'; /* No warning */ f(c); return 0; } 中的作业,而不是f()中的作业。但是,如果你注释它,那么它有足够的信息来解决它:

main()

但即使在这里,如果您将static void f(char * pc) /*@requires maxSet(pc) >= 0; @*/ { if ( pc ) { *pc = 'E'; /* No warning */ } } int main(void) { char c[25] = "Oysters and half crowns."; *c = 'U'; /* No warning */ f(c); return 0; } 更改为单个c,您也会遇到相同的问题,因为splint无法验证是否满足带注释的约束,因此:

char

给你这个:

static void f(/*@out@*/ char * pc) /*@requires maxSet(pc) >= 0; @*/
{
    if ( pc ) {
        *pc = 'E';      /*  No warning      */
    }
}

int main(void)
{
    char c;
    f(&c);              /*  maxSet warning  */

    return 0;
}