0

I'm trying to study how Linux would behave if I were to allocate a 10 bytes of memory at every page boundary for a total of ten pages. Here is the program I could come up with:

  1 #include <stdlib.h>$
  2 #include <stdio.h>$
  3 #include <time.h>$
  4 #include <unistd.h>$
  5 #include <string.h>$
  6 $
  7 #define PAGESIZE getpagesize()$
  8 int main () {$
  9     int *ArrP[10] = {NULL};$
 10     int pgSz = PAGESIZE;$
 11     int randnum;$
 12 $
 13     
 14     for (int i = 0; i < (sizeof(ArrP)/sizeof(int*)); i++) {$
 15         if(posix_memalign((void **)&ArrP[i], pgSz, 10)) {$
 16             perror("error getting page aligned mem: ");$
 17             exit(1);$
 18         }$
 19         else$
 20             printf("ArrP[%d] = %lu\n", i, ArrP[i]);$
 21     }$
 22 $
 23     srand(time(0));$
 24     while(1) {$
 25         for (int i = 0; i <(sizeof(ArrP)/sizeof(int*)); i++) {$
 26             randnum = rand();$
 27             memcpy(ArrP[i], &randnum, sizeof(int));$
 28         }$
 29     }$
 30     return 0;$
 31 }$

However when I run it, the /proc/pid/maps file shows a heap size of 0. here's the content of that file:

555555554000-555555555000 r--p 00000000 08:01 1966744                    /home/AB1/ProgPractice/InternalFragmentation
555555555000-555555556000 r-xp 00001000 08:01 1966744                    /home/AB1/ProgPractice/InternalFragmentation
555555556000-555555557000 r--p 00002000 08:01 1966744                    /home/AB1/ProgPractice/InternalFragmentation
555555557000-555555558000 r--p 00002000 08:01 1966744                    /home/AB1/ProgPractice/InternalFragmentation
555555558000-555555559000 rw-p 00003000 08:01 1966744                    /home/AB1/ProgPractice/InternalFragmentation
555555559000-55555557a000 rw-p 00000000 00:00 0                          [heap]
7ffff7dd8000-7ffff7dfd000 r--p 00000000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7dfd000-7ffff7f4a000 r-xp 00025000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7f4a000-7ffff7f94000 r--p 00172000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7f94000-7ffff7f95000 ---p 001bc000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7f95000-7ffff7f98000 r--p 001bc000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7f98000-7ffff7f9b000 rw-p 001bf000 08:01 2234184                    /usr/lib/libc-2.30.so
7ffff7f9b000-7ffff7fa1000 rw-p 00000000 00:00 0
7ffff7fce000-7ffff7fd1000 r--p 00000000 00:00 0                          [vvar]
7ffff7fd1000-7ffff7fd2000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fd2000-7ffff7fd4000 r--p 00000000 08:01 2234140                    /usr/lib/ld-2.30.so
7ffff7fd4000-7ffff7ff3000 r-xp 00002000 08:01 2234140                    /usr/lib/ld-2.30.so
7ffff7ff3000-7ffff7ffb000 r--p 00021000 08:01 2234140                    /usr/lib/ld-2.30.so
7ffff7ffc000-7ffff7ffd000 r--p 00029000 08:01 2234140                    /usr/lib/ld-2.30.so
7ffff7ffd000-7ffff7ffe000 rw-p 0002a000 08:01 2234140                    /usr/lib/ld-2.30.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

I've disabled ASLR but it doesn't make a difference. Any suggestions

AjB
  • 890
  • 13
  • 34
  • 1
    When you post code, please post *valid* code. Line numbers and those weird `$` characters at the end of every line are not characteristics of valid code. – John Bollinger Mar 25 '20 at 12:58
  • `(void **)&ArrP[i]` is questionable. It likely leads to a violation of the strict-aliasing rule. – John Bollinger Mar 25 '20 at 13:00
  • 2
    `555555559000-55555557a000` is not zero size. – DaBler Mar 25 '20 at 13:04
  • `%lu` is not the proper format string to print a pointer. The proper format string is `%p`, but you have to cast the pointer to `void *` to be fully conformant. – Andrew Henle Mar 25 '20 at 13:08
  • Oh ok. My bad. I confused the offset with size – AjB Mar 25 '20 at 13:09
  • @JohnBollinger could you elaborate on what you mean in your second comment? – AjB Mar 25 '20 at 13:13
  • You misunderstand what `/proc/pid/maps` is telling you. To get the *RAM* size of a `/proc/pid/maps` entry you have to take the difference of the first two numbers on the line; the number in the sixth column is only meaningful for file maps, not "anonymous" memory allocations. Also, the "heap" allocation is the one controlled by the `sbrk` system call; `posix_memalign` may call `mmap` instead. (You can check this with `strace`. The entry at `7ffff7f9b000-7ffff7fa1000` appears to be RAM allocated with `mmap`.) – zwol Mar 25 '20 at 13:51
  • Also also, almost all C library functions are allowed to make internal calls to `malloc` for scratch storage, so not all of the space in the heap(s) necessarily belongs to allocations made directly by your program. – zwol Mar 25 '20 at 13:54
  • @zwol how do I use strace in a program – AjB Mar 25 '20 at 14:06
  • @HighOnMeat, it is allowed to convert an object pointer to a different object-pointer type, as the expression I called out does, but in many cases it produces undefined behavior to access the pointed-to object through the converted pointer. `posix_memalign()` will produce exactly such undefined behavior when it writes the address of the allocated memory through the pointer you provide as its first argument, because `void *` and `int *` are not compatible types. In practice, the UB is likely to take the form of the behavior you are expecting anyway, but it is not safe to rely on that. – John Bollinger Mar 25 '20 at 22:31
  • @JohnBollinger but that is what ‘posix_memalign’ expects doesn’t it? Which is why I did that. Most examples of this do it exactly like that – AjB Mar 26 '20 at 07:13
  • @HighOnMeat, the problem is the type mismatch. `posix_memalign()` expects a pointer to a `void *`. Cast notwithstanding, the thing that actually resides where the pointer you pass points is an `int *`. These are not the same thing, and accessing an object of one of these types as if it had the other type produces undefined behavior. This is so *even if these two type have the same size and representation*, as they will on all POSIX-conforming systems. Again, the manifestation of the UB is fairly likely to be what you expected anyway, but that just makes the issue more insidious. – John Bollinger Mar 26 '20 at 12:26
  • @JohnBollinger do you imply that if I cast it that way (void **) to satisfy the compiler, it might result in undefined behavior with the memory? – AjB Mar 27 '20 at 10:53
  • @HighOnMeat, I mean that casting the original pointer is not the correct way to address the compiler diagnostic, and doing it *does* result in UB in your case. The correct solution is to pass a pointer that really does point to a `void *`. You could arrange for that by changing the element type of the array or by using a temporary. Casts are rarely an appropriate solution to anything, and pretty much every cast has mild code smell. – John Bollinger Mar 27 '20 at 12:28

0 Answers0