メインコンテンツ

ロックの欠落

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

説明

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

この欠陥は、タスクが対応するロック関数を呼び出す前にロック解除関数を呼び出した場合に発生します。

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

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

リスク

対応するロック関数がないロック解除関数の呼び出しは、コーディング エラーを示す可能性があります。たとえば、ロック解除関数が、クリティカル セクションを開始するロック関数に対応していないことが考えられます。

修正方法

修正方法は欠陥の根本原因によって異なります。たとえば、ロック関数とロック解除関数の不一致が原因で欠陥が発生している場合は、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(void) 
{
  begin_critical_section();
  global_var = 0;
  end_critical_section();
}

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

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

オプション仕様
マルチタスクを手動で構成
タスク (-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 を呼び出す前に end_critical_section を呼び出します。

修正 — ロックを提供

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

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

オプション仕様
マルチタスクを手動で構成
タスク (-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_taskend_critical_section(); を呼び出してクリティカル セクションを離れます。while ループ内部の反復では次が発生します。

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

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

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

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

結果情報

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

バージョン履歴

R2014b で導入