CERT C: Rec. CON01-C

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

Описание

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

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

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

  • Пропавшие без вести блокировки.

  • Пропавшие без вести разблокировали.

  • Двойной замок.

  • Дважды разблокируйте.

Примеры

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

Проблема

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

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача 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сброс

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сброс

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сброс

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сброс

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сброс

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сброс

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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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