John Reiser jreiser@BitWagon.com writes:
Attached is the patch for http://bugs.winehq.org/show_bug.cgi?id=14360 dosmem forgot MAP_FIXED
No, it's not forgotten, that's the way it's supposed to work. What are you trying to fix?
Alexandre Julliard wrote:
John Reiser jreiser@BitWagon.com writes:
Attached is the patch for http://bugs.winehq.org/show_bug.cgi?id=14360 dosmem forgot MAP_FIXED
No, it's not forgotten, that's the way it's supposed to work. What are you trying to fix?
Some environments strictly enforce the semantics of mmap(), namely a successful return value need not equal the requested address unless MAP_FIXED, even if the requested address is unmapped and otherwise available. Unless MAP_FIXED, then it is legal to return any page range that is large enough. Callers of the patched code were relying on getting actual fixed addresses in the interval [0, 0x110000). In particular, this did not work under valgrind.
See also the similar bug http://bugs.winehq.org/show_bug.cgi?id=12783 Allocation of PEB and TEB can overlap dll mappings
John Reiser jreiser@BitWagon.com writes:
Some environments strictly enforce the semantics of mmap(), namely a successful return value need not equal the requested address unless MAP_FIXED, even if the requested address is unmapped and otherwise available. Unless MAP_FIXED, then it is legal to return any page range that is large enough. Callers of the patched code were relying on getting actual fixed addresses in the interval [0, 0x110000). In particular, this did not work under valgrind.
You can't use MAP_FIXED on an address that you are not sure is available. If it wasn't reserved first, the best we can do is request the address, and refuse to support DOS apps if we don't get it. If you want to make this work in all cases you have to fix valgrind to allow the preloader to do its job.
Alexandre Julliard wrote:
John Reiser jreiser@BitWagon.com writes:
Some environments strictly enforce the semantics of mmap(), namely a successful return value need not equal the requested address unless MAP_FIXED, even if the requested address is unmapped and otherwise available. Unless MAP_FIXED, then it is legal to return any page range that is large enough. Callers of the patched code were relying on getting actual fixed addresses in the interval [0, 0x110000). In particular, this did not work under valgrind.
You can't use MAP_FIXED on an address that you are not sure is available.
I call mmap(0,,,MAP_FIXED,,) often, and I get what I expect [*], namely a ["new"] mapping at 0, replacing any previous mapping at 0, regardless of the state of existing mappings. See testcase below.
I do this when I want to map a page at address 0. The typical reason _I_ want this, is to mmap an entire file into memory, such that the byte offset in the file equals the process virtual address in memory. This is exceedingly useful when examining random files using gdb.
The typical reason that _wine_ might want mmap(0,,,MAP_FIXED,,) is because some DOS apps "know" about interrupt vector at 0 and BIOS low memory in [0, 0x1000), or because some Win32 apps assume that there is an identity map from DOS addresses 0:0 through 0xffff:0xffff to process virtual addresses 0 through 0x10ffef. Both of these are reasonable assumptions in some environments. Supporting those assumptions requires MAP_FIXED in the two calls from dosmem.c to mmap().
----- demo that mmap(,,,MAP_FIXED,,) replaces any existing mapping #include <sys/types.h> #include <sys/mman.h> #include <errno.h> #include <stdio.h>
main() { /* accommodate Linux >= 2.6.24 whose default policy prohibits mapping in first 64KB */ char *const addr = (char *)0x100000; errno = 0; void *rv1 = mmap(addr, 4096, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); printf("rv1=%x errno=%d\n", rv1, errno); *addr = 5; printf("first byte = %d\n", *addr); errno = 0; void *rv2 = mmap(addr, 4096, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); printf("rv2=%x errno=%d\n", rv2, errno); *addr = 7; printf("first byte = %d\n", *addr); return; } ----- [*] Linux >= 2.6.24 has a default *policy* of not allowing mmap in the first 64KB, as a protection against privilege escalation that is enabled by a kernel bug involving a NULL pointer. So Linux >= 2.6.24 gives EINVAL unless the default policy has been changed (which can be done without reboot.)
If it wasn't reserved first, the best we can do is request the address, and refuse to support DOS apps if we don't get it. If you want to make this work in all cases you have to fix valgrind to allow the preloader to do its job.
_I_ don't care about those features of DOS and BIOS interface which require fixed addresses. What I want is that (* NULL) and (NULL->member) always give SIGSEGV (at least for structures <= 64KB in size.) This is a property that helps to make general apps more portable between Win32 and wine+Linux.
One of the other patches that I submitted introduces a new environment variable WINE_NO_DOSMEM_64KB which inhibits any attempt by wine itself to map [0, 0x10000), even though the operating system might allow it. The purpose of that patch is to allow a wine that is run on Linux < 2.6.24 (such as Ubuntu 7.10) to behave the same as it behaves on Linux >=2.6.24, and also to make (* NULL) always deliver SIGSEGV.
John Reiser jreiser@BitWagon.com writes:
I call mmap(0,,,MAP_FIXED,,) often, and I get what I expect [*], namely a ["new"] mapping at 0, replacing any previous mapping at 0, regardless of the state of existing mappings. See testcase below.
Yes, the replacing existing mappings is precisely the problem. That's why we reserve the memory, and that's why if it wasn't reserved we can't blindly replace it, because we don't know what's in there. MAP_FIXED is used a few lines below once we know we have the area we want.
_I_ don't care about those features of DOS and BIOS interface which require fixed addresses. What I want is that (* NULL) and (NULL->member) always give SIGSEGV (at least for structures <= 64KB in size.) This is a property that helps to make general apps more portable between Win32 and wine+Linux.
That's already the case, NULL pointer accesses are always caught, until you run some DOS code. There's nothing to fix in there, the only thing to do is to let the preloader do its job.