Et praktisk eksempel for programmører

The code that the programmer writes is as follows:

@@
expression E;
@@

  read_lock (E);
  ... when != E
- read_lock (E);
+ read_unlock (E);

He then gives the above rule and the Linux source code to Coccinelle.

A bug that is found using this rule is in the following function:

#ifdef CONFIG_UNCACHED_MAPPING
static void __init pmb_resize(void)
{

 int i;

 /*
  * If the uncached mapping was constructed by the kernel, it will
  * already be a reasonable size.
  */
 if (uncached_size == SZ_16M)
 return;

 read_lock(&pmb_rwlock);

 for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
 ...
 }

 read_lock(&pmb_rwlock);

}
#endif

This function contains two read_locks.  The one at the end of the function should become a read_unlock.

This function was first added to the Linux kernel in version 2.6.34, which was released on May 10, 2010.  It is likely that the bug escaped notice during testing for several reasons:

  1. This code is only available if the user has requested a specific configuration of the Linux kernel, as indicated by the line #ifdef CONFIG_UNCACHED_MAPPING
  2. The comment suggests that in the common case, the function returns before doing either read_lock.
  3. A double read lock does not in itself cause any visible effect on the kernel execution, in particular it does not cause the kernel to deadlock.
    Instead, the deadlock will come when there is a later attempt to do a write_lock.  The bug is thus particularly pernicious, because the place in the code where its effect can be observed is not at all related to the place where it occurs.

In this case, Coccinelle is able to correct the problem automatically, by changing read_lock to read_unlock.