If the heap is zero-initialized for security, then why is the stack merely uninitialized? The Next CEO of Stack OverflowSystem sending SIGTERM and SIGKILL during normal workwhy is “timer_t” defined in “time.h” on Linux but not OS XWhich parts of Memory can Swap Supportsecurity issues from installing from source code as rootWhat are the most restrictive external firewall / DNS listening port settings I can have for my DNS server (internal clients only)Trying to understanding startup procedure of monitWhy must the stack VMA be executable?When is the heap used for dynamic memory allocation?Is copy-on-write not implemented based on page fault?What happens to the old stack, heap, and (initialized and uninitialized) data segments after execve() call?

Is French Guiana a (hard) EU border?

Reference request: Grassmannian and Plucker coordinates in type B, C, D

Running a General Election and the European Elections together

What is meant by "large scale tonal organization?"

Can MTA send mail via a relay without being told so?

How to write a definition with variants?

If the heap is zero-initialized for security, then why is the stack merely uninitialized?

Recycling old answers

What connection does MS Office have to Netscape Navigator?

How to check if all elements of 1 list are in the *same quantity* and in any order, in the list2?

Writing differences on a blackboard

What did we know about the Kessel run before the prequels?

Can we say or write : "No, it'sn't"?

Calculator final project in Python

Can Plant Growth be repeatedly cast on the same area to exponentially increase the yield of harvests there (more than twice)?

How many extra stops do monopods offer for tele photographs?

How to invert MapIndexed on a ragged structure? How to construct a tree from rules?

A small doubt about the dominated convergence theorem

Why does the flight controls check come before arming the autobrake on the A320?

What was the first Unix version to run on a microcomputer?

How to edit “Name” property in GCI output?

Prepend last line of stdin to entire stdin

Does Germany produce more waste than the US?

Easy to read palindrome checker



If the heap is zero-initialized for security, then why is the stack merely uninitialized?



The Next CEO of Stack OverflowSystem sending SIGTERM and SIGKILL during normal workwhy is “timer_t” defined in “time.h” on Linux but not OS XWhich parts of Memory can Swap Supportsecurity issues from installing from source code as rootWhat are the most restrictive external firewall / DNS listening port settings I can have for my DNS server (internal clients only)Trying to understanding startup procedure of monitWhy must the stack VMA be executable?When is the heap used for dynamic memory allocation?Is copy-on-write not implemented based on page fault?What happens to the old stack, heap, and (initialized and uninitialized) data segments after execve() call?










14















On my Debian GNU/Linux 9 system, when a binary is executed,



  • the stack is uninitialized but

  • the heap is zero-initialized.

Why?



I assume that zero-initialization promotes security but, if for the heap, then why not also for the stack? Does the stack, too, not need security?



My question is not specific to Debian as far as I know.



Sample C code:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 8;

// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)

printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("n");


// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()

int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;



Output:



a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713 
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0


The C standard does not ask malloc() to clear memory before allocating it, of course, but my C program is merely for illustration. The question is not a question about C or about C's standard library. Rather, the question is a question about why the kernel and/or run-time loader are zeroing the heap but not the stack.



ANOTHER EXPERIMENT



My question regards observable GNU/Linux behavior rather than the requirements of standards documents. If unsure what I mean, then try this code, which invokes further undefined behavior (undefined, that is, as far as the C standard is concerned) to illustrate the point:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%dn", *p);
free(p);

return 0;



Output from my machine:



0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1


As far as the C standard is concerned, behavior is undefined, so my question does not regard the C standard. A call to malloc() need not return the same address each time but, since this call to malloc() does indeed happen to return the same address each time, it is interesting to notice that the memory, which is on the heap, is zeroed each time.



The stack, by contrast, had not seemed to be zeroed.



I do not know what the latter code will do on your machine, since I do not know which layer of the GNU/Linux system is causing the observed behavior. You can but try it.



UPDATE



@Kusalananda has observed in comments:




For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.




That my result differs from the result on OpenBSD is indeed interesting. Apparently, my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.



In this light, I believe that, together, the answers below of @mosvy, @StephenKitt and @AndreasGrapentin settle my question.



See also on Stack Overflow: Why does malloc initialize the values to 0 in gcc? (credit: @bta).










share|improve this question



















  • 2





    For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

    – Kusalananda
    2 days ago












  • Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

    – mosvy
    2 days ago







  • 3





    Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

    – mosvy
    2 days ago












  • @Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

    – thb
    2 days ago











  • @thb I believe that this may be a correct observation, yes.

    – Kusalananda
    2 days ago















14















On my Debian GNU/Linux 9 system, when a binary is executed,



  • the stack is uninitialized but

  • the heap is zero-initialized.

Why?



I assume that zero-initialization promotes security but, if for the heap, then why not also for the stack? Does the stack, too, not need security?



My question is not specific to Debian as far as I know.



Sample C code:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 8;

// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)

printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("n");


// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()

int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;



Output:



a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713 
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0


The C standard does not ask malloc() to clear memory before allocating it, of course, but my C program is merely for illustration. The question is not a question about C or about C's standard library. Rather, the question is a question about why the kernel and/or run-time loader are zeroing the heap but not the stack.



ANOTHER EXPERIMENT



My question regards observable GNU/Linux behavior rather than the requirements of standards documents. If unsure what I mean, then try this code, which invokes further undefined behavior (undefined, that is, as far as the C standard is concerned) to illustrate the point:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%dn", *p);
free(p);

return 0;



Output from my machine:



0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1


As far as the C standard is concerned, behavior is undefined, so my question does not regard the C standard. A call to malloc() need not return the same address each time but, since this call to malloc() does indeed happen to return the same address each time, it is interesting to notice that the memory, which is on the heap, is zeroed each time.



The stack, by contrast, had not seemed to be zeroed.



I do not know what the latter code will do on your machine, since I do not know which layer of the GNU/Linux system is causing the observed behavior. You can but try it.



UPDATE



@Kusalananda has observed in comments:




For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.




That my result differs from the result on OpenBSD is indeed interesting. Apparently, my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.



In this light, I believe that, together, the answers below of @mosvy, @StephenKitt and @AndreasGrapentin settle my question.



See also on Stack Overflow: Why does malloc initialize the values to 0 in gcc? (credit: @bta).










share|improve this question



















  • 2





    For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

    – Kusalananda
    2 days ago












  • Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

    – mosvy
    2 days ago







  • 3





    Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

    – mosvy
    2 days ago












  • @Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

    – thb
    2 days ago











  • @thb I believe that this may be a correct observation, yes.

    – Kusalananda
    2 days ago













14












14








14


0






On my Debian GNU/Linux 9 system, when a binary is executed,



  • the stack is uninitialized but

  • the heap is zero-initialized.

Why?



I assume that zero-initialization promotes security but, if for the heap, then why not also for the stack? Does the stack, too, not need security?



My question is not specific to Debian as far as I know.



Sample C code:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 8;

// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)

printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("n");


// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()

int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;



Output:



a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713 
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0


The C standard does not ask malloc() to clear memory before allocating it, of course, but my C program is merely for illustration. The question is not a question about C or about C's standard library. Rather, the question is a question about why the kernel and/or run-time loader are zeroing the heap but not the stack.



ANOTHER EXPERIMENT



My question regards observable GNU/Linux behavior rather than the requirements of standards documents. If unsure what I mean, then try this code, which invokes further undefined behavior (undefined, that is, as far as the C standard is concerned) to illustrate the point:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%dn", *p);
free(p);

return 0;



Output from my machine:



0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1


As far as the C standard is concerned, behavior is undefined, so my question does not regard the C standard. A call to malloc() need not return the same address each time but, since this call to malloc() does indeed happen to return the same address each time, it is interesting to notice that the memory, which is on the heap, is zeroed each time.



The stack, by contrast, had not seemed to be zeroed.



I do not know what the latter code will do on your machine, since I do not know which layer of the GNU/Linux system is causing the observed behavior. You can but try it.



UPDATE



@Kusalananda has observed in comments:




For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.




That my result differs from the result on OpenBSD is indeed interesting. Apparently, my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.



In this light, I believe that, together, the answers below of @mosvy, @StephenKitt and @AndreasGrapentin settle my question.



See also on Stack Overflow: Why does malloc initialize the values to 0 in gcc? (credit: @bta).










share|improve this question
















On my Debian GNU/Linux 9 system, when a binary is executed,



  • the stack is uninitialized but

  • the heap is zero-initialized.

Why?



I assume that zero-initialization promotes security but, if for the heap, then why not also for the stack? Does the stack, too, not need security?



My question is not specific to Debian as far as I know.



Sample C code:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 8;

// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)

printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("n");


// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()

int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;



Output:



a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713 
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0


The C standard does not ask malloc() to clear memory before allocating it, of course, but my C program is merely for illustration. The question is not a question about C or about C's standard library. Rather, the question is a question about why the kernel and/or run-time loader are zeroing the heap but not the stack.



ANOTHER EXPERIMENT



My question regards observable GNU/Linux behavior rather than the requirements of standards documents. If unsure what I mean, then try this code, which invokes further undefined behavior (undefined, that is, as far as the C standard is concerned) to illustrate the point:



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%dn", *p);
free(p);

return 0;



Output from my machine:



0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1


As far as the C standard is concerned, behavior is undefined, so my question does not regard the C standard. A call to malloc() need not return the same address each time but, since this call to malloc() does indeed happen to return the same address each time, it is interesting to notice that the memory, which is on the heap, is zeroed each time.



The stack, by contrast, had not seemed to be zeroed.



I do not know what the latter code will do on your machine, since I do not know which layer of the GNU/Linux system is causing the observed behavior. You can but try it.



UPDATE



@Kusalananda has observed in comments:




For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.




That my result differs from the result on OpenBSD is indeed interesting. Apparently, my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.



In this light, I believe that, together, the answers below of @mosvy, @StephenKitt and @AndreasGrapentin settle my question.



See also on Stack Overflow: Why does malloc initialize the values to 0 in gcc? (credit: @bta).







linux security memory






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday









Jacob Jones

28117




28117










asked 2 days ago









thbthb

601517




601517







  • 2





    For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

    – Kusalananda
    2 days ago












  • Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

    – mosvy
    2 days ago







  • 3





    Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

    – mosvy
    2 days ago












  • @Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

    – thb
    2 days ago











  • @thb I believe that this may be a correct observation, yes.

    – Kusalananda
    2 days ago












  • 2





    For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

    – Kusalananda
    2 days ago












  • Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

    – mosvy
    2 days ago







  • 3





    Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

    – mosvy
    2 days ago












  • @Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

    – thb
    2 days ago











  • @thb I believe that this may be a correct observation, yes.

    – Kusalananda
    2 days ago







2




2





For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

– Kusalananda
2 days ago






For what it's worth, your most recent code returns different addresses and (occasional) uninitialised (non-zero) data when run on OpenBSD. This obviously does not say anything about the behaviour that you are witnessing on Linux.

– Kusalananda
2 days ago














Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

– mosvy
2 days ago






Please do not change the scope of your question, and do not try to edit it in order to make answers and comments redundant. In C, the "heap" is nothing else but the memory returned by malloc() and calloc(), and only the latter is zeroing out the memory; the new operator in C++ (also "heap") is on Linux just a wrapper for malloc(); the kernel doesn't know nor care what the "heap" is.

– mosvy
2 days ago





3




3





Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

– mosvy
2 days ago






Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed.

– mosvy
2 days ago














@Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

– thb
2 days ago





@Kusalananda I see. That my result differs from the result on OpenBSD is indeed interesting. Apparently, you and Mosvy have shown that my experiments were discovering not a kernel (or linker) security protocol, as I had thought, but a mere implementational artifact.

– thb
2 days ago













@thb I believe that this may be a correct observation, yes.

– Kusalananda
2 days ago





@thb I believe that this may be a correct observation, yes.

– Kusalananda
2 days ago










4 Answers
4






active

oldest

votes


















26














The storage returned by malloc() is not zero-initialized. Do not ever assume it is.



In your test program, it's just a fluke: I guess the malloc()just got a fresh block off mmap(), but don't rely on that, either.



For an example, if I run your program on my machine this way:



$ echo 'void __attribute__((constructor)) p(void)
void *b = malloc(4444); memset(b, 4, 4444); free(b);
' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036


Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed, as in the following sample code.



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j)
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);

free(p);
printf("n");

return 0;



Output:



0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4





share|improve this answer




















  • 1





    Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

    – thb
    2 days ago






  • 17





    I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

    – mosvy
    2 days ago



















22














Regardless of how the stack is initialised, you’re not seeing a pristine stack, because the C library does a number of things before calling main, and they touch the stack.



With the GNU C library, on x86-64, execution starts at the _start entry point, which calls __libc_start_main to set things up, and the latter ends up calling main. But before calling main, it calls a number of other functions, which causes various pieces of data to be written to the stack. The stack’s contents aren’t cleared in between function calls, so when you get into main, your stack contains leftovers from the previous function calls.



This only explains the results you get from the stack, see the other answers regarding your general approach and assumptions.






share|improve this answer

























  • Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

    – Andrew Henle
    2 days ago











  • Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

    – thb
    2 days ago


















16














In both cases, you get uninitialized memory, and you can't make any assumptions about its contents.



When the OS has to apportion a new page to your process (whether that's for its stack or for the arena used by malloc()), it guarantees that it won't expose data from other processes; the usual way to ensure that is to fill it with zeros (but it's equally valid to overwrite with anything else, including even a page worth of /dev/urandom - in fact some debugging malloc() implementations write non-zero patterns, to catch mistaken assumptions such as yours).



If malloc() can satisfy the request from memory already used and released by this process, its contents won't be cleared (in fact, the clearing is nothing to do with malloc() and it can't be - it has to happen before the memory is mapped into your address space). You may get memory that has previously been written by your process/program (e.g. before main()).



In your example program, you're seeing a malloc() region that hasn't yet been written by this process (i.e. it's direct from a new page) and a stack that has been written to (by pre-main() code in your program). If you examine more of the stack, you'll find it's zero-filled further down (in its direction of growth).



If you really want to understand what's happening at the OS level, I recommend that you bypass the C Library layer and interact using system calls such as brk() and mmap() instead.






share|improve this answer




















  • 1





    A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

    – thb
    2 days ago







  • 1





    @thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

    – Toby Speight
    2 days ago







  • 1





    @TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

    – Joshua
    2 days ago







  • 1





    @Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

    – Toby Speight
    2 days ago






  • 2





    If you need initialized memory using calloc might be an option (instead of memset)

    – eckes
    2 days ago


















5














Your premise is wrong.



What you describe as 'security' is really confidentiality, meaning that no process may read another processes memory, unless this memory is explicitly shared between these processes. In an operating system, this is one aspect of the isolation of concurrent activities, or processes.



What the operating system is doing to ensure this isolation, is whenever memory is requested by the process for heap or stack allocations, this memory is either coming from a region in physical memory that is filled whith zeroes, or that is filled with junk that is coming from the same process.



This ensures that you're only ever seeing zeroes, or your own junk, so confidentiality is ensured, and both heap and stack are 'secure', albeit not necessarily (zero-)initialized.



You're reading too much into your measurements.






share|improve this answer








New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 1





    The question's Update section now explicitly references your illuminating answer.

    – thb
    yesterday









protected by Kusalananda yesterday



Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



Would you like to answer one of these unanswered questions instead?














4 Answers
4






active

oldest

votes








4 Answers
4






active

oldest

votes









active

oldest

votes






active

oldest

votes









26














The storage returned by malloc() is not zero-initialized. Do not ever assume it is.



In your test program, it's just a fluke: I guess the malloc()just got a fresh block off mmap(), but don't rely on that, either.



For an example, if I run your program on my machine this way:



$ echo 'void __attribute__((constructor)) p(void)
void *b = malloc(4444); memset(b, 4, 4444); free(b);
' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036


Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed, as in the following sample code.



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j)
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);

free(p);
printf("n");

return 0;



Output:



0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4





share|improve this answer




















  • 1





    Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

    – thb
    2 days ago






  • 17





    I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

    – mosvy
    2 days ago
















26














The storage returned by malloc() is not zero-initialized. Do not ever assume it is.



In your test program, it's just a fluke: I guess the malloc()just got a fresh block off mmap(), but don't rely on that, either.



For an example, if I run your program on my machine this way:



$ echo 'void __attribute__((constructor)) p(void)
void *b = malloc(4444); memset(b, 4, 4444); free(b);
' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036


Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed, as in the following sample code.



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j)
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);

free(p);
printf("n");

return 0;



Output:



0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4





share|improve this answer




















  • 1





    Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

    – thb
    2 days ago






  • 17





    I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

    – mosvy
    2 days ago














26












26








26







The storage returned by malloc() is not zero-initialized. Do not ever assume it is.



In your test program, it's just a fluke: I guess the malloc()just got a fresh block off mmap(), but don't rely on that, either.



For an example, if I run your program on my machine this way:



$ echo 'void __attribute__((constructor)) p(void)
void *b = malloc(4444); memset(b, 4, 4444); free(b);
' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036


Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed, as in the following sample code.



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j)
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);

free(p);
printf("n");

return 0;



Output:



0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4





share|improve this answer















The storage returned by malloc() is not zero-initialized. Do not ever assume it is.



In your test program, it's just a fluke: I guess the malloc()just got a fresh block off mmap(), but don't rely on that, either.



For an example, if I run your program on my machine this way:



$ echo 'void __attribute__((constructor)) p(void)
void *b = malloc(4444); memset(b, 4, 4444); free(b);
' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036


Your second example is simply exposing an artifact of the malloc implementation in glibc; if you do that repeated malloc/free with a buffer larger than 8 bytes, you will clearly see that only the first 8 bytes are zeroed, as in the following sample code.



#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()

for (size_t i = n; i; --i)
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j)
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);

free(p);
printf("n");

return 0;



Output:



0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4






share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago









thb

601517




601517










answered 2 days ago









mosvymosvy

8,8621833




8,8621833







  • 1





    Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

    – thb
    2 days ago






  • 17





    I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

    – mosvy
    2 days ago













  • 1





    Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

    – thb
    2 days ago






  • 17





    I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

    – mosvy
    2 days ago








1




1





Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

– thb
2 days ago





Well, yes, but this is why I have asked the question here rather than on Stack Overflow. My question was not about the C standard but about the way modern GNU/Linux systems typically link and load binaries. Your LD_PRELOAD is humorous but answers another question than the question I had meant to ask.

– thb
2 days ago




17




17





I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

– mosvy
2 days ago






I'm happy I made you laugh, but your assumptions and prejudices aren't funny at all. On a "modern GNU/Linux system", binaries are typically loaded by a dynamic linker, which is running constructors from dynamic libraries before getting to the main() function from your program. On your very Debian GNU/Linux 9 system, both malloc() and free() will be called more than once before the main() function from your program, even when not using any preloaded libraries.

– mosvy
2 days ago














22














Regardless of how the stack is initialised, you’re not seeing a pristine stack, because the C library does a number of things before calling main, and they touch the stack.



With the GNU C library, on x86-64, execution starts at the _start entry point, which calls __libc_start_main to set things up, and the latter ends up calling main. But before calling main, it calls a number of other functions, which causes various pieces of data to be written to the stack. The stack’s contents aren’t cleared in between function calls, so when you get into main, your stack contains leftovers from the previous function calls.



This only explains the results you get from the stack, see the other answers regarding your general approach and assumptions.






share|improve this answer

























  • Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

    – Andrew Henle
    2 days ago











  • Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

    – thb
    2 days ago















22














Regardless of how the stack is initialised, you’re not seeing a pristine stack, because the C library does a number of things before calling main, and they touch the stack.



With the GNU C library, on x86-64, execution starts at the _start entry point, which calls __libc_start_main to set things up, and the latter ends up calling main. But before calling main, it calls a number of other functions, which causes various pieces of data to be written to the stack. The stack’s contents aren’t cleared in between function calls, so when you get into main, your stack contains leftovers from the previous function calls.



This only explains the results you get from the stack, see the other answers regarding your general approach and assumptions.






share|improve this answer

























  • Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

    – Andrew Henle
    2 days ago











  • Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

    – thb
    2 days ago













22












22








22







Regardless of how the stack is initialised, you’re not seeing a pristine stack, because the C library does a number of things before calling main, and they touch the stack.



With the GNU C library, on x86-64, execution starts at the _start entry point, which calls __libc_start_main to set things up, and the latter ends up calling main. But before calling main, it calls a number of other functions, which causes various pieces of data to be written to the stack. The stack’s contents aren’t cleared in between function calls, so when you get into main, your stack contains leftovers from the previous function calls.



This only explains the results you get from the stack, see the other answers regarding your general approach and assumptions.






share|improve this answer















Regardless of how the stack is initialised, you’re not seeing a pristine stack, because the C library does a number of things before calling main, and they touch the stack.



With the GNU C library, on x86-64, execution starts at the _start entry point, which calls __libc_start_main to set things up, and the latter ends up calling main. But before calling main, it calls a number of other functions, which causes various pieces of data to be written to the stack. The stack’s contents aren’t cleared in between function calls, so when you get into main, your stack contains leftovers from the previous function calls.



This only explains the results you get from the stack, see the other answers regarding your general approach and assumptions.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered 2 days ago









Stephen KittStephen Kitt

179k24406484




179k24406484












  • Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

    – Andrew Henle
    2 days ago











  • Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

    – thb
    2 days ago

















  • Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

    – Andrew Henle
    2 days ago











  • Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

    – thb
    2 days ago
















Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

– Andrew Henle
2 days ago





Note that by the time main() is called, initialization routines may very well have modified memory returned by malloc() - especially if C++ libraries are linked in. Assuming the "heap" is initialized to anything is a really, really bad assumption.

– Andrew Henle
2 days ago













Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

– thb
2 days ago





Your answer together with the Mosvy's settle my question. The system unfortunately allows me to accept only one of the two; otherwise, I would accept both.

– thb
2 days ago











16














In both cases, you get uninitialized memory, and you can't make any assumptions about its contents.



When the OS has to apportion a new page to your process (whether that's for its stack or for the arena used by malloc()), it guarantees that it won't expose data from other processes; the usual way to ensure that is to fill it with zeros (but it's equally valid to overwrite with anything else, including even a page worth of /dev/urandom - in fact some debugging malloc() implementations write non-zero patterns, to catch mistaken assumptions such as yours).



If malloc() can satisfy the request from memory already used and released by this process, its contents won't be cleared (in fact, the clearing is nothing to do with malloc() and it can't be - it has to happen before the memory is mapped into your address space). You may get memory that has previously been written by your process/program (e.g. before main()).



In your example program, you're seeing a malloc() region that hasn't yet been written by this process (i.e. it's direct from a new page) and a stack that has been written to (by pre-main() code in your program). If you examine more of the stack, you'll find it's zero-filled further down (in its direction of growth).



If you really want to understand what's happening at the OS level, I recommend that you bypass the C Library layer and interact using system calls such as brk() and mmap() instead.






share|improve this answer




















  • 1





    A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

    – thb
    2 days ago







  • 1





    @thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

    – Toby Speight
    2 days ago







  • 1





    @TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

    – Joshua
    2 days ago







  • 1





    @Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

    – Toby Speight
    2 days ago






  • 2





    If you need initialized memory using calloc might be an option (instead of memset)

    – eckes
    2 days ago















16














In both cases, you get uninitialized memory, and you can't make any assumptions about its contents.



When the OS has to apportion a new page to your process (whether that's for its stack or for the arena used by malloc()), it guarantees that it won't expose data from other processes; the usual way to ensure that is to fill it with zeros (but it's equally valid to overwrite with anything else, including even a page worth of /dev/urandom - in fact some debugging malloc() implementations write non-zero patterns, to catch mistaken assumptions such as yours).



If malloc() can satisfy the request from memory already used and released by this process, its contents won't be cleared (in fact, the clearing is nothing to do with malloc() and it can't be - it has to happen before the memory is mapped into your address space). You may get memory that has previously been written by your process/program (e.g. before main()).



In your example program, you're seeing a malloc() region that hasn't yet been written by this process (i.e. it's direct from a new page) and a stack that has been written to (by pre-main() code in your program). If you examine more of the stack, you'll find it's zero-filled further down (in its direction of growth).



If you really want to understand what's happening at the OS level, I recommend that you bypass the C Library layer and interact using system calls such as brk() and mmap() instead.






share|improve this answer




















  • 1





    A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

    – thb
    2 days ago







  • 1





    @thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

    – Toby Speight
    2 days ago







  • 1





    @TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

    – Joshua
    2 days ago







  • 1





    @Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

    – Toby Speight
    2 days ago






  • 2





    If you need initialized memory using calloc might be an option (instead of memset)

    – eckes
    2 days ago













16












16








16







In both cases, you get uninitialized memory, and you can't make any assumptions about its contents.



When the OS has to apportion a new page to your process (whether that's for its stack or for the arena used by malloc()), it guarantees that it won't expose data from other processes; the usual way to ensure that is to fill it with zeros (but it's equally valid to overwrite with anything else, including even a page worth of /dev/urandom - in fact some debugging malloc() implementations write non-zero patterns, to catch mistaken assumptions such as yours).



If malloc() can satisfy the request from memory already used and released by this process, its contents won't be cleared (in fact, the clearing is nothing to do with malloc() and it can't be - it has to happen before the memory is mapped into your address space). You may get memory that has previously been written by your process/program (e.g. before main()).



In your example program, you're seeing a malloc() region that hasn't yet been written by this process (i.e. it's direct from a new page) and a stack that has been written to (by pre-main() code in your program). If you examine more of the stack, you'll find it's zero-filled further down (in its direction of growth).



If you really want to understand what's happening at the OS level, I recommend that you bypass the C Library layer and interact using system calls such as brk() and mmap() instead.






share|improve this answer















In both cases, you get uninitialized memory, and you can't make any assumptions about its contents.



When the OS has to apportion a new page to your process (whether that's for its stack or for the arena used by malloc()), it guarantees that it won't expose data from other processes; the usual way to ensure that is to fill it with zeros (but it's equally valid to overwrite with anything else, including even a page worth of /dev/urandom - in fact some debugging malloc() implementations write non-zero patterns, to catch mistaken assumptions such as yours).



If malloc() can satisfy the request from memory already used and released by this process, its contents won't be cleared (in fact, the clearing is nothing to do with malloc() and it can't be - it has to happen before the memory is mapped into your address space). You may get memory that has previously been written by your process/program (e.g. before main()).



In your example program, you're seeing a malloc() region that hasn't yet been written by this process (i.e. it's direct from a new page) and a stack that has been written to (by pre-main() code in your program). If you examine more of the stack, you'll find it's zero-filled further down (in its direction of growth).



If you really want to understand what's happening at the OS level, I recommend that you bypass the C Library layer and interact using system calls such as brk() and mmap() instead.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered 2 days ago









Toby SpeightToby Speight

5,54711134




5,54711134







  • 1





    A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

    – thb
    2 days ago







  • 1





    @thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

    – Toby Speight
    2 days ago







  • 1





    @TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

    – Joshua
    2 days ago







  • 1





    @Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

    – Toby Speight
    2 days ago






  • 2





    If you need initialized memory using calloc might be an option (instead of memset)

    – eckes
    2 days ago












  • 1





    A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

    – thb
    2 days ago







  • 1





    @thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

    – Toby Speight
    2 days ago







  • 1





    @TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

    – Joshua
    2 days ago







  • 1





    @Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

    – Toby Speight
    2 days ago






  • 2





    If you need initialized memory using calloc might be an option (instead of memset)

    – eckes
    2 days ago







1




1





A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

– thb
2 days ago






A week or two ago, I tried a different experiment, calling malloc() and free() repeatedly. Though nothing requires malloc() to reuse the same storage recently freed, in the experiment, malloc() did happen to do that. It happened to return the same address each time, but also nulled the memory each time, which I had not expected. This was interesting to me. Further experiments have led to today's question.

– thb
2 days ago





1




1





@thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

– Toby Speight
2 days ago






@thb, Perhaps I'm not being clear enough - most implementations of malloc() do absolutely nothing with the memory they hand you - it's either previously-used, or freshly-assigned (and therefore zeroed by the OS). In your test, you evidently got the latter. Similarly, the stack memory is given to your process in the cleared state, but you don't examine it far enough to see parts your process hasn't yet touched. Your stack memory is cleared before it's given to your process.

– Toby Speight
2 days ago





1




1





@TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

– Joshua
2 days ago






@TobySpeight: brk and sbrk are obsoleted by mmap. pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html says LEGACY right at the top.

– Joshua
2 days ago





1




1





@Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

– Toby Speight
2 days ago





@Joshua, that page says "The use of malloc() is now preferred", i.e. a higher-level library function, rather than recommending alternative system calls. malloc() implementations aren't really subject to that recommendation, almost by definition.

– Toby Speight
2 days ago




2




2





If you need initialized memory using calloc might be an option (instead of memset)

– eckes
2 days ago





If you need initialized memory using calloc might be an option (instead of memset)

– eckes
2 days ago











5














Your premise is wrong.



What you describe as 'security' is really confidentiality, meaning that no process may read another processes memory, unless this memory is explicitly shared between these processes. In an operating system, this is one aspect of the isolation of concurrent activities, or processes.



What the operating system is doing to ensure this isolation, is whenever memory is requested by the process for heap or stack allocations, this memory is either coming from a region in physical memory that is filled whith zeroes, or that is filled with junk that is coming from the same process.



This ensures that you're only ever seeing zeroes, or your own junk, so confidentiality is ensured, and both heap and stack are 'secure', albeit not necessarily (zero-)initialized.



You're reading too much into your measurements.






share|improve this answer








New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 1





    The question's Update section now explicitly references your illuminating answer.

    – thb
    yesterday















5














Your premise is wrong.



What you describe as 'security' is really confidentiality, meaning that no process may read another processes memory, unless this memory is explicitly shared between these processes. In an operating system, this is one aspect of the isolation of concurrent activities, or processes.



What the operating system is doing to ensure this isolation, is whenever memory is requested by the process for heap or stack allocations, this memory is either coming from a region in physical memory that is filled whith zeroes, or that is filled with junk that is coming from the same process.



This ensures that you're only ever seeing zeroes, or your own junk, so confidentiality is ensured, and both heap and stack are 'secure', albeit not necessarily (zero-)initialized.



You're reading too much into your measurements.






share|improve this answer








New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 1





    The question's Update section now explicitly references your illuminating answer.

    – thb
    yesterday













5












5








5







Your premise is wrong.



What you describe as 'security' is really confidentiality, meaning that no process may read another processes memory, unless this memory is explicitly shared between these processes. In an operating system, this is one aspect of the isolation of concurrent activities, or processes.



What the operating system is doing to ensure this isolation, is whenever memory is requested by the process for heap or stack allocations, this memory is either coming from a region in physical memory that is filled whith zeroes, or that is filled with junk that is coming from the same process.



This ensures that you're only ever seeing zeroes, or your own junk, so confidentiality is ensured, and both heap and stack are 'secure', albeit not necessarily (zero-)initialized.



You're reading too much into your measurements.






share|improve this answer








New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










Your premise is wrong.



What you describe as 'security' is really confidentiality, meaning that no process may read another processes memory, unless this memory is explicitly shared between these processes. In an operating system, this is one aspect of the isolation of concurrent activities, or processes.



What the operating system is doing to ensure this isolation, is whenever memory is requested by the process for heap or stack allocations, this memory is either coming from a region in physical memory that is filled whith zeroes, or that is filled with junk that is coming from the same process.



This ensures that you're only ever seeing zeroes, or your own junk, so confidentiality is ensured, and both heap and stack are 'secure', albeit not necessarily (zero-)initialized.



You're reading too much into your measurements.







share|improve this answer








New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this answer



share|improve this answer






New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









answered yesterday









Andreas GrapentinAndreas Grapentin

1512




1512




New contributor




Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Andreas Grapentin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 1





    The question's Update section now explicitly references your illuminating answer.

    – thb
    yesterday












  • 1





    The question's Update section now explicitly references your illuminating answer.

    – thb
    yesterday







1




1





The question's Update section now explicitly references your illuminating answer.

– thb
yesterday





The question's Update section now explicitly references your illuminating answer.

– thb
yesterday





protected by Kusalananda yesterday



Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



Would you like to answer one of these unanswered questions instead?



Popular posts from this blog

Sum ergo cogito? 1 nng

419 nièngy_Soadمي 19bal1.5o_g

Queiggey Chernihivv 9NnOo i Zw X QqKk LpB