Bug 14532 - Generic sem_post race
Summary: Generic sem_post race
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: nptl (show other bugs)
Version: 2.16
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-08-30 19:13 UTC by Joseph Myers
Modified: 2014-06-25 06:49 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph Myers 2012-08-30 19:13:59 UTC
The generic Linux version of sem_post (nptl/sysdeps/unix/sysv/linux/sem_post.c) uses atomic_compare_and_exchange_bool_acq to increment the semaphore.  This is an unlock operation and should actually be using a release barrier.  The following test fails on some MIPS systems (MIPS uses the generic version of sem_post where various architectures use their own .S versions).  Testing a patch.

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>

#define NTHREADS 10
#define NITER 100000

sem_t sem;
int c;
volatile int thread_fail;

static void *
tf (void *arg)
{
  for (int i = 0; i < NITER; i++)
    {
      if (sem_wait (&sem) != 0)
        {
          perror ("sem_wait");
          thread_fail = 1;
        }
      ++c;
      if (sem_post (&sem) != 0)
        {
          perror ("sem_post");
          thread_fail = 1;
        }
    }
  return NULL;
}

int
main (void)
{
  if (sem_init (&sem, 0, 0) != 0)
    {
      perror ("sem_init");
      return 1;
    }

  pthread_t th[NTHREADS];
  for (int i = 0; i < NTHREADS; i++)
    {
      if (pthread_create (&th[i], NULL, tf, NULL) != 0)
        {
          puts ("pthread_create failed");
          return 1;
        }
    }

  if (sem_post (&sem) != 0)
    {
      perror ("sem_post");
      return 1;
    }

  for (int i = 0; i < NTHREADS; i++)
    if (pthread_join (th[i], NULL) != 0)
      {
        puts ("pthread_join failed");
        return 1;
      }

  if (c != NTHREADS * NITER)
    {
      printf ("c = %d, should be %d\n", c, NTHREADS * NITER);
      return 1;
    }
  return thread_fail;
}
Comment 1 Joseph Myers 2012-08-31 19:51:52 UTC
Fixed for 2.17 by:

commit 033d54a2d43a92cdb1794a4dfece4d465cf36f6b
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Fri Aug 31 19:49:31 2012 +0000

    Fix sem_post race (bug 14532).