Sign in to follow this  
ordered_disorder

Access Violations and Memory

Recommended Posts

I'm really confused and I hope one you more experienced programmers can sort me out. I have the follow c++ source ->
void main()
{
	unsigned int *ptr_to_mem = (unsigned int *)0x00000000; // could be anything for all I care, 0xXXXXXXXX
	*ptr_to_mem = 0xFFFFFFFF;
}

As you can see I'm trying to change the value of the memory at this location. I'm doing this to teach me more about the OS, winDBg(visual studio's debugger) and how memory works in windows, all for my future mastery of assembly programming. I keep getting access violations 0xC0000005 which is perplexing because I thought each program was given its own 4 GB address space, because windows runs in protected mode. When I debug the program I see at the address 0x0000000 there is just uninitialized data, so I don't know why I would be getting the access violation, because from my perspective it's just free memory! This makes me wonder how the compiler sets up memory to be used when I dynamically allocate it. This is what I get for learning assembly, a lot of questions.

Share this post


Link to post
Share on other sites
SiCrane    11839
On windows the memory addresses from the range 0x0000 0000 to 0x0000 ffff are a protected range that your program cannot write to without generating an access violation. Even if you had a pointer to another location, a program can only legitimately write to a memory location that has been committed, which may not be true of a given random memory address.

Share this post


Link to post
Share on other sites
bakery2k1    712
Just because your program is given a 4GB address space, it doesn't mean it is free to use whichever parts of that it chooses. The top 2GB are reserved for the OS, and the lower 2GB are only made usable when you request memory from the OS. Moreover, the bottom 64(?)KB will never be allocated to you, in order that writes to NULL pointers are caught.

Share this post


Link to post
Share on other sites
LessBread    1415
This code

unsigned int *ptr_to_mem = (unsigned int *)0x00000000;
*ptr_to_mem = 0xFFFFFFFF;

is akin to

unsigned int *ptr_to_mem = NULL;
*ptr_to_mem = 0xFFFFFFFF;

that means that ptr_to_mem doesn't point to valid memory, so attempting to dereference the pointer in order to write a value to the space it points to, throws an access violation exception.

Share this post


Link to post
Share on other sites
nice observation there LessBread, didn't even realize. I get get an access violation at pretty much any memory address I try to write and read from, even if the memory address > 0x0000FFFF, I guess I have to go through the operating system to get access to my program's memory, i.e. by using functions defined in kernal32.lib

Share this post


Link to post
Share on other sites
Spoonbender    1258
Quote:
Original post by ordered_disorder
nice observation there LessBread, didn't even realize. I get get an access violation at pretty much any memory address I try to write and read from, even if the memory address > 0x0000FFFF, I guess I have to go through the operating system to get access to my program's memory, i.e. by using functions defined in kernal32.lib


Basically, just stick to the memory you've new'ed or malloc'ed. Everything else can give you an access violation (Occasionally it won't, but only because you accidentally hit somewhere within a page that's already been allocated to you)

Share this post


Link to post
Share on other sites
Anon Mike    1098
Different parts of memory have different permissions. Some you can't touch at all, some you can only read from. Some parts you can run code in and some parts you can't, etc, etc. An access violation means that you've tried to do something that is not allowed for that particular piece of memory.

You can have the OS allocate memory for you and once that's done you can usually request that it change the permissions around.

(and windbg is not Visual Studio's debugger. The debugger built into VS and windbg are two unrelated debuggers).

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by ordered_disorder
I guess I have to go through the operating system to get access to my program's memory, i.e. by using functions defined in kernal32.lib
Bingo!
The OS allocates memory, not your program. The memory address space is shared amoungst all processes, and the OS will give you bits that you can use, because it is the only thing keeping track of who is using what bit of memory.

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by LessBread
The physical memory is spread out among all processes, but each process has it's own virtual address space.
Okay, so you mean that two processes can be allocated the same virtual memory addresses when calling new, and yet the physical memory accessed by both will be different between them.
Sorry, I thought that because it's best to rebase your DLLs to avoid automatic relocation, that it was bigger than that.
I really should learn how shared memory works too.

Still, you can't go picking random memory addresses to write to, and expect to not get access violations anyway. Nor can one expect that even half of the 4GB address range of a process is all actually mapped to physical memory. There's obviously got to be large hole(s) somewhere, especially around 0!

Share this post


Link to post
Share on other sites
SiCrane    11839
Access violations are only peripherally related to what physical memory is associated with what address, what matters is if the virtual memory is committed. If the virtual memory is committed when a read or write occurs to that address no access violation will be registered even if there is no physical memory mapped to that address.

And no physical memory will ever be mapped to the range 0x0000 0000 to 0x0000 ffff because that is a reserved area meant to catch bad pointer access.

Rebasing DLLs just prevents the loader from doing extra work if two DLLs happen to have the same base address, it's not really related to this discussion.

Share this post


Link to post
Share on other sites
LessBread    1415
Quote:
Original post by iMalc
Okay, so you mean that two processes can be allocated the same virtual memory addresses when calling new, and yet the physical memory accessed by both will be different between them.


That's what happens.

Quote:
Original post by iMalc
Sorry, I thought that because it's best to rebase your DLLs to avoid automatic relocation, that it was bigger than that.


The advantage gained by dll rebasing pertains to avoiding load clashes between different dlls. This happens within the address space of a single process.

Quote:
Original post by iMalc
I really should learn how shared memory works too.


You probably should learn about how virtual memory works on Windows first. This article, The Virtual-Memory Manager in Windows NT, might be old but the basics it lays down are still used today in XP, but don't get too bogged down in the details because you don't need to know how an engine works in order to drive a car.

Quote:
Original post by iMalc
Still, you can't go picking random memory addresses to write to, and expect to not get access violations anyway. Nor can one expect that even half of the 4GB address range of a process is all actually mapped to physical memory. There's obviously got to be large hole(s) somewhere, especially around 0!


Yes, you can't just go picking randmon addresses and expect them to be valid. After reading the above link, you'll have a better idea of how virtual memory is organized and how it relates back to physical memory. For what it's worth, there are large "holes" in the virtual address space of a process. There's a huge one between 0x10000000 and 0x60000000 and addresses above 0x80000000 are off limits to user mode programs alltogether.

Share this post


Link to post
Share on other sites
SiCrane    11839
Quote:
Original post by LessBread
Yes, you can't just go picking randmon addresses and expect them to be valid. After reading the above link, you'll have a better idea of how virtual memory is organized and how it relates back to physical memory. For what it's worth, there are large "holes" in the virtual address space of a process. There's a huge one between 0x10000000 and 0x60000000 and addresses above 0x80000000 are off limits to user mode programs alltogether.


0x1000 0000 to 0x6000 0000 isn't off limits to the application. Seeing as 0x1000 0000 is the default loading address for DLLs linked with MSVC's linker, that area being off limits wouldn't make much sense.

Share this post


Link to post
Share on other sites
dbzprogrammer    100

unsigned int* ptr_to_mem = (unsigned int*) 0x00000000;
*ptr_to_mem = 0xFFFFFFFF;


Shouldn't you NOT have the dereference operator in the second line?

I think your getting an access violation because your trying to set the value (i.e. 5, not the memory adress) to 0xFFFFFFFF

Share this post


Link to post
Share on other sites
rip-off    10976
Quote:
Original post by dbzprogrammer

unsigned int* ptr_to_mem = (unsigned int*) 0x00000000;
*ptr_to_mem = 0xFFFFFFFF;


Shouldn't you NOT have the dereference operator in the second line?


either pointer is wrong. they are both arbitrary and dereferencing them will lead to a segfault (at best). if it isnt dereferenced then its pointless. if it is then storage should be allocated properly

Share this post


Link to post
Share on other sites
dbzprogrammer    100
Quote:
Original post by rip-off
Quote:
Original post by dbzprogrammer

unsigned int* ptr_to_mem = (unsigned int*) 0x00000000;
*ptr_to_mem = 0xFFFFFFFF;


Shouldn't you NOT have the dereference operator in the second line?


either pointer is wrong. they are both arbitrary and dereferencing them will lead to a segfault (at best). if it isnt dereferenced then its pointless. if it is then storage should be allocated properly


Then why is it compiling? God I'm so lost... Here's what I got. he's making a unsigned int pointer to some point in memory, and then is trying to change it to something else... Very interesting though!

Share this post


Link to post
Share on other sites
rip-off    10976
Quote:
Original post by dbzprogrammer
Quote:
Original post by rip-off
Quote:
Original post by dbzprogrammer

unsigned int* ptr_to_mem = (unsigned int*) 0x00000000;
*ptr_to_mem = 0xFFFFFFFF;


Shouldn't you NOT have the dereference operator in the second line?


either pointer is wrong. they are both arbitrary and dereferencing them will lead to a segfault (at best). if it isnt dereferenced then its pointless. if it is then storage should be allocated properly


Then why is it compiling? God I'm so lost... Very interesting though!


it is a run time issue. not a compilation error. its syntactiacally correct, but is logically incorrect (it wont do whats intended)

Share this post


Link to post
Share on other sites
LessBread    1415
Quote:
Original post by SiCrane
Quote:
Original post by LessBread
Yes, you can't just go picking randmon addresses and expect them to be valid. After reading the above link, you'll have a better idea of how virtual memory is organized and how it relates back to physical memory. For what it's worth, there are large "holes" in the virtual address space of a process. There's a huge one between 0x10000000 and 0x60000000 and addresses above 0x80000000 are off limits to user mode programs alltogether.


0x1000 0000 to 0x6000 0000 isn't off limits to the application. Seeing as 0x1000 0000 is the default loading address for DLLs linked with MSVC's linker, that area being off limits wouldn't make much sense.


I didn't say that range was off limits, I said it was an empty hole. I've been playing with some code that dump page tables and that range usually turns up empty. However, using dependencywalker to examine various exe reveals that many dlls have preferred base addresses in that range - for example on the XP installation on the PC I'm using to write this, gdiplus.dll prefers 0x4EC50000, dbghelp.dll prefers 0x59A60000, netapi32.dll prefers 0x5B860000, comctl32.dll prefers 0x5D090000 and olepro32.dll prefers 0x5EDD0000. Perhaps my observations pertained more to W2K, which is the OS on the PC that I ran the page table dumping code on. The off limits remark pertains to addresses above 0x80000000. You're not going to protest that are you?

Share this post


Link to post
Share on other sites
dbzprogrammer    100
Quote:
Original post by LessBread
Quote:
Original post by SiCrane
I suppose you don't want me to mention the /3GB switch then. :)


That would only confuse the issue! [smile]


How the hell do you guys know so much?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this