Messages in this thread |  | | Date | Sun, 16 Sep 2001 13:42:52 -0400 (EDT) | From | Leonid Igolnik <> | Subject | semadj overflow in ipc/sem.c |
| |
-----BEGIN PGP SIGNED MESSAGE----- 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 1028: 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.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: For info see http://www.gnupg.org
iD8DBQE7pOSeRrKFtN3cJpMRAk6ZAJwIq2cqbdT6xc//IGz8kljsS5LHMgCgnfpd nZaAW4KIcFTnnOPPWyhdnFU= =wm6F -----END PGP SIGNATURE----- #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) { perror("semget"); exit(-1); }
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) { perror("semop"); }
if (semop(sem_id, &op_off, 1) < 0) { perror("semop"); } }
return 0; }
|  |