1 / 49

RWset: Attacking Path Explosion in Constraint-Based Test Generation

Cristian Cadar, Peter Boonstoppel, Dawson Engler. RWset: Attacking Path Explosion in Constraint-Based Test Generation. TACAS 2008, Budapest, Hungary ETAPS 2008. Constraint-Based Test Generation.

margo
Télécharger la présentation

RWset: Attacking Path Explosion in Constraint-Based Test Generation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Cristian Cadar, Peter Boonstoppel, Dawson Engler RWset: Attacking Path Explosion in Constraint-Based Test Generation TACAS 2008, Budapest, Hungary ETAPS 2008

  2. Constraint-Based Test Generation • Goal: generate inputs that explore (ideally) all paths of a program • Run program on symbolic input, whose initial value is anything • At conditionals that use symbolic inputs, fork execution and follow both paths: • On true branch, add constraint that condition is true • On false, that it is not • When a path terminates, generate a test case by solving the constraints on that path

  3. Constraint-Based Test Generation • EGT / EXE / KLEE • DART [Godefroid/Klarlund/Sen] • CUTE [Sen et al.] • SAGE, Pex [Godefroid et al.] • Vigilante [Castro et al ] • BitScope [Song et al.] • RWset applicable to any of these

  4. EXE Results • Effective bug-finding tool • File system code • ext2, ext3, JFS • Networking applications • bpf, udhcpd • Library code • PCRE, Pintos • Device drivers • Minix

  5. Scalability challenge • Exponential space! • Relatively small number of interesting paths: e.g., those that achieve maximum branch coverage • Mixed symbolic/concrete execution (EXE/DART) • Search heuristics • Best First Search (EXE) • Generational Search (SAGE) • Symbolic execution + random testing (Hybrid CUTE) • Caching function summaries (SMART) • Demand-Driven Compositional Symbolic Execution (Pex)

  6. RWset (read-write set) analysis • Determine whether continuing to execute the current program path will explore new states • Only a value observed by the program can determine the execution of new program states

  7. {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag);

  8. flag = 0 {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag);

  9. flag = 0 arg1 > 100 true: arg1 > 100 false: arg1  100 . . . . . . {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag);

  10. flag = 0 arg1 > 100 true: arg1 > 100 false: arg1  100 . . . flag = 1 {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag); arg2 > 100 true: arg2 > 100 false: arg2  100

  11. flag = 0 arg1 > 100 true: arg1 > 100 false: arg1  100 . . . flag = 1 {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag); arg2 > 100 true: arg2 > 100 false: arg2  100 flag = 1 process(data, 1)

  12. flag = 0 arg1 > 100 true: arg1 > 100 false: arg1  100 . . . flag = 1 {data, arg1, arg2} = unconstrained flag = 0; if (arg1 > 100) flag = 1; if (arg2 > 100) flag = 1; process(data, flag); arg2 > 100 true: arg2 > 100 false: arg2  100 flag = 1 process(data, 1) process(data, 1)

  13. flag = 0 arg1 > 100 true: arg1 > 100 false: arg1  100 . . . flag = 1 arg2 > 100 true: arg2 > 100 false: arg2  100 flag = 1 process(data, 1) process(data, 1) If arg1, arg2 not read

  14. Write-set analysis • Look at values written in the past • State abstraction in model checking • Memory state = write set up to current progr. pt. • Concrete writes: concr loc = concr val • Symbolic writes: constraint(sym loc) • Program point P, two paths w/ same write-set • prune the second one

  15. Write-sets • Precision: reason at the byte-level • Minimize write-set size 1. Overwrites 2. Dead locations 3. Alpha renaming • Complicated in the symbolic domain • a[i] = 17; • a[j] = 20; • Cannot discard all constraints • on dead locations

  16. Read-set analysis • Key idea: can ignore from write-set writes to locations that are never read again • Definition of read driven by goal to achieve high branch coverage • Location read if can hit a new branch by changing its value

  17. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 =  arg2 =  arg2 > 100 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  18. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 =  arg2 =  arg2 > 100 flag = 0 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  19. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 =  arg2 > 100 flag = 0 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  20. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 =  arg2 > 100 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  21. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 > 100 arg2 > 100 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  22. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 > 100 arg2 > 100 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  23. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 > 100 arg2 > 100 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1)

  24. flag = 0 RWset arg1 > 100 True-True path true: arg1 > 100 false: arg1  100 data =  . . . flag = 1 arg1 > 100 arg2 > 100 arg2 > 100 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1) arg1, arg2 not read

  25. flag = 0 RWset RWset arg1 > 100 True-True path True-False path true: arg1 > 100 false: arg1  100 data =  data =  . . . arg1 > 100 flag = 1 arg1 > 100 arg2  100 arg2 > 100 arg2 > 100 flag = 1 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1) arg1, arg2 not read

  26. flag = 0 RWset RWset arg1 > 100 True-True path True-False path true: arg1 > 100 false: arg1  100 data =  data =  . . . arg1 > 100 flag = 1 arg1 > 100 arg2  100 arg2 > 100 arg2 > 100 flag = 1 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1) arg1, arg2 not read

  27. flag = 0 RWset RWset arg1 > 100 True-True path True-False path true: arg1 > 100 false: arg1  100 data =  data =  . . . arg1 > 100 flag = 1 arg1 > 100 arg2  100 arg2 > 100 arg2 > 100 flag = 1 flag = 1 true: arg2 > 100 false: arg1  100 flag = 1 process(data, 1) process(data, 1) arg1, arg2 not read

  28. Implementation Execution pathGlobal cache W1 RW-Set(P) W2 (W1, R1) (W2, R2) … (Wn, Rn) WP P Wp

  29. Implementation Execution pathGlobal cache W1 RW-Set(P) W2 (W1, R1) (W2, R2) … (Wn, Rn) WP P Wp Write-set Hit! Emit test case i.(WP= Wi)

  30. Implementation Execution pathGlobal cache W1 RW-Set(P) W2 (W1, R1) (W2, R2) … (Wn, Rn) (WP, Ri) WP P Wp Read-set Hit! Emit test case i.(WP Ri = Wi  Ri) Add (WP,Ri) to RW-Set(P)

  31. Implementation Execution pathGlobal cache W1 RW-Set(P) W2 (W1, R1) (W2, R2) … (Wn, Rn) (WP, _) WP P Wp Miss! Add (WP,_) to RW-Set(P) . . .

  32. Evaluation • Medium-sized open source benchmarks • bpf, udhcpd, expat, tcpdump, pcre • Minix 3 device drivers • lance, pci, sb16

  33. Medium-sized apps • bpf: Berkeley Packet Filter • expat: XML parsing library • pcre: Perl compatible reg exp library • tcpdump: tool for printing packet headers • udhcpd: a DHCPD server

  34. Medium-sized apps • Ran base EXE on each app for 30 minutes • Except 30,000 test cases for PCRE • Recorded number of branches hit • Reran in RWset mode until we reached the same branch coverage

  35. Medium-sized apps

  36. Non-redundant states pcre bpf expat Non-redundant states Non-redundant states Non-redundant states Test cases Test cases Test cases tcpdump udhcpd Test cases Test cases

  37. Performance • Dry run for the medium-sized apps: compute write-sets and read-sets but do no pruning

  38. Device drivers • Hard to check w/o the physical device or outside of the kernel • Focused on three MINIX 3 drivers: • lance: AMD lance ethernet card driver • pci: PCI bus driver • sb16: Sound Blaster 16 driver

  39. Minix 3 device drivers • Structured around a main dispatch loop • while (1) { • /* receive message from other processes, • the kernel, or the hardware */ • message = read_message(); • process(message); • }

  40. Minix 3 device drivers • Structured around a main dispatch loop • while (1) { • /* receive message from other processes, • the kernel, or the hardware */ • message = read_symbolic_data(); • process(message); • }

  41. Minix 3 device drivers • Structured around a main dispatch loop • for (k=0; k < n; k++) { • /* receive message from other processes, • the kernel, or the hardware */ • message = read_symbolic_data(); • process(message); • }

  42. Minix drivers - evaluation • Three versions of EXE: • Base • Write-set • RWset • Fixed the # of iterations in each version • mainly to have the base version terminate • Ran each version for an hour • recorded branch coverage + non-redundant states

  43. Branch coverage (pci) RWset Write-set Base

  44. Branch coverage (lance) RWset Write-set Base

  45. Branch coverage (sb16) RWset Write-set Base

  46. RWset DFS RWset DFS RWset Base RWset Base RWset Base Non-redundant states RWset DFS

  47. Bugs in device drivers

  48. Summary • RWset analysis • efficient way to prune large numbers of redundant paths • only values observed by the program trigger the execution of new paths • Evaluated on Minix drivers and medium size applications • big reduction in the number of paths explored

  49. Questions?

More Related