150 likes | 174 Views
Interlude: Memory API. Myeongcheol Kim (mckim@dcslab.snu.ac.kr) School of Computer Science and Engineering Seoul National University. Contents. Types of Memory The malloc() Call The free() Call Common Errors Underlying OS Support. Introduction. Question
E N D
Interlude: Memory API Myeongcheol Kim (mckim@dcslab.snu.ac.kr) School of Computer Science and Engineering Seoul National University
Contents Typesof Memory The malloc() Call The free() Call Common Errors Underlying OS Support
Introduction Question Q1: What interfaces are commonly used? Q2: What mistakes should be avoided? • How to allocate and manage memory • In UNIX/C programs, it is critical in building robust and reliable software.
Two Types of Memory High address cmd linearguments & env variables Stack x y x void func () { int x; … { int y; } } void func () { int *x = (int *)malloc(sizeof(int)); } Heap 4 bytes by malloc() Uninitialized data (bss) Initialized data Text Low address • Stack memory • Resides in the stack area of a process. • Is managed implicitly by the compiler. • Allocation: declaration of a variable inside code block • Deallocation: exiting from code block • Heap memory • Resides in the heap area of a process. • Should be explicitly handled by programmer. • Allocation: malloc() call • Deallocation: free() call
Stack Memory Allocation Example void func() { 4004ed: push %rbp 4004ee: mov %rsp,%rbp int x = sizeof(double); 4004f1: movl $0x8,-0x4(%rbp) } 4004f8: pop %rbp 4004f9: retq intmain(intargc, char *argv[]) { 4004fa: push %rbp 4004fb: mov%rsp,%rbp 4004fe: sub $0x10,%rsp 400502: mov%edi,-0x4(%rbp) 400505: mov %rsi,-0x10(%rbp) func(); 400509: mov $0x0,%eax 40050e: callq 4004ed <func> return 0; 400513: mov $0x0,%eax } Stack Frame Allocation Frame #0 Deallocation Return address %rbp %rbp of frame #0 Frame #1 (main()) %rsp Callee-saved registers Frame #1 (main()) Frame #1 (main()) Frame #1 (main()) Return address %rbp of frame #1 Frame #2 (func()) Memory for x Allocation and deallocation of stack memory is done by compiler automatically.
The malloc() Call #include <stdlib.h> void *malloc(size_t size); Returns: non-NULL pointer if OK, NULL on error char *s = (char *)malloc(strlen(str) + 1); • A simple way to allocate heap memory • Passing size parameter describing how many bytes you need. • Getting the pointer to the newly-allocated space. • Idiom to follow • Size parameter • Use sizeof (compile time operator) to let the compiler decide the size of a type. • Use strlen(str) + 1 for memory of a string. • Return value • Cast explicitly to let the compiler know what the program is doing.
The free() Call #include <stdlib.h> void free(void *ptr); • To free heap memory that is no longer in use, programmers simply call free(). • The size of the allocated region is tracked by the memory-allocation library.
Common Errors • A number of run-time errors arise in the use of malloc() and free(). • Compiling C program is necessary for correctness, but far from sufficient. • Newer languages have support for automatic memory management. • Garbage collection • Common errors • Forgetting to allocate memory • Not allocating enough memory • Forgetting to initialize allocated memory • Forgetting to free memory • Freeing memory before you are done with it • Freeing memory repeatedly • Calling free() incorrectly
Common Errors (1/5) char *src = “hello”; char *dst; strcpy(dst, src); char *src = “hello”; char *dst = (char *)malloc(strlen(src) + 1); strcpy(dst, src); Oops! Process crashes. strdup() makes these simple • Forgetting to allocate memory • Memory should be allocated before use. • Improper use of memory which is not allocated leads to a segmentation fault.
Common Errors (2/5) char *src = “hello”; char *dst = (char *)malloc(strlen(src)); strcpy(dst, src); char *src = “hello”; char *dst = (char *)malloc(strlen(src) + 1); strcpy(dst, src); Memory allocated for dst X 3 … ‘h’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’ • Not allocating enough memory • It leads to possible buffer overflow. • In some cases, it is harmless • When malloc library allocates a little extra space. • When overwriting a variable that isn’t used anymore. • Even though ran correctly once, doesn’t mean it’s correct.
Common Errors (3/5) • Forgetting to initialize allocated memory • You will encounter an uninitialized read, where unknown value is read. • calloc() fills the newly-allocated memory with zeroes. • Forgetting to free memory • It is known as memory leak. • For short-lived program, it not harmful. • OS takes back all pages of the process when it dies. • For long-lived program, it is huge problem. • Slowly leaking memory eventually leads one to run out of memory.
Common Errors (4/5) int *p1 = (int *)malloc(sizeof(int)); free(p1); int *p2 = (int *)malloc(sizeof(int)); *p1 = 100; int *p1 = (int *)malloc(sizeof(int)); int *p2 = (int *)malloc(sizeof(int)); *p1 = 100; free(p1); dangling pointer Free memory p2 p1 100 • Freeing memory before you are done with it • Dangling pointer can crash the program or overwrite memory because subsequent malloc() recycles the errantly-freed memory.
Common Errors (5/5) • Freeing memory repeatedly • The result of double free is undefined • Setting the freed pointer to NULL is a good practice. • free(NULL) has no effect. • Calling free() incorrectly • free() expects one of the pointers received from malloc(). • Invalid-frees are dangerous and should be avoided.
Underlying OS Support cmd linearguments & env variables Stack #include <unistd.h> intbrk(void *new_break); Returns: 0 ifOK, -1 on error break Heap Uninitialized data (bss) Initialized data Text • Library call malloc() is built on top of brk() system call. • brk() changes programs break: the location of the end of the heap. • new break > current break • Increasing the heap size • new break < current break • Decreasing the heap size
Summary • Stack memory is managed by compiler implicitly. • Long-lived memory needs to be allocated on heap explicitly and requires careful management. • There are lots of ways to abuse memory. • Avoid bad habits.