Memory Debugging SS 2007 Johannes Kepler University Linz, Austria - - PowerPoint PPT Presentation

memory debugging
SMART_READER_LITE
LIVE PREVIEW

Memory Debugging SS 2007 Johannes Kepler University Linz, Austria - - PowerPoint PPT Presentation

Advanced Topics on Applied Systemtheory: Debugging Memory Debugging 1 Memory Debugging SS 2007 Johannes Kepler University Linz, Austria Dr. Toni Jussila Institut for Formal Models and Verification http://fmv.jku.at/kv Applied Systemtheory


slide-1
SLIDE 1

Advanced Topics on Applied Systemtheory: Debugging Memory Debugging 1

Memory Debugging

SS 2007 Johannes Kepler University Linz, Austria

  • Dr. Toni Jussila

Institut for Formal Models and Verification http://fmv.jku.at/kv

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-2
SLIDE 2

Memory Debugging

Memory Debugging 2

  • some programming languages (most notably C and C++), leave the management of

the heap∗ to the programmer – you allocate new memory with malloc() / new() – you free allocated memory with free() / delete()

  • unintentional misuse of this heap memory is a common source of errors
  • there types of faults are time bombs

– they may manifest themselves only millions of instructions later

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

∗heap is the place where new objects are allocated

slide-3
SLIDE 3

Types of Heap Faults

Memory Debugging 3

  • 1. uninitialized memory read resp. copy (umr, umc)
  • 2. using memory that you do not own

(a) null pointer read or write (npr, npw) (b) zero page read of write (zpr, zpw) (c) invalid pointer read or write (ipr, ipw) (d) free memory read or write (fmr, fmw) (e) beyong stack read or write (bsr, bsw)

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-4
SLIDE 4

Types of Heap Faults II

Memory Debugging 4

  • 3. using more memory that you have allocated (buffer overruns)

(a) array bounds read (abr) (b) array bounds write (abw)

  • 4. using faulty heap memory management

(a) memory leaks and potential memory leaks (mlk, plk, mpk) (b) freeing invalid memory (fim)

  • i. freeing mismatched memory (fmm)
  • ii. freeing non-heap memory (fnh)
  • iii. freeing unallocated memory (fum)

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-5
SLIDE 5

Tools to Detect Memory Faults

Memory Debugging 5

  • validating the heap with MALLOC CHECK

– provided with the GNU C runtime library

  • avoiding buffer overflows with Electricfence

– provided as a library, compile with -lefence

  • detecting memory errors with Purify (a commercial tool)
  • detecting memory errors (and profiling) with Valgring

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-6
SLIDE 6

Purify

Memory Debugging 6

  • initially written by Reed Hastings and Bob Joyce (1991)
  • Pure Software ⇒ Pure Atria ⇒ Rational Software ⇒ IBM
  • OCI = Object Code Instrumentation

– compile your programs with debug information (switch -g) – call Purify with the binary as an argument to instrument it with additional code around calls to malloc() and free() – if you run the instrumented program, Purify detects errors inside of your program

  • r operating system libraries at runtime

– program may work, yet Purify may report an error

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-7
SLIDE 7

Heap Fault Examples I

Memory Debugging 7

  • NPR – read from address zero
  • ZPR – try to read an address from memory page zero

typedef struct node { struct node* next; int val; } Node; int findLastNodeValue(Node* head) { while (head->next != NULL) { /* Expect NPR */ head = head->next; } return head->val; /* Expect ZPR */ } void genNPRandZPR() { int i = findLastNodeValue(NULL); }

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-8
SLIDE 8

Heap Fault Examples II

Memory Debugging 8

  • FMR – read from a memory that is released (dangling pointer)
  • FMR – write from a memory that is released

int* init_array(int *ptr, int new_size) { ptr = (int*) realloc(ptr, new_size*sizeof(int)); memset(ptr, 0, new_size*sizeof(int)); return ptr; } int* fill_fibonacci(int *fib, int size) { int i; /* oops, forgot: fib = */ init_array(fib, size); fib[1] = 1; for (i=2; i<size; i++) fib[i] = fib[i-1] + fib[i-2]; return fib; } void genFMRandFMW() { int *array = (int*)malloc(10); fill_fibonacci(array, 3); }

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-9
SLIDE 9

Heap Fault Examples III

Memory Debugging 9

  • BSR – beyond stack read (dangling stack pointer)
  • BSW – beyong stack write

char *append(const char* s1, const char *s2) { const int MAXSIZE = 128; char result[128]; int i=0, j=0; for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) { result[i] = s1[j]; } for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) { result[i] = s2[j]; } result[++i] = ’\0’; return result; } void genBSRandBSW() { char *name = append("Applied ", append("System", "theory")); printf("%s\n", name); /* Expect BSR */ *name = ’\0’; /* Expect BSW */ }

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-10
SLIDE 10

Heap Fault Examples IV – memory leaks

Memory Debugging 10

  • PLK – potential memory leak

int *plk = NULL; void genPLK() { plk = (int *) malloc(2 * sizeof(int)); /* Expect PLK */ plk++; }

  • FNH – freeing non-heap memory
  • FUM – freeing unallocated memory

void genFNH() { int fnh = 0; free(&fnh); /* Expect FNH: freeing stack memory */ } void genFUM() { int *fum = (int *) malloc(4 * sizeof(int)); free(fum+1); /* Expect FUM: fum+1 points to middle of a block */ free(fum); free(fum); /* Expect FUM: freeing already freed memory */ }

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-11
SLIDE 11

Valgrind

Memory Debugging 11

  • named after the holy entrance of Valhalla from Nordic mythology
  • originally written by Julian Seward (aka the author of bzip2)
  • DBI framework for building heavyweight DBA tools
  • tool to execute dynamic x86-to-x86 transformations

– thus can be combined with different code instrumentation plug-ins – shadow values: for each register and memory value you can introduce additional data

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-12
SLIDE 12

Valgrind II

Memory Debugging 12

  • Valgrind runs on the machine’s real CPU
  • the client (the program to be analyzed) is run on a simulated CPU
  • Tools: heap bugs can be analyzed with a plug-in called memcheck
  • cachegrind annotate every line of your program with the number of executed in-

structions and incurred cache misses

  • callgrind get call counts and cost of each call
  • helgrind spots potential race conditions in your program

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-13
SLIDE 13

Valgrind III

Memory Debugging 13

  • uses dynamic binary recompilation (D & R)

– machine code is transformed to Valgrind intermediate representation – architecture-neutral, single-static-assignment (SSA) – granularity: superblock (single-entry, multiple-exit) – RISC-like, yet over 200 primitive arithmetic/logical operations

  • FP

, MMX, SSE and SSE2 instructions (on Intel architecture) – not disassembled to the same level of detail as integer instructions

  • cannot trace into kernel, system calls handled by wrappers 15KLOC of tedious C code

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-14
SLIDE 14

(Valgrind) + memcheck

Memory Debugging 14

  • memory definedness checker at the bit level
  • for each register or memory bit, a shadow V-bit is introduced
  • every operation that creates a value is shadowed by an operation that computes the

V-bits of the output based on those of the input

  • every operation using a value in a way that could affect observable behavior is checked
  • example: d3 = Add(d1, d2) is shadowed by v3 = Left(UifU(v1, v2))
  • large overhead, programs typically run 20 – 30 times slower

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-15
SLIDE 15

Memcheck, avoiding false positives

Memory Debugging 15

  • Memcheck defers error reporting as far as it can.
  • Checks for undefinedness are made for:
  • 1. memory addresses in load and store instructions
  • 2. conditional jump, check %eflags for definedness
  • 3. arguments to system calls
  • 4. memory loads (address and data) into a SIMD or FP register

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-16
SLIDE 16

Memcheck – limitations

Memory Debugging 16

  • cannot be free of both false positives and negatives

– equivalent of solving the Halting Problem

  • design goal: almost completely avoid false negatives and minimize false positives
  • a worthy aim: Memcheck-cleanness.

To get there, dummy initializations may be needed.

  • Memcheck cannot test for code that is not executed

– thus, in addition to ad-hoc debugging, it should be used together with automatic regression test suites

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz

slide-17
SLIDE 17

Current Trends

Memory Debugging 17

  • Valgrind and Purify only make sense in environments where heap memory manage-

ment is left to the programmer

  • current trend in software development is to trade performance for runtime safety

wherever possible (Zeller)

  • in Java and .NET the integrity of code and data is constantly verified
  • given explosion in computational power, the cost of checking becomes more and more

irrelevant

  • eventually, proving correctness may turn to be a strategy for optimization

Applied Systemtheory – SS 2007 – Toni Jussila – JKU Linz