简体   繁体   中英

Is my malloc function allocating more than I intend to

Here is the code I'm trying to run. The malloc function allocates 800 bytes.

void DynamicMemoryAllocationUsingMalloc()
{
    int* p,i;
    if((p = (int*) malloc(800)) == NULL)
    {
        printf("\n Out of Memory \n");
        exit(0);
    }

    for(i =0;i < 800;i++)
    {
        printf(" 0x%x", (p + i));
        printf(" %d\n", *(p + i));

    }
}

But inside the for loop when I print the addresses I'm able to hop through 800 memory locations (using integer pointer p ) each 4 byte long (size of an integer) safely which amounts to 3200 bytes. How is that possible or I'm being lucky not be getting access violation error even though I'm actually entering into a memory area which I've not yet allocated for my program? I see garbage being written in all the memory locations for the obvious reason as I've not set those memory location to anything.

Note : It is a C program being run on Windows 7.

How is that possible or I'm being lucky not be getting access violation error even though I'm actually entering into a memory area which I've not yet allocated for my program?

When code reaches printf(" %d\\n", *(p + 200)); is is attempting to read outside allocated memory. That is undefined behavior UB.

UB is UB. It may happen like this every day or change the next time you run.


You are not lucky. Lucky would be for your code to stop right there.

Even reading uninitialized int data is UB. So code has UB (or maybe implementation defined) as soon as printf(" %d\\n", *(p + 0)); . IAC, code could have stopped right there.


Is my malloc function allocating more than I intend to?

That is the tricky bit. Code that invokes UB creates questionable results. Code without UB has no standard way to test the question. The only non-UB way to determine this is if the library supplies a function with the answer.

printf("True size %lu\n", (unsigned long) True_size(p));

Note: OP asserts int is 4 bytes.

It's working probably because you're not reaching past the range of memory currently allocated for the process. Modern systems typically allocate memory to a process in 4-kilobyte pages. Your first allocation is possibly at the beginning of a page, and the memory you're snooping in is probably in the unallocated remainder of that first page.

The OS can't detect invalid memory accesses unless they go beyond the ranges of memory allocated for your process. As far as the OS is concerned, it gave your process that page and the process is using it. It doesn't care whether or not the malloc routine used by your process has said your program "owns" that memory yet.

It might be a fun experiment to see how far you can read before you get an access violation. Just loop and print each address out before you try to read it.

But inside the for loop when I print the addresses I'm able to hop through 800 memory locations (using integer pointer p) each 4 byte long (size of an integer) safely which amounts to 3200 bytes.

Where I guess by "safely" you mean that the program does not crash. This is an ok definition when applied to air travel, but not so appropriate for a computer program.

How is that possible or I'm being lucky not be getting access violation error even though I'm actually entering into a memory area which I've not yet allocated for my program?

By accessing unallocated memory your program exhibits undefined behavior. You are to be commended for recognizing the problem. To quote @KerrekSB, however, "Undefined behavior is undefined". Generally speaking, you cannot assume any particular manifestation of undefined behavior.

If your program did happen to crash, with an access violation, for example, then you could be sure that it had exhibited undefined behavior, simply because C does not define any way to produce that behavior. But just because it seems to do what you expect does not mean that its behavior is defined. If it is not defined then, generally speaking, you cannot be confident that it will be consistent, either.

So basically, yes, you're just lucky. Or maybe unlucky. Myself, I'd rather have the program crash, so that I am alerted to the problem.

This here be an example of undefined behavior. Logically, this program should break. but it does not because the process image has some extra space that you can overflow into without having the operating system sending a segfault. I mean, instead of going to 800, go up to 1000, 10000, and so on. Eventually you'll get a segfault at some arbitrary number of iterations.

The reason you can go so high is because your program has a lot of overhead in the ram, this overhead is allowed to be overflowed into.

C standard answer : Accessing memory beyond what you have allocated results in undefined behaviour.

Real world answer :Your program allocates memory using malloc() which provisions it from the operating system, in this case Windows. However, each malloc() call doesn't result in a call to the operating system. Malloc will in fact usually allocate a bit more memory than it needs right now and will then break off a chunk which is at least the size you requested. This is done for performance reasons since every call to the operating system has a bit of overhead. Also, there is a minimum "page size" which is the smallest unit of memory which can be allocated from the operating system. 4096 bytes is a typical page size.

So in your case, you are accessing the memory which malloc has provisioned from the system but has not allocated for use. You should avoid this since the next call to malloc might cause the memory to be allocated for another purpose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM