问题
In order to test a software in limit conditions, I'm trying to create a test case where the provided user buffer is allocated at some very low memory address. Something very close to NULL
, like for example 0x1000h
.
This is proving a tough condition to create.
Actually, I'm unable to generate that with malloc()
on Linux, BSD, Windows, or OS-X.
I'm convinced this situation can happen on other types of devices, but I need a reproducible test case that can be inserted into a CI test suite.
Is there any known method with moderate complexity (and dependencies) to generate such conditions ?
Edit : Selected the solution proposed by Eric Postpischil, using mmap()
. Note that, as underlined by R., it's first necessary to lower the lowest address limit, readable at /proc/sys/vm/mmap_min_addr
(on Linux).
sudo sysctl -w vm.mmap_min_addr="4096"
Then the example code :
#include <stdio.h> /* printf */
#include <sys/mman.h> /* mmap */
int main(int argc, const char** argv)
{
void* lowBuff = mmap((void*)(0x1000), 64<<10,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
printf("lowBuff starts at %p \n", lowBuff);
}
And the result :
lowBuff starts at 0x1000
回答1:
On a POSIX/Unix system, you can use mmap
to request memory at specific page-aligned addresses. The lowest you can get will depend on your particular system and circumstances.
回答2:
You can only allocate virtual memory in C (malloc is a wrapper around VirtualAlloc on Windows as far as I know), and virtual memory is managed by your operating system, so it is pretty much impossible to predict what address you will get. It will likely never be close to 0x00 though. Unless you're writing a custom a memory allocation system, you shouldn't really have to deal with that and even then it shouldn't care about the provided address.
回答3:
On Windows, the lowest part of memory (64KB?) is reserved by the system specifically to catch accesses through invalid pointers. For example, if you try to dereference a null pointer, perhaps with an offset, you'll trigger an access violation. So 0x1000 is off the table because it's within the first 64KB.
Beyond that initial range, you can try to reserve and commit memory with VirtualAlloc, specifying a base address (the parameter is named lpAddress). The base address will be rounded down to the allocation granularity (which I think is also 64KB). If that memory is available, you're all set, but it might not be.
LPVOID desired_address = (LPVOID) 0x00010000;
LPVOID actual_address =
VirtualAlloc(desired_address, desired_size,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (actual_address == NULL) {
// we couldn't get the address we wanted.
} else if (actual_address != desired_address) {
// something very weird happened
} else {
// we got the low memory we wanted
}
Historically, typical 32-bit user processes has their executable code loaded starting at 0x00400000 and DLLs generally started higher (like 0x10000000), so you might get lucky shooting for something in that second block of 64KB. But address space layout randomization (ASLR) changes those defaults, and who knows what strange addresses other libraries are going to grab before you get a chance.
So you can try, but you have to be prepared for the possibility that trying to grab low memory with VirtualAlloc fails.
来源:https://stackoverflow.com/questions/48631207/allocate-at-low-memory-address