バグの直し方

: subtitle

実例を添えて

: author

Kenji Okimoto

: institution

株式会社クリアコード

: date

2012-09-16

: theme

.

: allotted-time

30m

自己紹介

自己紹介

お品書き

バグの直し方

再現方法を記録する

問題箇所を絞り込む

対象のプログラムを

問題箇所を絞り込む

# image
# src = flow.svg
# relative_height = 100

property

: enable-title-on-image

false

ポイント!!

# blockquote
プログラムの変更を少しずつ行うことによって、一歩ずつ着実に問題の解決に
向かっていく

ポイント!!

# blockquote
プログラムの変更を行うたびに、「今回の変更では何を調べたいのか」を意識
して作業する

問題箇所を特定できたら

修正できたことを確認

実例紹介

デモ

事前情報

再現コード

# coderay ruby
ARGV[0].to_i.times do |n|
  fork{ exit! }
  #spawn{ exit! }
  GC.start if n % 100 == 0
end

((‘note:fork()でもspawn()でもメモリリークする’))

便利スクリプト

# coderay bash
#!/bin/bash
/tmp/a/bin/ruby ./fork-exit.rb 300000 &
pid=$!
echo fork-exit:$pid
trap "kill $pid; exit" INT TERM
count=0
ps -o pid,ppid,vsz,rss,args | head -1
prev=""
while true; do
  current=`ps -p ${pid} -o pid,ppid,vsz,rss,args | grep fork-exit.rb`
  if test "$current" != "$prev"; then
      echo "$current"
  fi
  prev=$current
  sleep 1
done

((‘note:便利スクリプトがあると便利!!’))

Step 1

spawn のコールグラフ

spawn
 -> rb_f_spawn
  -> rb_spawn_process
   -> rb_fork_err

Step 1

fork のコールグラフ

fork
 -> rb_f_fork
  -> rb_fork
   -> rb_fork_err

Step 2

spawn でも fork でも ((rb_fork_err))nを呼んでいる

Step 3 - 処理を確認する

rb_fork_err の中身を確認

before_fork()
fork()
if (!pid) { ... }
after_fork()

((‘note:if(!pid){…}は子プロセスの処理なので無視する’))

Step 3 - 処理を変更する

Step 4

((*after_fork()*)) に問題があることがわかった!!

Step 5 - after_fork()

Step 5 - after_fork()

Step 6

Step 7

pthread_createn の第2引数をn ((NULL))にすると…

Step 7

メモリリークnしなくなる!!

Step 8

((pthread_attr_init))n してるけどn ((pthread_attr_destroy))n してないことに気付く

Step 9

((pthread_attr_destroy))n を追加してn試すと…

Step 10

((*メモリリーク*))n ((*しなくなる*))

パッチ

# coderay diff
diff --git a/thread_pthread.c b/thread_pthread.c
index 4746aaa..ab7bdf9 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -835,6 +835,7 @@ rb_thread_create_timer_thread(void)
     }
     native_cond_wait(&timer_thread_cond, &timer_thread_lock);
     native_mutex_unlock(&timer_thread_lock);
+    pthread_attr_destroy(&attr);
     }
     rb_disable_interrupt(); /* only timer thread recieve signal */
 }

Step 11

# blockquote
パッチを作ったら\nmake test-all\nを流してE,Fが増えていないことを確認する

まとめ

ポイント!!

問題箇所はn((*一歩ずつ着実に*))n絞り込む

ポイント!!

# blockquote
問題箇所を特定できたらバグの修正は((*八割以上*))できたも同然です

次の一歩