[lkml]   [2001]   [Sep]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Subjectsemadj overflow in ipc/sem.c
Hash: SHA1

Short description of the problem: incorrect use of SEM_UNDO flag for
semaphore operations and overflow of the semadj value causes the process
to leave semaphore locked after it exits.

Longer version:
while working on the project at work I've came across the bug that
would only manifest itself after the application run for long period of
time. The problem was narrowed down to a semaphore handling that was used
to synchronize access to shared memory region, and for some reason the
semaphore would be left locked after one of the processes exits. I've
found out that the code in question was setting SEM_UNDO flag for lock
operations and was not setting it for unlocks. At first it seemed normal,
but I've noticed that problem manifests itself after large number of
operations on the semaphore.

It appears that the problem is caused by semajd overflow in
following code in sem.c :
Line 258:
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] -= sem_op;

semajd is not checked for overflows, and since only lock operations are
counted it overflows after 32768 operations. Than when processes if killed
or exits, semadj is applied to the current value of the semaphore at line
sem->semval += u->semadj[i];
if (sem->semval < 0)
sem->semval = 0; /* shouldn't happen */
sem->sempid = current->pid;

At this stage semval is 32767 since which is the value of the semadj after
it overflows.

AFAIK SYSV will not let the application to overflow semadj, but I don't
have a Solaris box handy.

See attached example that demonstrates the problem, after it exits
semaphore is left locked (which can be verified by running it again and
watching it waiting for the sem to become free).

- ----

Leonid Igolnik.

Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(int argc, char *argv[]) {
int sem_id, i;
struct sembuf op_on[2];
struct sembuf op_off;

sem_id = semget(123, 1, IPC_CREAT | 0600);
if (sem_id < 0) {

op_on[0].sem_num = 0;
op_on[0].sem_op = 0;
op_on[0].sem_flg = 0;
op_on[1].sem_num = 0;
op_on[1].sem_op = 1;
op_on[1].sem_flg = SEM_UNDO;

op_off.sem_num = 0;
op_off.sem_op = -1;
op_off.sem_flg = 0;

for (i = 0; i < 32769; i++) {
if (semop(sem_id, op_on, 2) < 0) {

if (semop(sem_id, &op_off, 1) < 0) {

return 0;
 \ /
  Last update: 2005-03-22 13:03    [W:0.035 / U:0.948 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site