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]

Re: SYSV semaphore bug (testcase attached)


On Nov 23 13:19, Corinna Vinschen wrote:
> On Nov 19 16:04, Lavrentiev, Anton (NIH/NLM/NCBI) [C] wrote:
> > 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).
> 
> This is original FreeBSD code, so I have a hard time to follow the idea
> that it might be wrong.  I stared a long while into the source now, and
> I compared that with the latest version of the upstream code.
> 
> The i counter is in lockstep with the sunptr pointer.  The only time
> something happens is if sunptr->un_num (== suptr->un_ent[i].un_num)
> equals semnum.  In that case, suptr->un_ent[i] is overwritten with
> with the last element uptr->un_ent[suptr->un_cnt], and then the code
> calls continue, thus NOT incrementing i and sunptr.  So the same
> element, now containing the contents of suptr->un_ent[suptr->un_cnt],
> is evaluated again.
> 
> Am I missing something?

Yes, I do, and debugging as well as comparing my observations with the
NetBSD code of this function reveals a long-standing bug in the FreeBSD
code.  This call:

	if (semnum != -1)
		break;

is outside of the `if (semnum == -1 || sunptr->un_num == semnum)'
condition, and that results in ignoring every member of the un_ent array
but the first one (i == 0).

Can you please test the below patch?


Thanks,
Corinna


	* sysv_sem.cc (semundo_clear): Move condition to break from
	inner loop to the right spot.


Index: sysv_sem.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygserver/sysv_sem.cc,v
retrieving revision 1.10
diff -u -p -r1.10 sysv_sem.cc
--- sysv_sem.cc	6 Feb 2008 22:30:38 -0000	1.10
+++ sysv_sem.cc	23 Nov 2012 14:18:21 -0000
@@ -529,9 +529,9 @@ semundo_clear(int semid, int semnum, str
 						  suptr->un_ent[suptr->un_cnt];
 						continue;
 					}
+					if (semnum != -1)
+						break;
 				}
-				if (semnum != -1)
-					break;
 			}
 			i++, sunptr++;
 		}


-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

--
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]