Double lock

Функция блокировки вызвана дважды в задаче без промежуточного вызова, чтобы разблокировать функцию

Описание

Этот дефект происходит когда:

  • Задача вызывает функцию блокировки 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();
}

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

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

 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 (-entry-points)

task1

task2

Critical section details (-critical-section-begin -critical-section-end)Starting 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();
}

Информация о результате

Группа: параллелизм
Язык: C | C++
Значение по умолчанию: On
Синтаксис командной строки: DOUBLE_LOCK
Удар: высоко
ID CWE: 764
Введенный в R2014b