0

I'm running a simple program to show the memory capacity between the stack and the heap in the scope of a single process, and am receiving some strange values that I may be misunderstanding.

I'm running this block of code:

int main() {
  uint64_t *heap = new uint64_t;
  uint64_t stackvar; 

  uint64_t diff = &stackvar - heap;
  float size = (float) diff/ (1024 * 1024 * 1024);  // conversion to GB

  free(heap);

  return 0;
}

The address values of the allocated heap variable and the stack variable make sense, but I believe I am misinterpreting how to calculate the memory capacity between the two, as the final value of diff is in the range of 16TB once I run it through the conversion in the code above.

How do I effectively convert this range to an understandable memory range, or what is the proper interpretation of diff if I have made a mistake?

drescherjm
  • 10,365
  • 5
  • 44
  • 64
atf
  • 3
  • 3
  • 2
    @tf This statement uint64_t diff = &stackvar - heap; does not make sense and has undefined behavior. – Vlad from Moscow Nov 07 '19 at 15:38
  • 2
    I'm pretty sure it is UB to take the difference between pointers to objects not from the same allocation (be it a local array or a dynamic array) – Jeffrey Nov 07 '19 at 15:39
  • But if you were to count on this undefined behaviour, try the difference in the other direction (heap - &stackvar) too. – Jeffrey Nov 07 '19 at 15:40
  • 1
    Why does 16TB seem unreasonable? You are dealing with virtual, *not* physical, addresses after all. – Jesper Juhl Nov 07 '19 at 15:42
  • 2
    You `free`d when you should have `delete`d btw. This is UB (too). – nada Nov 07 '19 at 15:44
  • 4
    Even if you manage to get the difference, it has nothing to do with capacity whatsoever. The addresses are virtual, and that space might not even be mapped or accessible. – Eugene Sh. Nov 07 '19 at 15:47
  • @EugeneSh. OP _might_ be trying to run this in an OS like DOS with real mode memory access. Memory (addresses) do not have to be virtualized. – nada Nov 07 '19 at 15:48
  • 1
    @nada Could be but highly unlikely.. And I believe the memory space in DOS real mode was highly restricted - 20bit of address width or so... – Eugene Sh. Nov 07 '19 at 15:52
  • A modern operating system may randomize the layout as well. So running this program multiple times may return very different answers.[https://en.wikipedia.org/wiki/Address_space_layout_randomization](https://en.wikipedia.org/wiki/Address_space_layout_randomization) – drescherjm Nov 07 '19 at 15:53
  • @EugeneSh. Well maybe OP's developing his/her/x own OS. Then this question would maybe even make a little more sense (?) I don't know – nada Nov 07 '19 at 15:54
  • 1
    @nada, thank you for the tips, I'll make sure to keep them in mind! I am simply running this in Ubuntu, and was going off the fundamental of 'stack grows down, heap grows up' etc that is probably unrealistic in modern systems. Part of this was trying to find the correlation between the virtual mappings of the stack and heap, and how (if at all) I could find the virtual size between the two. – atf Nov 07 '19 at 16:02
  • This may help: [https://linux-kernel-labs.github.io/master/labs/memory_mapping.html](https://linux-kernel-labs.github.io/master/labs/memory_mapping.html) and [https://www.cyberciti.biz/faq/linux-viewing-process-address-space-command/](https://www.cyberciti.biz/faq/linux-viewing-process-address-space-command) – drescherjm Nov 07 '19 at 18:47
  • regarding: `uint64_t *heap = new uint64_t;` This is a C++ statement. However, `free(heap);` is a C statement. Don't mix statements from two different languages – user3629249 Nov 08 '19 at 16:44
  • @user3629249 I will keep that in mind, thank you! :) – atf Nov 11 '19 at 14:09

2 Answers2

7

&stackvar - heap is undefined behavior. Whatever result you get from it is pointless. Unless the pointers point into the same array or a both nullptr subtracting them is undefined behavior. This is detailed in [expr.add]/5

When two pointer expressions P and Q are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std​::​ptrdiff_­t in the header ([support.types.layout]).

  • If P and Q both evaluate to null pointer values, the result is 0.

  • Otherwise, if P and Q point to, respectively, array elements i and j of the same array object x, the expression P - Q has the value i−j.

  • Otherwise, the behavior is undefined. [ Note: If the value i−j is not in the range of representable values of type std​::​ptrdiff_­t, the behavior is undefined. — end note ]

emphasis mine

Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

Also note that the process memory is not necessary to be continuous and pointers may not actually points to physical memory locations. this due to virtual memory and physcal memory translation What are the differences between virtual memory and physical memory? so in most cases you never get the correct distance between heap an stack.

Ahmed Anter
  • 650
  • 4
  • 13