CERT C: Rec. CON01-C

Получите и выпустите примитивы синхронизации в том же модуле на том же уровне абстракции

Описание

Управляйте определением

Получите и выпустите примитивы синхронизации в том же модуле на том же уровне абстракции. [1]

Примеры

развернуть все

Описание

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

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача, my_task вызывает функцию блокировки my_lock, другие задачи, вызывая my_lock, должна ожидать до вызовов my_task соответствие разблокировало функцию. Polyspace® требует, чтобы и блокировка и разблокировала функции, должен иметь форму void func(void).

Чтобы найти этот дефект, необходимо задать многозадачные опции перед анализом. Чтобы задать эти опции, на панели Configuration, выбирают Multitasking.

Риск

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

Фиксация

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

Смотрите примеры мер ниже. Чтобы избежать проблемы, можно применить практику вызова блокировки и разблокировать функции в том же модуле на том же уровне абстракции. Например, в этом примере, func вызывает блокировку, и разблокируйте функцию на том же уровне, но func2 не делает.

void func() {
  my_lock();
  {
    ...
  }
  my_unlock();
}

void func2() {
  {
   my_lock();
   ...
  }
  my_unlock();
}

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

Пример - пропускающий блокировку



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset(void) 
{
  begin_critical_section();
  global_var = 0;
  end_critical_section();
}

void my_task(void)
{
  global_var += 1;
  end_critical_section();
}

В этом примере, чтобы эмулировать многозадачное поведение, необходимо задать следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
begin_critical_sectionend_critical_section

На командной строке можно использовать следующее:

polyspace-bug-finder
   -entry-points my_task,reset
   -critical-section-begin begin_critical_section:cs1
   -critical-section-end end_critical_section:cs1

Пример имеет две точки входа, my_task и reset. my_task вызывает end_critical_section прежде, чем вызвать begin_critical_section.

Исправление — обеспечивает блокировку

Одно возможное исправление должно вызвать функцию блокировки begin_critical_section перед инструкциями в критическом разделе.



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset(void) 
{
  begin_critical_section();
  global_var = 0;
  end_critical_section();
}

void my_task(void)
{
    begin_critical_section();
    global_var += 1;
    end_critical_section();
}

Пример - привязывает условие



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset() {
    begin_critical_section();
    global_var=0;
    end_critical_section();
}

void my_task(void) {
    int index=0;
    volatile int numCycles;
    
    while(numCycles) {
      if(index%10==0) {
        begin_critical_section();
        global_var ++;  
      }
      end_critical_section(); 
      index++;
    }
}

В этом примере, чтобы эмулировать многозадачное поведение, необходимо задать следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
begin_critical_sectionend_critical_section

На командной строке можно использовать следующее:

polyspace-bug-finder
   -entry-points my_task,reset
   -critical-section-begin begin_critical_section:cs1
   -critical-section-end end_critical_section:cs1

Пример имеет две точки входа, my_task и reset.

В цикле while my_task оставляет критический раздел через вызов end_critical_section();. В итерации цикла while:

  • Если my_task вводит ответвление условия if, критический раздел начинается через вызов begin_critical_section.

  • Если my_task не вводит ответвление условия if и оставляет цикл while, критический раздел не начинается. Поэтому дефект Missing lock происходит.

  • Если my_task не вводит ответвление условия if и продолжается к следующей итерации цикла while, разблокировать функциональный end_critical_section называется снова. Дефект Double unlock происходит.

Поскольку numCycles является переменной volatile, он может принять любое значение. Любой из случаев выше возможен. Поэтому дефект Missing lock и дефект Double unlock появляются на вызове end_critical_section.

Описание

Пропавшие без вести разблокировали, происходит когда:

  • Задача вызывает функцию блокировки.

  • Задача заканчивается без вызова разблокировать функции.

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача, my_task, вызывает функцию блокировки, my_lock, другие задачи, вызывая my_lock должны ожидать до вызовов my_task соответствие разблокировало функцию. Polyspace требует, чтобы и блокировка и разблокировала функции, должен иметь форму void func(void).

Чтобы найти этот дефект, перед анализом, необходимо задать многозадачные опции. На панели Configuration выберите Multitasking.

Риск

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

Фиксация

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

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

Смотрите примеры мер ниже. Чтобы избежать проблемы, можно применить практику вызова блокировки и разблокировать функции в том же модуле на том же уровне абстракции. Например, в этом примере, func вызывает блокировку, и разблокируйте функцию на том же уровне, но func2 не делает.

void func() {
  my_lock();
  {
    ...
  }
  my_unlock();
}

void func2() {
  {
   my_lock();
   ...
  }
  my_unlock();
}

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

Пример - Пропавшие без вести разблокировали



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset() 
{
    begin_critical_section();
    global_var = 0;
    end_critical_section();
}

void my_task(void)
{
    begin_critical_section(); 
    global_var += 1;
}

В этом примере, чтобы эмулировать многозадачное поведение, задают следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
begin_critical_sectionend_critical_section

На командной строке можно использовать следующее:

polyspace-bug-finder
   -entry-points my_task,reset
   -critical-section-begin begin_critical_section:cs1
   -critical-section-end end_critical_section:cs1

Пример имеет две точки входа, my_task и reset. my_task вводит критический раздел через вызов begin_critical_section();. my_task заканчивается, не вызывая end_critical_section.

Исправление — обеспечивает, разблокировали

Одно возможное исправление должно вызвать разблокировать функциональный end_critical_section после инструкций в критическом разделе.



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset(void)
{
    begin_critical_section(); 
    global_var = 0;
    end_critical_section();
}

void my_task(void)
{
    begin_critical_section(); 
    global_var += 1;
    end_critical_section();
}

Пример - разблокировал в условии



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset() {
    begin_critical_section();
    global_var=0;
    end_critical_section();
}

void my_task(void) {
    int index=0;
    volatile int numCycles;

    while(numCycles) {
      begin_critical_section();
      global_var ++;
      if(index%10==0) {
        global_var = 0;
        end_critical_section();
      }
      index++;
    }
}

В этом примере, чтобы эмулировать многозадачное поведение, задают следующие опции.

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
begin_critical_sectionend_critical_section

На командной строке можно использовать следующее:

polyspace-bug-finder
   -entry-points my_task,reset
   -critical-section-begin begin_critical_section:cs1
   -critical-section-end end_critical_section:cs1

Пример имеет две точки входа, my_task и reset.

В цикле while my_task вводит критический раздел через вызов begin_critical_section();. В итерации цикла while:

  • Если my_task вводит ответвление условия if, критические концы раздела через вызов end_critical_section.

  • Если my_task не вводит ответвление условия if и оставляет цикл while, критический раздел не заканчивается. Поэтому дефект Missing unlock происходит.

  • Если my_task не вводит ответвление условия if и продолжается к следующей итерации цикла while, функция блокировки, begin_critical_section называется снова. Дефект Double lock происходит.

Поскольку numCycles является переменной volatile, он может принять любое значение. Любой из случаев выше возможен. Поэтому дефект Missing unlock и дефект Double lock появляются на вызове begin_critical_section.

Исправление — место разблокировало внешнее условие

Одно возможное исправление должно вызвать разблокировать функциональный end_critical_section вне условия if.



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset() {
    begin_critical_section();
    global_var=0;
    end_critical_section();
}

void my_task(void) {
    int index=0;
    volatile int numCycles;

    while(numCycles) {
      begin_critical_section();
      global_var ++;
      if(index%10==0) {
        global_var=0;
      }
      end_critical_section();
      index++;
    }
}

Исправление — место разблокировало в каждом условном переходе

Другое возможное исправление должно вызвать разблокировать функциональный end_critical_section в каждом ответвления условия if.



void begin_critical_section(void);
void end_critical_section(void);

int global_var;

void reset() {
    begin_critical_section();
    global_var=0;
    end_critical_section();
}

void my_task(void) {
    int index=0;
    volatile int numCycles;

    while(numCycles) {
      begin_critical_section();
      global_var ++;
      if(index%10==0) {
        global_var=0;
        end_critical_section();
      }
      else
        end_critical_section();
      index++;
    }
}

Описание

Двойной замок происходит когда:

  • Задача вызывает функцию блокировки my_lock.

  • Вызовы задачи my_lock снова прежде, чем вызвать соответствие разблокировали функцию.

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача, task1 вызывает функцию блокировки lock, другие задачи, вызывая lock, должна ожидать до вызовов task соответствие разблокировало функцию. Polyspace требует, чтобы и блокировка и разблокировала функции, должен иметь форму void func(void).

Чтобы найти этот дефект, необходимо задать многозадачные опции перед анализом. Чтобы задать эти опции, на панели Configuration, выбирают Multitasking.

Риск

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

Фиксация

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

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

Смотрите примеры мер ниже. Чтобы избежать проблемы, можно применить практику вызова блокировки и разблокировать функции в том же модуле на том же уровне абстракции. Например, в этом примере, func вызывает блокировку, и разблокируйте функцию на том же уровне, но func2 не делает.

void func() {
  my_lock();
  {
    ...
  }
  my_unlock();
}

void func2() {
  {
   my_lock();
   ...
  }
  my_unlock();
}

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

Пример - двойной замок



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    lock(); 
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

В этом примере, чтобы эмулировать многозадачное поведение, необходимо задать следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
lockunlock

На командной строке можно использовать следующее:

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin lock:cs1
   -critical-section-end unlock:cs1

task1 вводит критический раздел через вызов lock();. task1 вызывает lock снова, прежде чем это оставит критический раздел через вызов unlock();.

Исправление — удаляет первую блокировку

Если вы хотите, чтобы первый global_var+=1; был вне критического раздела, одно возможное исправление должно удалить первый вызов lock. Однако, если другие задачи используют global_var, этот код может произвести ошибку Data race.



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    global_var += 1;
    lock(); 
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

Исправление — удаляет вторую блокировку

Если вы хотите, чтобы первый global_var+=1; был в критическом разделе, одно возможное исправление должно удалить второй вызов lock.



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

Исправление — добавляет, что другой разблокировал

Если вы хотите, чтобы второй global_var+=1; был в критическом разделе, другое возможное исправление должно добавить другой вызов unlock.



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    unlock();
    lock();
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

Пример - двойной замок с вызовом функции



int global_var;

void lock(void);
void unlock(void);

void performOperation(void) {
  lock();
  global_var++;
}

void task1(void)
{
    lock();
    global_var += 1;
    performOperation();
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

В этом примере, чтобы эмулировать многозадачное поведение, необходимо задать следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks

my_task, reset

Critical section detailsStarting routineEnding routine
lockunlock

На командной строке можно использовать следующее:

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin lock:cs1
   -critical-section-end unlock:cs1

task1 вводит критический раздел через вызов lock();. task1 вызывает функциональный performOperation. В performOperation lock называется снова даже при том, что task1 не оставил критический раздел через вызов unlock();.

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

  • Вводит функциональный performOperation.

  • В performOperation, попытки ввести тот же критический раздел еще раз.

Можно кликнуть по каждому событию, чтобы перейти к соответствующей строке в исходном коде.

Исправление — удаляет вторую блокировку

Одно возможное исправление должно удалить вызов lock в task1.



int global_var;

void lock(void);
void unlock(void);

void performOperation(void) {
  global_var++;
}

void task1(void)
{
    lock();
    global_var += 1;
    performOperation();
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

Описание

Дважды разблокируйте, происходит когда:

  • Задача вызывает функцию блокировки my_lock.

  • Вызовы задачи соответствие разблокировали функциональный my_unlock.

  • Задача вызывает my_unlock снова. Задача не вызывает my_lock во второй раз между двумя вызовами my_unlock.

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача, task1 вызывает функцию блокировки my_lock, другие задачи, вызывая my_lock, должна ожидать до вызовов task1 соответствие разблокировало функцию. Polyspace требует, чтобы и блокировка и разблокировала функции, должен иметь форму void func(void).

Чтобы найти этот дефект, необходимо задать многозадачные опции перед анализом. Чтобы задать эти опции, на панели Configuration, выбирают Multitasking.

Риск

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

Фиксация

Фиксация зависит от первопричины дефекта.

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

Смотрите примеры мер ниже. Чтобы избежать проблемы, можно применить практику вызова блокировки и разблокировать функции в том же модуле на том же уровне абстракции. Например, в этом примере, func вызывает блокировку, и разблокируйте функцию на том же уровне, но func2 не делает.

void func() {
  my_lock();
  {
    ...
  }
  my_unlock();
}

void func2() {
  {
   my_lock();
   ...
  }
  my_unlock();
}

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

Пример - дважды разблокировал



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

В этом примере, чтобы эмулировать многозадачное поведение, необходимо задать следующие опции:

ОпцияЗначение
Configure multitasking manually
Tasks

task1

task2

Critical section detailsStarting routineEnding routine
BEGIN_CRITICAL_SECTIONEND_CRITICAL_SECTION

На командной строке можно использовать следующее:

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin BEGIN_CRITICAL_SECTION:cs1
   -critical-section-end END_CRITICAL_SECTION:cs1

task1 вводит критический раздел через вызов BEGIN_CRITICAL_SECTION();. task1 оставляет критический раздел через вызов END_CRITICAL_SECTION();. task1 вызывает END_CRITICAL_SECTION снова без промежуточного вызова BEGIN_CRITICAL_SECTION.

Исправление — удаляет второй, разблокировали

Если вы хотите, чтобы второй global_var+=1; был вне критического раздела, одно возможное исправление должно удалить второй вызов END_CRITICAL_SECTION. Однако, если другие задачи используют global_var, этот код может произвести ошибку Data race.



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    global_var += 1;
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Исправление — удаляет, сначала разблокировали

Если вы хотите, чтобы второй global_var+=1; был в критическом разделе, одно возможное исправление должно удалить первый вызов END_CRITICAL_SECTION.



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Исправление — добавляет другую блокировку

Если вы хотите, чтобы второй global_var+=1; был в критическом разделе, другое возможное исправление должно добавить другой вызов BEGIN_CRITICAL_SECTION.



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Проверяйте информацию

Группа: Rec. 14. Параллелизм (CON)

Введенный в R2019a


[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.