>Number:         173724
>Category:       misc
>Synopsis:       SYSV semaphore adjustment incorrect for SETVAL for array with 
>2 or more semaphores
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 19 17:00:00 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Anton Lavrentiev
>Release:        8.3-RELEASE-p3 FreeBSD 8.3-RELEASE-p3 #0: Mon Jun 11 23:52:38 
>UTC 2012
>Organization:
>Environment:
>Description:
SYSV semaphore adjustment is not done correctly for arrays with more than one 
semathore.


#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>


#define BUG1
#define BUG2


#define SEMKEY 1


union semun {
    int val;                    /* value for SETVAL */
    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;     /* array for GETALL, SETALL */
};


static void doCriticalWork(void)
{
    return;
}


int main(void)
{
    struct sembuf lock[2];
    int n, semid;

    if ((semid = semget(SEMKEY, 2, IPC_CREAT | 0666)) < 0) {
        perror("semget(IPC_CREATE)");
        return 1;
    }

#ifdef BUG1
    lock[0].sem_num = 0;
    lock[0].sem_op  = 0;
    lock[0].sem_flg = IPC_NOWAIT;
    lock[1].sem_num = 0;
    lock[1].sem_op  = 1;

#ifdef BUG2
    lock[1].sem_flg = SEM_UNDO;
#else
    lock[1].sem_flg = 0;
#endif

    if (semop(semid, lock, 2) != 0) {
        perror("semop(LOCK[0])");
        return 1;
    }
#endif

    for (n = 0; ; ++n) {
        static const union semun arg = { 0 };
        int error;

        printf("Iteration %d\n", n);

        lock[0].sem_num = 1;
        lock[0].sem_op  = 0; /* precondition:  [1] == 0 */
        lock[0].sem_flg = 0;
        lock[1].sem_num = 1;
        lock[1].sem_op  = 1; /* postcondition: [1] == 1 */
        lock[1].sem_flg = SEM_UNDO;

        if (semop(semid, lock, 2) < 0) {
            error = errno;
            fprintf(stderr, "semop(LOCK[1]): %d, %s\n",
                    error, strerror(error));
            break;
        }

        doCriticalWork();

#if 1
        if (semctl(semid, 1, SETVAL, arg) < 0) {
            error = errno;
            fprintf(stderr, "semctl(UNLOCK[1]): %d, %s\n",
                    error, strerror(error));
            break;
        }
#else
        lock[0].sem_num =  1;
        lock[0].sem_op  = -1;
        lock[0].sem_flg =  SEM_UNDO | IPC_NOWAIT;

        if (semop(semid, lock, 1) < 0) {
            error = errno;
            fprintf(stderr, "semop(UNLOCK[1]): %d, %s\n",
                    error, strerror(error));
            break;
        }
#endif

    }

    return 1;
}

>How-To-Repeat:
Compile and run the code shown in the problem description.  It will stop at 
iteration 16384 suggesting the UNDO adjustment value overflow with ERANGE 
(which should have not happened because SETVAL should have cleared all the UNDO 
adjustments on each loop iteration).
>Fix:
The probable cause is the implementation semundo_clear() found in 
sys/kern/sysv_sem.c .  FYI, originally the bug was found on CYGWIN, which 
adopts the
similar FreeBSD code to implement the semaphore arrays.

>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to