Main Content

CWE Rule 832

Unlock of a Resource that is not Locked

Since R2024a

Description

Rule Description

The product attempts to unlock a resource that is not locked.

Polyspace Implementation

The rule checker checks for Missing lock.

Examples

expand all

Issue

This checker is deactivated in a default Polyspace® as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).

This issue occurs when a task calls an unlock function before calling the corresponding lock function.

In multitasking code, a lock function begins a critical section of code and an unlock function ends it. When a task my_task calls a lock function my_lock, other tasks calling my_lock must wait till my_task calls the corresponding unlock function. Polyspace requires that both lock and unlock functions must have the form void func(void).

To find this defect, specify your lock and unlock functions using one of these methods:

Risk

A call to an unlock function without a corresponding lock function can indicate a coding error. For instance, perhaps the unlock function does not correspond to the lock function that begins the critical section.

Fix

The fix depends on the root cause of the defect. For instance, if the defect occurs because of a mismatch between lock and unlock function, check the lock-unlock function pair in your Polyspace analysis configuration and fix the mismatch.

See examples of fixes below. To avoid the issue, you can follow the practice of calling the lock and unlock functions in the same module at the same level of abstraction. For instance, in this example, func calls the lock and unlock function at the same level but func2 does not.

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

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

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

You might be using locking and unlocking functions that are not supported by Polyspace. Extend this checker by mapping these functions to their known POSIX® equivalent. See Extend Concurrency Defect Checkers to Unsupported Multithreading Environments.

Example — Missing lock


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(); //Noncompliant
}

In this example, to emulate multitasking behavior, you must specify the following options:

OptionSpecification
Configure multitasking manually
Tasks (-entry-points)

my_task, reset

Critical section details (-critical-section-begin -critical-section-end)Starting routineEnding routine
begin_critical_sectionend_critical_section

On the command-line, you can use the following:

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

The example has two entry points, my_task and reset. my_task calls end_critical_section before calling begin_critical_section.

Correction — Provide Lock

One possible correction is to call the lock function begin_critical_section before the instructions in the 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();
}
Example — Lock in Condition


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();  //Noncompliant
      index++;
    }
}

In this example, to emulate multitasking behavior, you must specify the following options:

OptionSpecification
Configure multitasking manually
Tasks (-entry-points)

my_task, reset

Critical section details (-critical-section-begin -critical-section-end)Starting routineEnding routine
begin_critical_sectionend_critical_section

On the command-line, you can use the following:

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

The example has two entry points, my_task and reset.

In the while loop, my_task leaves a critical section through the call end_critical_section();. In an iteration of the while loop:

  • If my_task enters the if condition branch, the critical section begins through a call to begin_critical_section.

  • If my_task does not enter the if condition branch and leaves the while loop, the critical section does not begin. Therefore, a Missing lock defect occurs.

  • If my_task does not enter the if condition branch and continues to the next iteration of the while loop, the unlock function end_critical_section is called again. A Double unlock defect occurs.

Because numCycles is a volatile variable, it can take any value. Any of the cases above are possible. Therefore, a Missing lock defect and a Double unlock defect appear on the call end_critical_section.

Check Information

Category: Resource Locking Problems

Version History

Introduced in R2024a