28
Pointers and Memory Allocation – part 2 -L. Grewe

Pointers and Memory Allocation – part 2 -L. Grewe

  • View
    226

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers and Memory Allocation – part 2-L. Grewe

Page 2: Pointers and Memory Allocation – part 2 -L. Grewe

2

Objectives

•Pointers to Functions

•More potential Issues with Pointers - advanced

Page 3: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers to Functions(this is NOT passing pointers as arguments to functions!!!

This is a pointer pointing to a function itself!!!!!!)

A pointer can also store the address of a function

A function name is the address in memory of the start of the function

Function pointers can be

– Passed to a function

– Returned to functions

– Stored in arrays

– Assigned to other function pointers

Page 4: Pointers and Memory Allocation – part 2 -L. Grewe

An Array of Pointers to Functions#include <stdio.h>

void fun1(void);

void fun2(void);

void fun3(void);

 

int main(){

/*declare an array of pointers to functions*/

void (*array[3])(void) = {fun1,fun2,fun3};

int i;

for (i=0;i<3;i++)

(*array[i])();/*make a function call*/

return 0; /*output: 1st 2nd 3rd */

}

void fun1(void){printf("1st ");}

void fun2(void){printf("2nd ");}

void fun3(void){printf("3rd ");}

Page 5: Pointers and Memory Allocation – part 2 -L. Grewe

Alternative Code#include <stdio.h>

void fun1(void);

void fun2(void);

void fun3(void);

 

int main(){

void (*array[3])(void) = {fun1,fun2,fun3};

/*declare an array of pointers to functions*/

int i;

for (i=0;i<3;i++)

array[i](); /*or (*array[i])(); */

return 0; /*output: 1st 2nd 3rd */

}

void fun1(void){printf("1st ");}

void fun2(void){printf("2nd ");}

void fun3(void){printf("3rd ");}

Page 6: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers to Functions

void (*array[3])(void)={fun1,fun2,fun3};

“array” is an array of 3 pointers to 3 functions with no arguments and return type void

(*array[i])(void); //THESE ARE THE SAME

array[i]();

Page 7: Pointers and Memory Allocation – part 2 -L. Grewe

An Array of Pointers to Functions 2#include <stdio.h>

int fun1(int);

int fun2(int);

int fun3(int);

 

int main(){

int (*array[3])(int) = {fun1,fun2,fun3};

int i;

for (i=0;i<3;i++)

printf("%d ",(*array[i])(i)); /*1 3 5*/

/* printf("%d ", array[i](i)); */

return 0;

}

  int fun1(int x){return x+1;}

int fun2(int x){return x+2;}

int fun3(int x){return x+3;}

Just some new functionsfun1, fun2, fun3With parameters

Page 8: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers to Functions 2

int (*array[3])(int)={fun1,fun2,fun3};

“array” is an array of 3 pointers to 3 functions with one int argument and return type int

(*array[i])(i);

array[i](i);

The function is dereferenced and integer “i” is passed as an argument to the function

Page 9: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers to functions: WHY?

9

They allow for a certain amount of polymorphism:

– “poly” (many) + “morph” (shape)

– A polymorphic language can handle a range of different data types (“shapes”?) with a single statement

Page 10: Pointers and Memory Allocation – part 2 -L. Grewe

Pointers to functions: safety concerns

10

What if uninitialized function pointer value is accessed?

– Safest outcome: memory error, and program is terminated

– But what if the “garbage” value is a valid address?

• Worst case: address contains program instruction –execution continues, with random results

• Hard to trace the cause of the erroneous behavior

Page 11: Pointers and Memory Allocation – part 2 -L. Grewe

Pointer and Memory Failures re-visited and Advanced

11

Page 12: Pointers and Memory Allocation – part 2 -L. Grewe

Memory-related bugs

Dereferencing bad pointers

Reading uninitialized memory

Overwriting memory

Referencing nonexistent variables

Freeing blocks multiple times

Referencing freed blocks

Failing to free blocks

Page 13: Pointers and Memory Allocation – part 2 -L. Grewe

Reading uninitialized memoryAssuming that heap data is initialized to zero

/* return y = Ax */int *matvec(int **A, int *x) { int *y = malloc(N*sizeof(int)); int i, j;

for (i=0; i<N; i++) for (j=0; j<N; j++) y[i] += A[i][j]*x[j]; return y;}

Page 14: Pointers and Memory Allocation – part 2 -L. Grewe

Overwriting memory

Allocating the (possibly) wrong sized object

int **p;

p = malloc(N*sizeof(int));

for (i=0; i<N; i++) { p[i] = malloc(M*sizeof(int));}

Page 15: Pointers and Memory Allocation – part 2 -L. Grewe

Overwriting memory

Off-by-one

int **p;

p = malloc(N*sizeof(int *));

for (i=0; i<=N; i++) { p[i] = malloc(M*sizeof(int));}

Page 16: Pointers and Memory Allocation – part 2 -L. Grewe

Overwriting memoryNot checking the max string size

char s[8];int i;

gets(s); /* reads “123456789” from stdin */

Basis for classic buffer overflow attacks• 1988 Internet worm• modern attacks on Web servers• AOL/Microsoft IM war

Page 17: Pointers and Memory Allocation – part 2 -L. Grewe

Buffer overflow attacksDescription of hole:

– Servers that use C library routines such as gets() that don’t check input sizes when they write into buffers on the stack.

– The following description is based on the IA32 stack conventions. The details will depend on how the stack is organized, which varies between compilers and machines

64 bytesfor buffer

return addr

Saved regs. and Local vars

proc a() { b(); # call procedure b}

proc b() { char buffer[64]; # alloc 64 bytes on stack gets(buffer); # read STDIN line into buf}

Stack frame

for proc a

%ebpStack frame

for proc b

%ebp

increasingaddrs

Page 18: Pointers and Memory Allocation – part 2 -L. Grewe

Buffer overflow attacksVulnerability stems from possibility of the gets() routine overwriting the return address

for b.

– overwrite stack frame with

• machine code instruction(s) that execs a shell

• a bogus return address to the instruction

proc a() { b(); # call procedure b} # b should return here, instead it # returns to an address inside of buffer

proc b() { char buffer[64]; # alloc 64 bytes on stack gets(buffer); # read STDIN line to buffer}

Stack region overwritten by gets(buffer)

exec(“/bin/sh”)

New return addr

Saved regs. and Local vars

Stack frame

for proc a

paddingStack frame

for proc b

%ebp

incraddrs

Page 19: Pointers and Memory Allocation – part 2 -L. Grewe

Overwriting memoryReferencing a pointer instead of the object it points to

int *BinheapDelete(int **binheap, int *size) { int *packet; packet = binheap[0]; binheap[0] = binheap[*size - 1]; *size--; Heapify(binheap, *size, 0); return(packet);}

Page 20: Pointers and Memory Allocation – part 2 -L. Grewe

Overwriting memory

Misunderstanding pointer arithmetic

int *search(int *p, int val) { while (*p && *p != val) p += sizeof(int);//you should increment //array by 1 only //you are missing elements

return p;}

Page 21: Pointers and Memory Allocation – part 2 -L. Grewe

Referencing nonexistent variables

Forgetting that local variables disappear when a function returns

int *foo () { int val; return &val;}

Page 22: Pointers and Memory Allocation – part 2 -L. Grewe

Freeing blocks multiple times

x = malloc(N*sizeof(int));// ….<manipulate x>free(x);

y = malloc(M*sizeof(int));//…<manipulate y>free(x);

Page 23: Pointers and Memory Allocation – part 2 -L. Grewe

Referencing freed blocks

x = malloc(N*sizeof(int));//….<manipulate x>free(x);...

y = malloc(M*sizeof(int));for (i=0; i<M; i++) y[i] = x[i]++;

Page 24: Pointers and Memory Allocation – part 2 -L. Grewe

Failing to free blocks(memory leaks)

Run out of memory as you repeatedly call function …foo(), foo(), foo() ….

foo() { int *x = malloc(N*sizeof(int)); ... return;}

Page 25: Pointers and Memory Allocation – part 2 -L. Grewe

Failing to free blocks(memory leaks)

Freeing only part of a data structure

struct list { int val; struct list *next;};

foo() { struct list *head = malloc(sizeof(struct list)); head->val = 0; head->next = NULL; <create and manipulate the rest of the list> ... free(head); //not freeing other part of list created. return;}

Page 26: Pointers and Memory Allocation – part 2 -L. Grewe

Dealing with memory bugs

Conventional debugger (gdb)

– good for finding bad pointer dereferences

– hard to detect the other memory bugs

Debugging malloc

– wrapper around conventional malloc

– detects memory bugs at malloc and free boundaries

• memory overwrites that corrupt heap structures

• some instances of freeing blocks multiple times

• memory leaks

– Cannot detect all memory bugs

• overwrites into the middle of allocated blocks

• freeing block twice that has been reallocated in the interim

• referencing freed blocks

Page 27: Pointers and Memory Allocation – part 2 -L. Grewe

Dealing with memory bugs (cont.)

Binary translator (i.e. Purify-IBM product)

– powerful debugging and analysis technique

– rewrites text section of executable object file

– can detect all errors as debugging malloc

– can also check each individual reference at runtime

• bad pointers

• overwriting

• referencing outside of allocated block

Garbage collection– let the system free blocks instead of the programmer.

Page 28: Pointers and Memory Allocation – part 2 -L. Grewe

Pointer and Memory Allocation Tips

• Use Pointers only when you need to.

• Pointer problems can be the most difficult to debug

• Whenever you allocate memory – think immediately where/if you need to deallocate it

• Use Data Structures implemented in C++ Collections already provided when possible –as they are written to take care of potential problems like class copying we saw previously.

28