Предположения о заблокированных функциях

Функции тупиков верификации, которые не заданы в вашем исходном коде или что вы принимаете решение заблокировать. Для заблокированной функции:

  • Верификация делает определенные предположения о функциональном возвращаемом значении и других побочных эффектах функции.

    Можно подстроить предположения путем определения ограничений.

  • Верификация игнорирует тело функции, если это существует. Операции в теле функции не проверяются на ошибки времени выполнения.

Если верификация тела функции неточна и вызывает много оранжевых проверок, когда вы вызываете функцию, можно принять решение заблокировать функцию. Чтобы сократить количество оранжевых проверок, вы блокируете функцию, и затем ограничиваете возвращаемое значение функции и задаете другие побочные эффекты.

К интерфейсным функциям можно использовать эти опции:

Если вы используете право преимущественной покупки, чтобы заблокировать функцию, вы ограничиваете функциональное возвращаемое значение и моделируете другие побочные эффекты путем определения ограничений. Если вы хотите задать ограничения, более мелкомодульные, чем те доступные через ограничительный интерфейс спецификации Polyspace, задайте свои собственные тупики. Если вы используете другие опции для интерфейсных функций, само программное обеспечение ограничивает функциональное возвращаемое значение и моделирует его побочные эффекты соответственно.

Верификация делает следующие предположения об аргументах заблокированных функций.

Функциональное возвращаемое значение

Предположения

Верификация принимает что:

  • Переменная, возвращенная функцией, берет полный спектр значений, позволенных его типом данных.

    Если функция возвращает enum переменная, значение переменных находится в области значений перечисления. Например, если enum тип принимает, значения {0,5,-1,32} и заблокированная функция имеют тот тип возврата, верификация принимает, что функция возвращает значения в области значений-1.. 32.

  • Если функция возвращает указатель, указатель не является ПУСТЫМ и безопасным разыменовать. Указатель не указывает на динамически выделенную память или другую переменную в вашем коде.

  • C++ определенные предположения: оператор new возвращает выделенную память. Операторы, такие как operator=оператор + =оператор--(снабженная префиксом версия) или operator<< возвращается:

    • Ссылка на *this, если оператор является частью определения класса.

      Например, если оператор задан как:

      class X {
        X& operator=(const X& arg) ;
      };
      
      Это возвращает ссылку на *this (объект, который вызывает оператор). Объект, который вызывает оператор или его элементы данных, имеет полный спектр значений, позволенных их типом.

    • Первый аргумент, если оператор не является частью определения класса.

      Например, если оператор задан как:

      X& operator+=(X& arg1, const X& arg2) ;
      
      Это возвращает arg1. Объект, что arg1 относится к, или его элементы данных имеют полный спектр значений, позволенных их типом.

    Функции объявляются с __declspec(no_return) (Визуальный Studio®) или __attribute__ ((noreturn)) (GCC) не возвращаются.

Как изменить предположения

Можно изменить предположения по умолчанию о функциональном возвращаемом значении.

  • Если функция возвращает неуказательную переменную, можно ограничить ее область значений. Используйте опцию Constraint setup (-data-range-specifications).

    Через ограничительный интерфейс спецификации можно указать абсолютный диапазон [minMax ]. Чтобы задать более сложные ограничения, запишите функциональный тупик.

    Например, неопределенная функция имеет прототип:

    int func(int ll, int ul);
    Предположим, что вы знаете, что функциональное возвращаемое значение находится между первым и вторыми аргументами. Однако программное обеспечение принимает полный спектр для возвращаемого значения, потому что функция не задана. Чтобы смоделировать поведение, что вы хотите и уменьшаете оранжевые проверки от неточности, запишите функциональный тупик можно следующим образом:
    int func(int ll, int ul) {
         int ret;
         assert(ret>=ll && ret <=ul);
         return ret;
    }
    Обеспечьте функциональный тупик в отдельном файле для верификации. Верификация использует ваш тупик в качестве функционального определения.

    Если определение func существует в вашем коде, и вы хотите заменить определение, потому что верификация тела функции неточна, встройте фактическое определение и тупик в #ifdef оператор:

    #ifdef POLYSPACE
    int func(int ll, int ul) {
         int ret;
         assert(ret>=ll && ret <=ul);
         return ret;
    }
    #else
    int func(int ll, int ul) {
        /*Your function body */ 
    }
    #endif
    Задайте макро-POLYSPACE при помощи опции Preprocessor definitions (-D). Верификация использует ваш тупик вместо фактического функционального определения.

  • Если функция возвращает переменную указателя, можно указать, что указателем может быть NULL.

Аргументы функции, Которые являются Указателями

Предположения

Верификация принимает что:

  • Если аргумент является указателем, функция может записать любое значение в объект, на который указывает указатель. Область значений значений ограничивается одним только типом данных аргумента.

    Например, в этом примере, верификация принимает что заблокированный функциональный stubbedFunc записи любое возможное значение к val. Поэтому утверждение является оранжевым.

    void stubbedFunc(int*);
    
    void main() {
        int val=0, *ptr=&val;
        stubbedFunc(ptr);
        assert(val==0);
    }

  • Если аргумент является указателем на структуру, функция может записать любое значение в поля структуры. Область значений значений ограничивается только по условию тип полей.

    В Коде С++ только первые элементы данных уровня структуры могут быть записаны через указатель на структуру. Например, в этом примере, анализ имеет знание какой pb->j точки к, но не, что pb->pa->i точки к. Так, после вызова Foo, b.j появляется, как инициализировано, но a.i не инициализируется.

    struct A {
       int i;
    };
     
    struct B {
       A* pa;
       int j;
    };
     
    void Foo(B*);
     
    void main() {
        A a;
        B b;
        b.pa = &a;
        Foo(&b); 
        int var1 = b.j;
        int var2 = a.i;
    }

  • Если аргумент является указателем на другой указатель, функция может записать любое значение в объект, который второй указатель указывает на (Только код С). Это предположение продолжается к произвольным глубинам иерархии указателя.

    Например, предположите что указатель **pp точки к другому указателю *p, который указывает на int переменная var. Если заблокированная функция берет **p в качестве аргумента верификация принимает что, следуя за вызовом функции, var имеет любой int значение. *p может указать на где угодно в выделенной памяти или может указать на var но не указывает на другую переменную в коде.

  • Если аргумент является указателем функции, функция, на которую он указывает, вызвана (Только код С).

    Например, в этом примере, заблокированном функциональном stubbedFunc берет указатель функции funcPtr в качестве аргумента. funcPtr точки к func, который называется, когда вы вызываете stubbedFunc.

    typedef int (*typeFuncPtr) (int);
    
    int func(int x){
      	return x;
    }
    
    int stubbedFunc(typeFuncPtr);
    
    void main() {
        typeFuncPtr funcPtr = (typeFuncPtr)(&func);
        int result = stubbedFunc(funcPtr);
    }
    Если указатель функции берет другой указатель функции в качестве аргумента, функция, на которую указывает второй указатель функции, заблокирована.

Как изменить предположения

Можно ограничить область значений аргумента, который передается ссылкой. Используйте опцию Constraint setup (-data-range-specifications).

Через ограничительный интерфейс спецификации можно указать абсолютный диапазон [minMax ]. Чтобы задать более сложные ограничения, запишите функциональный тупик.

Например, неопределенная функция имеет прототип:

void func(int *x, int ll, int ul);
Предположим, что вы знаете что значение, записанное в x находится между вторым и третьими аргументами. Однако программное обеспечение принимает полный спектр для значения *x потому что функция не задана. Чтобы смоделировать поведение, что вы хотите и уменьшаете оранжевые проверки от неточности, запишите функциональный тупик можно следующим образом:
void func(int *x, int ll, int ul) {
     assert(*x>=ll && *x <=ul);
}
Обеспечьте функциональный тупик в отдельном файле для верификации. Верификация использует ваш тупик в качестве функционального определения.

Если определение func существует в вашем коде, и вы хотите заменить определение, потому что верификация тела функции неточна, встройте фактическое определение и тупик в #ifdef оператор:

#ifdef POLYSPACE
void func(int *x, int ll, int ul) {
     assert(*x>=ll && *x <=ul);
}
#else
void func(int *x, int ll, int ul) {
     /* Your function body */
}
#endif
Задайте макро-POLYSPACE при помощи опции Preprocessor definitions (-D). Верификация использует ваш тупик вместо фактического функционального определения.

Глобальные переменные

Предположения

Верификация принимает, что функциональный тупик не изменяет глобальные переменные.

Как изменить предположения

Чтобы смоделировать операции записи на глобальной переменной, запишите функциональный тупик.

Например, неопределенная функция имеет прототип:

void func(void);
Предположим, что вы знаете, что функция пишет значение 0 или 1 к глобальной переменной glob. Чтобы смоделировать поведение, которое вы хотите, запишите функциональный тупик можно следующим образом:
void func(void) {
     volatile int randomVal;
     if(randomVal)
          glob = 0;
     else
          glob = 1;
}
Обеспечьте функциональный тупик в отдельном файле для верификации. Верификация использует ваш тупик в качестве функционального определения.

Если определение func существует в вашем коде, и вы хотите заменить определение, потому что верификация тела функции неточна, встройте фактическое определение и тупик в #ifdef оператор можно следующим образом:

#ifdef POLYSPACE
void func(void) {
     volatile int randomVal;
     if(randomVal)
          glob = 0;
     else
          glob = 1;
}
#else
void func(void) {
     /* Your function body */
}
#endif
Задайте макро-POLYSPACE использование опции Preprocessor definitions (-D). Верификация использует ваш тупик вместо фактического функционального определения.