This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

SYSV semaphore bug (testcase attached)


Hi,

As I previously reported, there is a weird behavior of CYGWIN implementation
of SYSV semaphores, and a bug exposition for one problem is attached below
(I'm still looking into some other issues in there).

If the code is compiled with both BUG1 and BUG2 defined (as shown), it
will abort at iteration 16384 (just the default semaphore overflow).

Undefining BUG2 causes the problem disappear (because there is no longer
UNDO on the 1st semaphore).  Also, running the code with just one semaphore
(undef BUG1) causes no problem.  Finally, replacing "#if 1" with "#if 0"
to unlock the semaphore allows to run indefinitely with any combination of
BUG1/2 (just remember to issue ipcs/ipcrm to start with a clean slate at
all times).

Reviewing the code of CYGSERVER, there is an apparent bug in the semundo_clear()
routine (at around line 536, which looks like "i++, sunptr++;", and advances
both undo indexes even when "if (sunptr->un_id == semid)" (line 524)
failed to match semid.  This means that for two (or more) semaphores, the
undo index "i" moves ahead even when nothing was done while still searching.
This causes the adjust pointer to miss the position to clear, and overflow
the semaphore adjust value (line 1207, semop(), by the virtue of
semundo_adjust()'s logic at about line 486).


#include <errno.h>
#include <stdio.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;
}

Anton Lavrentiev
Contractor NIH/NLM/NCBI


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]