Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Tool Belt of a Seasond Bug Hunter

Damir
August 24, 2018

A Tool Belt of a Seasond Bug Hunter

Let me take you on a journey. This true story begins with a performance issue in a Ruby on Rails application, and ends deep inside internals of MRI, surrounded by barren landscape of C’s curly braces. Using tools I knew before, learning new utilities, failing to get a conclusive answer, and learning from all that, marked my passage from a software developer to a seasoned bug hunter. This talk will spare you the frustration of such a trip, and give you the raw insight.

Damir

August 24, 2018
Tweet

More Decks by Damir

Other Decks in Programming

Transcript

  1. Chapter 1: Reproduce A Tool Belt of a Seasoned Bug

    Hunter
 Damir Zekić • @sidonath
  2. Chapter 2: What introduced it? A Tool Belt of a

    Seasoned Bug Hunter
 Damir Zekić • @sidonath
  3. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  4. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  5. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  6. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  7. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  8. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  9. 13 37 c0 ff ee c0 de a0 bug is

    present here "bad" no bug 7 commits ago "good"
  10. "

  11. "

  12. "

  13. Chapter 3: Is it a memory leak? A Tool Belt

    of a Seasoned Bug Hunter
 Damir Zekić • @sidonath
  14. require 'objspace' ObjectSpace.trace_object_allocations_start class Foo def bar puts "Hello, world!"

    end end
 foo = Foo.new foo.bar File.open("/tmp/heap.dump", 'w') do |file| ObjectSpace.dump_all(output: file) end
  15. Analyzing Heap (Generation: 17) ------------------------------- allocated by memory (44061517) (in

    bytes) ============================== 39908512 …/ruby-2.2.3/lib/ruby/2.2.0/timeout.rb:79 1284993 …/ruby-2.2.3/lib/ruby/2.2.0/openssl/buffering.rb:182 201068 …/bundle/ruby/2.2.0/gems/json-1.8.3/lib/json/common.rb:223 189272 …/bundle/ruby/2.2.0/gems/newrelic_rpm-3.13.2.302/lib/… 172531 …/ruby-2.2.3/lib/ruby/2.2.0/net/http/header.rb:172 92200 …/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/…
  16. #

  17. Chapter 4: Let's trace a call stack A Tool Belt

    of a Seasoned Bug Hunter
 Damir Zekić • @sidonath
  18. def main say_hello say_bye end def say_hello name = read_name

    msg = greeting(name) puts msg end def say_bye puts "Bye" end
  19. say_hello read_name main def main say_hello say_bye end def say_hello

    name = read_name msg = greeting(name) puts msg end def say_bye puts "Bye" end
  20. say_hello read_name greeting main def main say_hello say_bye end def

    say_hello name = read_name msg = greeting(name) puts msg end def say_bye puts "Bye" end
  21. say_hello read_name greeting main say_bye def main say_hello say_bye end

    def say_hello name = read_name msg = greeting(name) puts msg end def say_bye puts "Bye" end
  22. say_hello read_name greeting main say_bye def main say_hello say_bye end

    def say_hello name = read_name msg = greeting(name) puts msg end def say_bye puts "Bye" end
  23. def clear! @path_helpers.each do |helper| @path_helpers_module.send :undef_method, helper end @url_helpers.each

    do |helper| @url_helpers_module.send :undef_method, helper end @routes.clear @path_helpers.clear @url_helpers.clear end
  24. def clear! @path_helpers.each do |helper| @path_helpers_module.send :undef_method, helper end @url_helpers.each

    do |helper| @url_helpers_module.send :undef_method, helper end @routes.clear @path_helpers.clear @url_helpers.clear end
  25. def clear! @path_helpers.each do |helper| @path_helpers_module.send :undef_method, helper end @url_helpers.each

    do |helper| @url_helpers_module.send :undef_method, helper end @routes.clear @path_helpers.clear @url_helpers.clear end
  26. Time (s) 0 1.75 3.5 5.25 7 Number of classes

    that include the module 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 Expected Constant Expected Linear Actual
  27. void rb_undef(VALUE klass, ID id) { const rb_method_entry_t *me; if

    (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class to undef method"); } rb_frozen_class_p(klass); if (id == object_id || id == id__send__ || id == idInitialize) { rb_warn("undefining `%s' may cause serious problems", rb_id2name(id)); } me = search_method(klass, id, 0); if (me && me->def->type == VM_METHOD_TYPE_REFINED) { me = rb_resolve_refined_method(Qnil, me); } if (UNDEFINED_METHOD_ENTRY_P(me) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_method_name_error(klass, rb_id2str(id)); } rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_PUBLIC); CALL_METHOD_HOOK(klass, undefined, id); }
  28. const rb_method_entry_t *me; me = search_method(klass, id, 0); if (me

    && me->def->type == VM_METHOD_TYPE_REFINED) { me = rb_resolve_refined_method(Qnil, me); } if (UNDEFINED_METHOD_ENTRY_P(me) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_method_name_error(klass, rb_id2str(id)); } rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_PUBLIC); CALL_METHOD_HOOK(klass, undefined, id);
  29. const rb_method_entry_t *me; me = search_method(klass, id, 0); if (me

    && me->def->type == VM_METHOD_TYPE_REFINED) { me = rb_resolve_refined_method(Qnil, me); } if (UNDEFINED_METHOD_ENTRY_P(me) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_method_name_error(klass, rb_id2str(id)); } rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_PUBLIC); CALL_METHOD_HOOK(klass, undefined, id);
  30. Chapter 5: Complete the puzzle A Tool Belt of a

    Seasoned Bug Hunter
 Damir Zekić • @sidonath
  31. Chapter 6: Fixing it! A Tool Belt of a Seasoned

    Bug Hunter
 Damir Zekić • @sidonath
  32. Chapter 7: The Lesson A Tool Belt of a Seasoned

    Bug Hunter
 Damir Zekić • @sidonath