メインコンテンツ

ロック解除されていません

ロック解除関数を伴わないロック関数

説明

このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされますPolyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください

この欠陥は、以下の場合に発生します。

  • タスクはロック関数を呼び出します。

  • タスクはロック解除関数の呼び出しをせずに終了します。

マルチタスキング コードでは、ロック関数はコードのクリティカル セクションを開始し、ロック解除関数はそれを終了させます。タスク my_task がロック関数 my_lock を呼び出すとき、my_lock を呼び出し中の他のタスクは my_task が対応するロック解除関数を呼び出すまで待たなくてはなりません。

この欠陥を検出するには、次のいずれかのメソッドを使用してロック関数とロック解除関数を指定します。

間接参照の複数の層を使用してコードで同時実行を実装する場合、Polyspace はこの欠陥を誤って報告する場合があります。

リスク

ロック解除関数は、待機中の他のタスクがクリティカル セクションに入ることができるようにクリティカル セクションを終了させます。ロック解除関数がないと、不必要に長い時間、タスクがブロックされる可能性があります。

修正方法

コードのクリティカル セクション、つまり、Atomic ブロックとして実行するセクションを特定します。セクションの最初で使用したロック関数に対応するロック解除関数をこのセクションの最後で呼び出します。

この欠陥には、他の理由があり、それに対応する修正方法がある場合があります。不適切なロック解除関数を呼び出している可能性もあります。Polyspace 解析構成でロック関数とロック解除関数のペアをチェックして、不一致を修正します。

以下の修正例を参照してください。この問題を回避するには、同じモジュール内のロック関数とロック解除関数を同じ抽象化レベルで呼び出す手法に従うことをお勧めします。次の例の場合、func はロック関数とロック解除関数を同じレベルで呼び出していますが、func2 はそうではありません。

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

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

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

チェッカーの拡張

Polyspace でサポートされていないロック関数またはロック解除関数を使用する場合があります。これらの関数を、POSIX® の既知の同等の関数にマッピングすることで、このチェッカーを拡張します。サポートされていないマルチスレッド環境への同時実行欠陥チェッカーの拡張を参照してください。

すべて展開する



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;
}

この例では、マルチタスクの動作をエミュレートするため、以下のオプションを指定しなければなりません。

オプション
マルチタスクを手動で構成
タスク (-entry-points)

my_task, reset

クリティカル セクション詳細 (-critical-section-begin -critical-section-end)開始ルーチン終了ルーチン
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

この例には 2 つのエントリ ポイント my_task および reset があります。my_taskbegin_critical_section(); を呼び出してクリティカル セクションを開始します。my_taskend_critical_section を呼び出さずに終了します。

修正 — ロック解除を追加

1 つの修正方法として、クリティカル セクションの命令の後に 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++;
    }
}

この例では、マルチタスクの動作をエミュレートするため、以下のオプションを指定しなければなりません。

オプション仕様
マルチタスクを手動で構成
タスク (-entry-points)

my_task, reset

クリティカル セクション詳細 (-critical-section-begin -critical-section-end)開始ルーチン終了ルーチン
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

この例には 2 つのエントリ ポイント my_task および reset があります。

while ループ内部で、my_taskbegin_critical_section(); を呼び出してクリティカル セクションを開始します。while ループ内部の反復では次が発生します。

  • my_taskif 条件の分岐を開始した場合、クリティカル セクションは end_critical_section が呼び出されて終了します。

  • my_taskif 条件分岐を開始せず、while ループを離れる場合、クリティカル セクションは終了しません。したがって、[ロック解除されていません] が発生します。

  • my_taskif 条件分岐を開始せずに、while ループの次の反復を継続する場合、ロック関数 begin_critical_section は再度呼び出されます。[ダブル ロック] の欠陥が発生します。

numCyclesvolatile 変数であるため、どのような値を取ることも可能です。上記のいずれのケースも発生する可能性があります。したがって [ロック解除されていません] の欠陥および [ダブル ロック] の欠陥は begin_critical_section 呼び出しで発生します。

修正 — ロック解除を条件部の外部に記述

修正方法の 1 つとして、ロック解除関数 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++;
    }
}
修正 — ロック解除をすべての条件分岐内部に記述

もう 1 つの修正方法は if 条件のすべての分岐内にロック解除関数 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();
      }
      else
        end_critical_section();
      index++;
    }
}

結果情報

グループ: 同時実行
言語: C | C++
既定値: オン
コマンド ライン構文: BAD_LOCK
影響度: High

バージョン履歴

R2014b で導入