- In Java, when JVM process starts, then some memory (defined by Xms and Xmx) is allocated. How do we know that how much memory is
allocated in case of C program, and can we control this program
memory?
programs written in Java have memory automatically managed for them. the case is different in C. that is, you can simulate that manually by taking minimum and maximum heap sizes as command-line arguments and allocating the minimum heap size (using a function from the malloc
family) as the program starts running and extend that during execution using realloc
.
since you allocate memory manually, you can keep track of the amount of memory that was allocated and not allow your allocated memory to exceed the maximum heap size.
- In Java, heap memory need not to be contiguous. How it is in case of C?
it's not guaranteed that separate memory allocations will allocate contiguous blocks. memory allocated on/freed from the heap is done dynamically as the program is running.
memory that gets freed is available to use again. so you may allocate a chunk from address 100 to 103, another chunk from 104 to 107, and a third chunk from 108 to 111.
if the middle chunk is freed, it becomes available to use and it might get allocated next time you allocate 4 bytes instead of 112 to 115.
- My understanding is that this memory is nothing but the memory allocated by OS to the C program, and not the complete OS RAM? Right?
well, this memory may not be allocated for your program. unlike Java where you get an exception for trying to access an out-of-bounds array index, the behavior of such operation in C is undefined. you never know what you're gonna get. for example, you may get the value that lives in this location at the moment, your program may crash immediately, etc.
If it is right then how a bad guy can access the passwords which may
be in my program's memory, because to access those areas he would need
the argv array, but then how we would have it because I am running the
program?
apparently you're referring to the problem of buffer overflow and you don't get the risk very well. here is the general idea with a fairly simple example:
let's say you allocated a piece of memory (a buffer) on the stack to take some input from the user and store it on that memory.
if you're not careful (i.e., ensuring the buffer is big enough to hold the data before you store it), the user may pass data until the buffer is filled and overflowed. meanwhile, whatever the user passes may keep getting stored in the contiguous blocks.
the are multiple chances for exploitation as a result of overflowing a buffer. for example, the hacker could be overwriting the value of some variable that would make the program behave in a way that would benefit the hacker.
the hacker could overwrite the return address of a function so that when the function returns, the presumably malicious code in the return address he/she specified will execute.