static void *
mmap_heap_malloc_1 (unsigned long requested_length, int fixedp)
{
unsigned long ps = (UX_getpagesize ());
void * addr
= (mmap (((void *) MMAP_BASE_ADDRESS),
(((requested_length + (ps - 1)) / ps) * ps),
(PROT_EXEC | PROT_READ | PROT_WRITE),
(MAP_PRIVATE | MAP_ANONYMOUS | (fixedp ? MAP_FIXED : 0)),
/* Ignored by GNU/Linux, required by FreeBSD and Solaris. */
(-1),
0));
return ((addr == MAP_FAILED) ? 0 : addr);
}
Now for the default runtime (
runtime.com), requested_length == 5726028,
and the function proceeds without fault. However when the "-compiler"
switch is used to load the compiler, the
all.com runtime is loaded and
then requested_length == 18563072 (this image is much bigger) and the
mmap call results in a segfault. ps is 4096, fixedp is 1 and
MMAP_BASE_ADDRESS == 4096.
Why does mmap segfault at all? Shouldn't it at worst return an error?
When MAP_FIXED is passed (fixedp!=0), the mapping will overwrite any other
mappings that exist. So if the address range overlaps some shared
libraries or something like that, it will clobber that part of the address
space and who knows what could happen. In older kernels, shared libraries
would always end up in a high part of the address space, so assuming a huge
low region was available worked. Now shared libraries (and any mmap
region) are more likely to be located at random addresses that may be in
the low part of the address space. It has never been safe or kosher to
assume some large part of the address space would never be used for shared
libraries. cscheme needs to change its plan for calling mmap. If you need
a big contiguous region of address space into which you will place multiple
separate mappings, then the only safe thing to do is to mmap a region of
the whole needed size without MAP_FIXED (e.g. using PROT_NONE), and then
overwrite portions of that mapping with MAP_FIXED mappings to get the
layout you want.
Thanks,
Roland