- функциональные спецификации поведения

Карта неточно анализируемая функция к стандартной функции для точного анализа

Синтаксис

-function-behavior-specifications file_path

Описание

-function-behavior-specifications file_path задает путь к XML-файлу. Можно использовать этот XML-файл, чтобы сопоставить некоторые функции к соответствующим стандартным функциям, которые распознает Polyspace®. Если при запуске верификацию из командной строки, file_path является абсолютным путем или путем относительно папки, от которой вы запускаете команду. Если при запуске верификацию от пользовательского интерфейса, file_path является абсолютным путем.

Если при запуске анализ от пользовательского интерфейса (только десктопные решения Polyspace) на панели Configuration, можно ввести эту опцию в поле Other. Смотрите Other.

Используя опцию для улучшения точности

Этот раздел применяется только к анализу Программы автоматического доказательства Кода.

Используйте эту опцию, чтобы сократить количество оранжевых проверок от неточного анализа вашей функции. Иногда, верификация не анализирует определенные виды функций точно из-за свойственных ограничений в статической верификации. В тех случаях, если вы находите стандартную функцию, которая является близким аналогом вашей функции, используйте это отображение. Хотя ваша функция сама не анализируется, анализ более точен в местоположениях, где вы вызываете функцию. Например, если верификация не может анализировать ваш функциональный cos32 точно и рассматривает полный спектр для его возвращаемого значения, сопоставьте его с функцией cos для возвращаемого значения в [-1,1].

Верификация игнорирует тело вашей функции. Однако верификация эмулирует ваше функциональное поведение следующими способами:

  • Верификация принимает те же возвращаемые значения для вашей функции как стандартная функция.

    Например, если вы сопоставляете свой функциональный cos32 со стандартной функцией cos, верификация принимает, что cos32 возвращает значения в [-1,1].

  • Верификация проверяет на те же проблемы, как она сверяется со стандартной функцией.

    Например, если вы сопоставляете свой функциональный acos32 со стандартной функцией acos,  проверка Invalid use of standard library routine определяет, находится ли аргумент acos32 в [-1,1].

function-behavior-specifications-sample.xml файла примера показывает функции, что можно сопоставить с. Файл находится в polyspaceroot\polyspace\verifier\cxx\, где polyspaceroot является папкой установки Polyspace. Функции, которые можно сопоставить, чтобы включать:

  • Стандартные библиотечные функции от math.h.

  • Управление памятью функционирует от string.h.

  • __ps_meminit: функционально-специализированное к Polyspace, который инициализирует область памяти.

    Иногда, верификация не распознает, что ваша инициализация памяти функционирует, и производит оранжевый Non-initialized local variable, проверяют переменную, которую вы инициализировали через эту функцию. Если вы знаете, что ваша функция инициализации памяти инициализирует переменную через свой адрес, сопоставьте свою функцию с __ps_meminit. Проверка становится зеленой.

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

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

    В коде, сгенерированном из моделей, верификация по умолчанию делает это предположение для функций интерполяционной таблицы. Чтобы идентифицировать, использует ли интерполяционная таблица линейную интерполяцию и никакую экстраполяцию, верификация использует имена функций. Используйте отображение только для рукописных функций, например, функций в Блоке s-function C/C++. Имена тех функций не следуют определенным соглашениям. Необходимо явным образом задать их.

Используя опцию для обнаружения параллелизма

Этот раздел применяется и к Средству поиска Ошибки и к анализу Программы автоматического доказательства Кода.

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

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

Чтобы найти, какие многозадачные примитивы могут быть автоматически обнаружены, смотрите Автоматическое обнаружение Создания Потока и Критического Раздела в Polyspace.

Примеры

Задайте отображение со стандартной функцией

Можно адаптировать демонстрационный XML-файл отображения, которому предоставляют установку Polyspace, и сопоставить функцию со стандартной функцией.

Предположим, что верификация по умолчанию производит оранжевый User assertion, проверяют этот код:

double x = acos32(1.0) ;  
assert(x <= 2.0);
Предположим, что вы знаете, что функциональный acos32 ведет себя как функциональный acos, и возвращаемое значение 0. Вы ожидаете, что проверка на операторе assert будет зеленой. Однако верификация полагает, что acos32 возвращает любое значение в области значений типа double, потому что acos32 точно не анализируется. Проверка является оранжевой. Сопоставлять ваш функциональный acos32 с acos:

  1. Скопируйте файл function-behavior-specifications-sample.xml от polyspaceroot\polyspace\verifier\cxx\ до другого местоположения, например, "C:\Polyspace_projects\Common\Config_files". Измените полномочия записи на файле.

  2. Чтобы сопоставить вашу функцию со стандартной функцией, измените содержимое XML-файла. Чтобы сопоставить ваш функциональный acos32 со стандартной библиотечной функцией acos, измените следующий код:

    <function name="my_lib_cos" std="acos"> </function>
    К:
    <function name="acos32" std="acos"> </function>

  3. Задайте местоположение файла для верификации:

    • Программа автоматического доказательства кода:

      polyspace-code-prover -function-behavior-specifications "C:\Polyspace_projects\Common\Config_files\function-behavior-specifications-sample.xml"
    • Сервер программы автоматического доказательства кода:

      polyspace-code-prover-server -function-behavior-specifications "C:\Polyspace_projects\Common\Config_files\function-behavior-specifications-sample.xml"

Задайте отображение со стандартной функцией с переотображением аргумента

Иногда, аргументы вашей функции не сопоставляют непосредственный с аргументами стандартной функции. В тех случаях повторно сопоставьте свой аргумент функции с аргументом стандартной функции. Например:

  • __ps_lookup_table_clip:

    Это функционально-специализированное к Polyspace берет только массив интерполяционной таблицы в качестве аргумента и возвращает значения в области значений интерполяционной таблицы. Ваша интерполяционная таблица функциональная сила имеет дополнительные аргументы помимо самого массива интерполяционной таблицы. В этом случае используйте переотображение аргумента, чтобы задать, какой аргумент вашей функции является массивом интерполяционной таблицы.

    Например, предположите, что функциональный my_lookup_table имеет следующее объявление:

    double my_lookup_table(double u0, const real_T *table,
                                         const double *bp0);
    Второй аргумент вашего функционального my_lookup_table является массивом интерполяционной таблицы. В файле function-behavior-specifications-sample.xml добавьте этот код:
    <function name="my_lookup_table" std="__ps_lookup_table_clip">
        <mapping std_arg="1" arg="2"></mapping>
    </function>

    Когда вы вызываете функцию:

    res = my_lookup_table(u, table10, bp);
    Верификация интерпретирует вызов как:
    res =__ps_lookup_table_clip(table10);
    Верификация принимает, что значение res находится в области значений значений в table10.

  • __ps_meminit:

    Это функционально-специализированное к Polyspace берет адрес памяти в качестве первого аргумента и многие байты в качестве второго аргумента. Функция принимает, что байты в памяти, начинающей с адреса памяти, инициализируются с допустимым значением. Ваша инициализация памяти функциональная сила имеет дополнительные аргументы. В этом случае используйте переотображение аргумента, чтобы задать, какой аргумент вашей функции является начальным адресом и какой аргумент является количеством байтов.

    Например, предположите, что функциональный my_meminit имеет следующее объявление:

         void my_meminit(enum InitKind k, void* dest, int is_aligned, unsigned int size);
    Второй аргумент вашей функции является начальным адресом, и четвертый аргумент является количеством байтов. В файле function-behavior-specifications-sample.xml добавьте этот код:
    <function name="my_meminit" std="__ps_meminit">
        <mapping std_arg="1" arg="2"></mapping>
        <mapping std_arg="2" arg="4"></mapping>
    </function>

    Когда вы вызываете функцию:

    my_meminit(INIT_START_BY_END, &buffer, 0, sizeof(buffer));
    Верификация интерпретирует вызов как:
    __ps_meminit(&buffer, sizeof(buffer));
    Верификация принимает, что количество sizeof(buffer) байтов, начинающих с &buffer, инициализируется.

  • memset: Переменное количество аргументов.

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

    void* my_memset(void*, int, size_t, ...)
    Чтобы сопоставить функцию с функцией memset, используйте следующее отображение:
    <function name="my_memset" std="memset">
        <mapping std_arg="1" arg="1"></mapping>
        <mapping std_arg="2" arg="2"></mapping>
        <mapping std_arg="3" arg="3"></mapping>
    </function>

Эффект отображения на точности

Эти примеры показывают результат отображения определенных функций к стандартным функциям:

  • my_acosacos:

    Если вы используете отображение, проверка User assertion становится зеленой. Верификация принимает, что возвращаемое значение my_acos 0.

    • Перед отображением:

      double x = my_acos(1.0);  
      assert(x <= 2.0);

    • Отображение спецификации:

      <function name="my_acos" std="acos">
      </function>

    • После отображения:

      double x = my_acos(1.0);  
      assert(x <= 2.0);

  • my_sqrtsqrt:

    Если вы используете отображение, проверка Invalid use of standard library routine покраснела. В противном случае верификация не проверяет, является ли аргумент my_sqrt неотрицательным.

    • Перед отображением:

      res = my_sqrt(-1.0);

    • Отображение спецификации:

      <function name="my_sqrt" std="sqrt"> 
      </function>

    • После отображения:

      res = my_sqrt(-1.0);

  • my_lookup_table (аргумент 2) →__ps_lookup_table_clip (аргумент 1):

    Если вы используете отображение, проверка User assertion становится зеленой. Верификация принимает, что возвращаемым значением my_lookup_table является в области значений массива интерполяционной таблицы table.

    • Перед отображением:

      double table[3] = {1.1, 2.2, 3.3}
      .
      .
      double res = my_lookup_table(u, table, bp);
      assert(res >= 1.1 && res <= 3.3);

    • Отображение спецификации:

      <function name="my_lookup_table" std="__ps_lookup_table_clip">
          <mapping std_arg="1" arg="2"></mapping>
      </function>

    • После отображения:

      double table[3] = {1.1, 2.2, 3.3}
      .
      .
      res_real = my_lookup_table(u, table9, bp);
      assert(res_real >= 1.1 && res_real <= 3.3);

  • my_meminit__ps_meminit:

    Если вы используете отображение, проверка Non-initialized local variable становится зеленой. Верификация принимает, что все поля структуры x инициализируются с допустимыми значениями.

    • Перед отображением:

      struct X {
        int field1 ;
        int field2 ;
      };
      .
      .
      struct X x;
      my_meminit(&x, sizeof(struct X));
      return x.field1;

    • Отображение спецификации:

      <function name="my_meminit" std="__ps_meminit">
           <mapping std_arg="1" arg="1"></mapping>
           <mapping std_arg="2" arg="2"></mapping>
      </function>

    • После отображения:

      struct X {
        int field1 ;
        int field2 ;
      };
      .
      .
      struct X x;
      my_meminit(&x, sizeof(struct X));
      return x.field1;

  • my_meminit__ps_meminit:

    Если вы используете отображение, проверка Non-initialized local variable покраснела. Верификация принимает, что только поле field1 структуры x инициализируется с допустимыми значениями.

    • Перед отображением:

      struct X {
        int field1 ;
        int field2 ;
      };
      .
      .
      struct X x;
      my_meminit(&x, sizeof(int));
      return x.field2;

    • Отображение спецификации:

      <function name="my_meminit" std="__ps_meminit">
      </function>

    • После отображения:

      struct X {
        int field1 ;
        int field2 ;
      };
      .
      .
      struct X x;
      my_meminit(&x, sizeof(int));
      return x.field2;

Эффект отображения на обнаружении параллелизма

В этом примере поддержка Polyspace автоматического обнаружения параллелизма расширена путем отображения неподдерживаемых функций с поддерживаемыми функциями Pthreads.

  • Функция создания потока: createTaskpthread_create

  • Функция, которая начинает критический раздел: takeLockpthread_mutex_lock

  • Функция, которая заканчивает критический раздел: releaseLockpthread_mutex_unlock

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

  • Перед отображением:

    Анализ не обнаруживает гонку данных на var2.

    typedef void* (*FUNT) (void*);
    
    extern int takeLock(int* t);
    extern int releaseLock(int* t);
    // First argument is the function, second the id
    extern int createTask(FUNT,int*,int*,void*);
    
    int t_id1,t_id2;
    int lock;
    
    int var1; 
    int var2; 
    
    void* task1(void* a) {
        takeLock(&lock);
        var1++;
        var2++;
        releaseLock(&lock);
        return 0;
    }
    
    void* task2(void* a) {
        takeLock(&lock);
        var1++;
        releaseLock(&lock);
        var2++;
        return 0;
    }
    
    void main() {
        createTask(task1,&t_id1,0,0);
        createTask(task2,&t_id2,0,0);
    }
    

  • Отображение спецификации:

    На основе номера и типа параметров функционального createTask, удобно сопоставить createTask с функцией создания потока pthread_create. Другие доступные альтернативы, createThread или OSTaskCreate, имеют различные типы аргумента.

    Сопоставляя с pthread_create, переотображение аргумента требуется, потому что аргументы не соответствуют точно. Поток запускается, стандартная программа является третьим аргументом pthread_create, но первым аргументом createTask.

    <function name="createTask" std="pthread_create" >
        <mapping std_arg="1" arg="2"></mapping>
        <mapping std_arg="3" arg="1"></mapping>
        <mapping std_arg="2" arg="3"></mapping>
        <mapping std_arg="4" arg="4"></mapping>
    </function>
    <function name="takeLock" std="pthread_mutex_lock" >
    </function>
    <function name="releaseLock" std="pthread_mutex_unlock" >
    </function>

    Для списка поддерживаемых функций, с которыми можно сопоставить, смотрите, что демонстрационное сопоставляет файл function-behavior-specifications-sample.xml в polyspaceroot\polyspace\verifier\cxx\. polyspaceroot является папкой установки Polyspace, такой как C:\Program Files\Polyspace\R2019a. См. также Автоматическое обнаружение Создания Потока и Критического Раздела в Polyspace.

  • После отображения:

    Анализ обнаруживает гонку данных на var2.

    typedef void* (*FUNT) (void*);
    
    extern int takeLock(int* t);
    extern int releaseLock(int* t);
    // First argument is the function, second the id
    extern int createTask(FUNT,int*,int*,void*);
    
    int t_id1,t_id2;
    int lock;
    
    int var1; 
    int var2; 
    
    void* task1(void* a) {
        takeLock(&lock);
        var1++;
        var2++;
        releaseLock(&lock);
        return 0;
    }
    
    void* task2(void* a) {
        takeLock(&lock);
        var1++;
        releaseLock(&lock);
        var2++;
        return 0;
    }
    
    void main() {
        createTask(task1,&t_id1,0,0);
        createTask(task2,&t_id2,0,0);
    }
    

Введенный в R2017b