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: 1.7.0 CVS mmap failure


On Sun, Jan 07, 2007 at 11:58:44AM +0100, Corinna Vinschen wrote:
> Lots of comments throughout the file...

Unfortunately the code-path is less than clear to follow. This may be
a matter of opinion but it's fairly complex and looks to have history in
it.

> > In the 2nd strace, I changed the mmap logic to stop trying to align the 1st
> > map on a 4k granularity boundary and just allocate a single map w/ 64k of
> > left over dead space (what I would typically expect in posix land). I also
> > added more debug info at various stages to try and figure things out. When
> > changing it to use 64k period, the mmaps are both successful - which is good,
> > but VirtualProtect always fails, no matter what, on unmap.
> 
> The strace is rather useless without the (hopefully very short) source
> code of the (hopefully very small) testcase.

Okay, I understand where you're coming from. Where I'm coming from is that it
is difficult to generate a test case that actually demonstrates the issue
outside of the scope of my application. Suffice to say, I do see the errors in
strace output - and I can see MapViewNT returning an error in the double-map
-so-we-can-have-4k-pseudopages version. Do you have a 4GB machine running w/
PAE enabled in which to even test a test case if I could come up with one which
consistently works? Also, VirtualProtect fails on unmap everytime, a test case
for this is a matter of any old map/unmap it seems.

  33 /* Filler pages are the pages from the last file backed page to the next
  34    64K boundary.  These pages are created as anonymous pages, but with
  35    the same page protection as the file's pages, since POSIX applications
  36    expect to be able to access this part the same way as the file pages. */
  37 #define __PROT_FILLER   0x4000000

1247   if (orig_len)
1248     {
1249       /* If the requested length is bigger than the file size, the
1250          remainder is created as anonymous mapping.  Actually two
1251          mappings are created, first the reminder from the file end to
1252          the next 64K boundary as accessible pages with the same
1253          protection as the file's pages, then as much pages as necessary
1254          to accomodate the requested length, but as reserved pages which
1255          raise a SIGBUS when trying to access them.  AT_ROUND_TO_PAGE
1256          and page protection on shared pages is only supported by 32 bit NT,
1257          so don't even try on 9x and in WOW64.  This is accomplished by not
1258          setting orig_len on 9x and in WOW64 above. */
1259       orig_len = roundup2 (orig_len, pagesize);
1260       len = roundup2 (len, getsystempagesize ());
                                ^^^^^^^^^^^^^^^^^
Why? This also violates the "to the next 64k boundary as accessible pages" part.
The pagesize is 64k, the granularity for addressing is 4k. Don't see why 4k has
to be mixed in here by calling getsystempagesize() or am I totally missing
something here?

1261
1262       if (orig_len - len)
1263         {
1264           orig_len -= len;
1265           size_t valid_page_len = orig_len % pagesize;
1266           size_t sigbus_page_len = orig_len - valid_page_len;
1267
1268           caddr_t at_base = base + len;

"       The  system shall always zero-fill any partial page at the end of
       an object. Further, the system shall never write out any
       modified portions of the last page of an object which are beyond
       its end. References within the address range starting at pa
       and continuing for len bytes to whole pages following the end of an
       object shall result in delivery of a SIGBUS signal.
"

Which I would expect to be: |0 <len> 65536| on Windows.

/* start */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>

int main(int argc, char **argv)
{
        struct stat st;
        long psz, r;
        char *q;
        char a;
        int fd;

        if (argc <= 2) return -1;
        if ((fd = open(argv[1], O_RDONLY)) == -1) {
                perror("open");
                return -1;
        }
        if (fstat(fd, &st) == -1) {
                perror("stat");
                return -1;
        }

        psz = sysconf(_SC_PAGESIZE);
        fprintf(stderr, "psz = %ld\n", psz);
        fprintf(stderr, "st.st_size == %lu\n", (long)st.st_size);

        q = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        if (q == MAP_FAILED) {
                perror("mmap");
                return -1;
        }

        if (*argv[2] == 'r') {
                for (r = 0; ; r++) {
                        if (r > st.st_size)
                                fprintf(stderr, "%lu ", r);
                        a = q[r];
                }
        } else if (*argv[2] == 'w') {
                for (r = 0; ; r++) {
                        if (r > st.st_size)
                                fprintf(stderr, "%lu ", r);
                        q[r] = a;
                }
        }

        return 0;
}
/* end */

Linux:

$ uname -rvs
Linux 2.6.18.2 #1 Sat Nov 4 16:37:01 PST 2006
$ gcc -g3 -o mmt mmt.c
$ ./mmt mmt.c r
psz = 4096
st.st_size == 889
[...]
8189 8190 8191 8192 Segmentation fault
(what? strange that this doesn't dump at 4k on read)

[clayne@ns1 mmt]$ ./mmt mmt.c w
psz = 4096
st.st_size == 889
[...]
4093 4094 4095 4096 Segmentation fault
(expected)

Darwin:

$ uname -rvs
Darwin 8.8.0 Darwin Kernel Version 8.8.0: Fri Sep  8 17:18:57 PDT 2006; root:xnu-792.12.6.obj~1/RELEASE_PPC

$ gcc -g3 -o mmt mmt.c
$ ./mmt mmt.c r
psz = 4096
st.st_size == 1309
4093 4094 4095 4096 Segmentation fault
(expected)

$ ./mmt mmt.c w
psz = 4096
st.st_size == 1309
4093 4094 4095 4096 Segmentation fault
(expected)

Cygwin:

$ uname -rvs
CYGWIN_NT-5.2 1.7.0s(0.161/4/2) 20070104 08:05:46

Virgin 20060104 snapshot:

$ gcc -g3 -o mmt mmt.c
$ ./mmt mmt.c r
psz = 65536
st.st_size == 1309
212989 212990 212991 212992 Segmentation fault (core dumped)
(what?)

$ ./mmt mmt.c w
psz = 65536
st.st_size == 1309
65533 65534 65535 65536 Segmentation fault (core dumped)
(expected)

Modified to use getpagesize() instead of getsystempagesize():

$ ./mmt mmt.c r
psz = 65536
st.st_size == 1309
4093 4094 4095 4096 Segmentation fault (core dumped)
(what? not 64k?)

$ ./mmt mmt.c w
psz = 65536
st.st_size == 1309
4093 4094 4095 4096 Segmentation fault (core dumped)
(what? not 64k?)

Yet the latter works for me, whereas the former results in mmap()
failures for files smaller than the page size.

Also, check this out:

http://blogs.msdn.com/oldnewthing/archive/2003/10/08/55239.aspx

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