Welcome to the 5th unit in our debugging course titled Reproducing Failures.
In the past units we have seen a number of techniques to systematically hand down
a failure cause by following back dependencies and applying the scientific method
to choose between various possible origins until we find the defect.
So far, however, we have assumed that the program fails in the lab
and that somehow we would be able to actually access these earlier states
or at least run appropriate experiments
where we would be able to gather additional.
Contrast this with a program failing in the field where all we know is that the program failed
plus possibly a few hints from the execution,
but all-in-all only a spottier record compared to what you get in the lab.
This is where reproduction comes into play.
You have to reproduce the failing run from the field in the lab
such that you can actually do the debugging. Why do you need to do that?
We need to be able to observe the run,
because once we have reproduced a failure locally,
we can observe and experiment at will.
This, of course, is invaluable for isolating the defect.
Second, we need to be able to check the fix.
Only if we can reproduce a bug can we be sure that we have actually fixed it,
namely, if the failure no longer occurs.
Reproducing a bug can be way harder than fixing the bug.
In programmer's jargon, bug's fall into four categories.
First, there is the Bohr bug from Bohr's model of the atom.
This is a repeatable bug that many manifests reliably
under a possibly unknown but well-defined set of conditions.
Next category is a Heisenbug from Heisenburg's uncertainty principle in quantum physics.
This is a bug that disappears or alters its behavior when one attempts to probe
or isolate it.
The next one is the Mandelbug, coming from the Mandelbrot set.
This is a bug whose underlying causes are so complex and obscure
as to make its behavior appear chaotic or even nondeterministic.
And last but not least there is the Schrödinbug,
which is MIT jargon coming from Schrödinger's cat thought experiment in quantum physics.
You know--the situation in which you have a cat in a box,
which may be dead or which may be alive, but you don't know until you open the box.
This is a bug in a program that doesn't manifest until someone who reads the source
or who uses the program in an unusual way notices that the program never should have worked,
at which point the program promptly stops working for everybody until it is fixed.
All these bug categories refer to various levels of difficulty as it comes to reproducing the bugs.
Here is an example of a bug that was hard to reproduce that I once encountered.
I had a C program that crashed all the time.
In an extremely simplified version this is what it looks like.
If I ran this program normally, it would crash.
The assertion would fail.
If I ran it in a debugger, however, it worked just fine.
デバッグコース第5レッスン
不具合の再現へようこそ
以前のレッスンでは
可能性のあるさまざまな発生源から
不具合を見つけ出すために科学的手法を応用し
依存関係をさかのぼることで
不具合の原因を系統的に突き止める技術を確認しました
ただしこの研究室でプログラムが失敗すること
何らかの形で以前の状態にアクセスできること
さらに情報が得られる場合に
少なくとも適切な実験を実行できると
今のところ仮定しています
実際の現場で失敗するプログラムと
これを比較すると分かることは
プログラムが失敗したこと
さらにヒントが少ししかないことです
しかし全体的に研究室で得られるものと比べて
記録にムラが多いのです
ここで必要になるのが再現です
実際にデバッグができるように
失敗する実行を研究室で
再現する必要があります
それはなぜでしょうか?
実行を観察できるようにする必要があるからです
一度不具合を再現できれば
思いのままに実験を行い観察することができます
これはもちろん不具合の検出に非常に有効です
次に修正をチェックできるようにする
必要があるからです
バグを再現できなければ
それを修正できたと確認できません
つまり不具合がもう起きないかどうかです
バグの再現はその修正よりもはるかに難しいでしょう
バグを4つのカテゴリに分類する業界用語があります
1つ目はボーアの原子模型から名づけられた
ボーアバグです
これは よく解明されていないが明確な条件下で
確実によく現れる反復するバグです
次は料理物理学のハイゼンベルグの
不確定性原理から名づけられたハイゼンバグです
これは調べたり検出しようとすると
動作を変えたり消えたりするバグです
次はマンデルブロ集合から名づけられた
マンデルバグです
これは動作をカオス的に見せたり非決定性にするほど
バグの根底原因がとても複雑で不明瞭なバグです
最後は重要なシュレーディングバグです
これは"シュレーディンガーの猫"から
名づけられたMITの専門用語です
ご存知ですよね?
猫が箱に入っている状況を想像してください
猫が生きているか死んでいるかは
箱を開けるまで分かりません
これがソースを読み込んだ時または
プログラムをいつもと違う方法で使用した時に
プログラムがまったく動かないことに
気づくまで現れないバグです
この時点で修正されるまで
プログラムが動作しなくなります
これらのバグカテゴリは
バグを再現する時の難しさも表しています
これは私の経験上
再現するのが特に大変だったバグの例です
常にクラッシュするCプログラムがありました
非常に単純化されたバージョンで
こんな感じです
このプログラムを通常どおり実行すると
クラッシュします
アサーションは失敗します
しかしデバッガで実行すると問題なく動きました