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: cygwin stable and cvs snapshot - fork() bug


On 11/5/07, Lev Bishop wrote:
> On 11/5/07, Corinna Vinschen  wrote:
> > On Nov  1 10:58, Corinna Vinschen wrote:
> > > On Oct 31 14:26, Lev Bishop wrote:
> > > > $ cat lev.c && gcc -o lev lev.c -Wall -Wextra && CYGWIN=server ./lev
> > > > #include <stdio.h>
> > > > #include <unistd.h>
> > > > #include <sys/shm.h>
> > > >
> > > > int main(void)
> > > > {
> > > >         int shmid;
> > > >         if ((shmid = shmget(IPC_PRIVATE, 100,IPC_CREAT | 0600 )) < 0 ||
> > > >                 !shmat(shmid, NULL, 0) ||
> > > >                 shmctl(shmid, IPC_RMID, NULL) < 0)
> > > >                 puts("problems with shm!");
> > > >         fork();
> > > > }
> > > > lev.c: In function `main':
> > > > lev.c:13: warning: control reaches end of non-void function
> > > >       3 [main] lev 1924 c:\Documents and
> > > > Settings\Lev\Desktop\mpd-0.13.0\lev.exe: *** fatal error -
> > > > MapViewOfFileEx (0x3E0000), Win32 error 6.  Terminating.
> > > >     124 [main] lev 5076 fork: child 1924 - died waiting for dll
> > > > loading, errno 11
> > >
> > > Thanks for the testcase.  I'm surprised that nobody experienced this
> > > problem before.  Sorta holiday here, so I'll look into it next week.
> >
> > Ouch, ouch, ouch.  shmctl(IPC_RMID) closed the handle to the shared
> > memory, but neglected to remove the actual mappings as well as the
> > bookkeeping structure.  The result is that after a fork the child thinks
> > there are still mappings which have to be duplicated into its own
> > memory.  But the handle has already been closed in the parent, so the
> > MapViewOfFile call fails with "invalid handle".
> >
> > Unfortunately not many applications use shmctl(IPC_RMID) before creating
> > a child process since usually the shared memory is meant to be... well,
> > shared.  That's why this didn't crop up more often, obviously.
>
> Are you sure that you're interpreting IPC_RMID correctly? My
> understanding is that you can still share the memory until you
> actually remove the mapping. (Sort of like how you can unlink() a temp
> file immediately after you open it, and continue to use it). I assumed
> this was the reason for the create-map-remove pattern used by mpd.
>
> From the linux man page:
>        IPC_RMID    Mark the segment to be destroyed.  The  segment  will  only
>                    actually  be  destroyed  after the last process detaches it
>                    (i.e., when the shm_nattch member of the associated  strucâ
>                    ture  shmid_ds  is  zero).  The caller must be the owner or
>                    creator, or be privileged.  If a segment  has  been  marked
>                    for  destruction,  then the (non-standard) SHM_DEST flag of
>                    the shm_perm.mode field in the  associated  data  structure
>                    retrieved by IPC_STAT will be set.

It indeed seems this is behaviour not described in SuSv3. But several
unices support (some variant of) this behaviour. At least linux,
freebsd, hp-ux, solaris 10 mention it in their man pages, and openbsd
and netbsd seem to implement it that way even though they don't
describe it in the man pages.

FreeBSD:
     IPC_RMID     Removes the segment from the system.  The removal will not
                  take effect until all processes having attached the segment
                  have exited; however, once the IPC_RMID operation has taken
                  place, no further processes will be allowed to attach the
                  segment.  For the operation to succeed, the calling
                  process's effective uid must match shm_perm.uid or
                  shm_perm.cuid, or the process must have superuser privi-
                  leges.

HP-UX:
IPC_RMID	 	
Remove the shared memory identifier specified by shmid from the system
and destroy the shared memory segment and data structure associated
with it. If the segment is attached to one or more processes, then the
segment key is changed to IPC_PRIVATE and the segment is marked
removed. The segment disappears when the last attached process
detaches it. This cmd can only be executed by a process that has an
effective user ID equal to either that of a user with appropriate
privileges or to the value of either shm_perm.uid or shm_perm.cuid in
the data structure associated with shmid.

Solaris 10:
IPC_RMID
Remove the shared memory identifier specified by shmid from the
system. The segment referenced by the identifier will be destroyed
when all processes with the segment attached have either detached the
segment or exited. If the segment is not attached to any process when
IPC_RMID is invoked, it will be destroyed immediately. This command
can be executed only by a process that has appropriate privileges or
an effective user ID equal to the value of shm_perm.cuid or
shm_perm.uid in the data structure associated with shmid.

A further linux extension: In addition to all the above, Linux goes
even further and still allows you to attach the segment even after
marking it for deletion. Linux man page:
       Linux  permits  a  process  to attach (shmat()) a shared memory segment
       that has already been marked for deletion using shmctl(IPC_RMID).  This
       feature is not available on other Unix implementations; portable appliâ
       cations should avoid relying on it.
Vmware and opera seem to depend on this extension-to-an-extension.
Freebsd (since version 5.2) has a sysctl kern.ipc.shm_allow_removed
which seems to allow you to force the linux behaviour on this issue.
Openbsd automatically does it (only) when running linux binaries via
compat_linux(8).

If you do implement the behaviour of not destroying the segment until
shm_nattach==0, you'll want to make sure that the shared memory key
can be reused immediately after the old segment has been IPC_RMIDed,
even though the old mapping may still be around. The other OS's which
implement it seem to do this by having shmctl(IPC_RMID) change the key
of the segment to be IPC_PRIVATE.

A cygwin discussion of not being able to reuse a shmid after
shmctl(IPC_RMID) is here:
http://www.cygwin.com/ml/cygwin/2001-11/msg01446.html
It looks like the old cygipc tried to implement the linux behaviour.

Don't you just love standards....

Lev

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


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