Common Printing Dialog をデバッグしてみよう (その1) [改訂あり]
d:id:naruoga:20090527:1243382202 はこのネタの前フリ。
もう現役プログラマといえなくなってしまったオイラだけど、ついつい勢いでジュンク堂の Debug Hacks 刊行記念イベント (d:id:naruoga:20090509:1241887511) に行ってしまい、サインもらうために本買ったのさ。
Debug Hacks -デバッグを極めるテクニック&ツール
- 作者: 吉岡弘隆,大和一洋,大岩尚宏,安部東洋,吉田俊輔
- 出版社/メーカー: オライリージャパン
- 発売日: 2009/04/27
- メディア: 単行本(ソフトカバー)
- 購入: 12人 クリック: 419回
- この商品を含むブログ (73件) を見る
で、最近急速に積ん読が増えてるのを反省して、とりあえず風を通して、Windows プログラマにも共通の知見があったら回りのエンジニアに渡して読んでもらおうなんて思ってたわけ。
けどやっぱりというかなんていうか Linux 本なわけで。しかもかなりディープなカーネルデバッグの本なわけで *1。
まあそんなこんなで風通し終えて、デバッグとかトラシューの過程って推理小説みたいで面白いよなー、なんて平凡な感想を持ちつつ本棚にしまおうとして。
いやまてよ、部署で数少ない Linux 技術者としては、ちょっと手を動かして実践してみないとイケてなくね? と思いまして、せっかくだから手を動かした結果を晒してみようというエントリでございます。
こちとら gdb [enter] って押すのも今日初めてな素人なんでツッコミ歓迎ですハイ。
Target
Common Printing Dialog KDE 版。
現象解説
こいつには「CUPS プリントキューが一個もないと KCrash が "Application 'view-dialog' Crashing..." とつぶやきつつ 『ファイルが見つかりません』といって寂しく終了する」というバグとも仕様とも言い難い動作*2がありまして。
まあ実際プリントキューがなかったらプリントダイアログだしてもしょうがないので仕様をどう決めるかってのは議論の余地はあると思うんですけどね。でも Crash するのは論外やろ。
ただ、エラーメッセージが --previewfile で指定したファイルがなかったときと同じというのは、いかなプロトタイプでもちょっと……じゃないかな? と。エラーハンドリングが悪いのかエラーメッセージを手抜きしたのかわかんないけど。
これぐらいの不具合だったらデバッガ出すよりエラーメッセージで grep してソース眺めた方が早いって説もあるけど、そこはあえてデバッガを使うのです。
デバッグオプションつきコンパイル
こんなところでいきなりつまづくところがみっともないです。
だって cmake よくわかんないんだもん。
結局 id:niitsuma さんの d:id:niiitsuma:20071127:1201323141
にずばっと書いてあったので、よしよし……と丸パクリして。
$ cmake -DCMAKE_INSTALL_PREFIX=/usr/bin/kde4 -DCMAKE_BUILD_TYPE=Debug .. -- Found Qt-Version 4.5.0 (using /usr/bin/qmake) -- Found X11: /usr/lib/libX11.so -- Phonon Version: 4.3.0 -- Found KDE 4.2 include dir: /usr/include -- Found KDE 4.2 library dir: /usr/lib -- Found the KDE4 kconfig_compiler preprocessor: /usr/bin/kconfig_compiler -- Found automoc4: /usr/bin/automoc4 -- Found CUPS: -lcups -lgssapi_krb5 -lgnutls -lz -lpthread -lm -lcrypt CMake Error at kde4-dialog/CMakeLists.txt:7 (PKGCONFIG): Unknown CMake command "PKGCONFIG". -- Configuring incomplete, errors occurred!
あれあれ?
どーやら cmake って生成したファイルをオプション変えたからって上書きしてくれないみたいね >
15分ほど悩んでしまった。
で、結局は build フォルダを消して再ビルドしたらうまく行ったです。
ちゃんとデバッグ版になってるの?
ということで不安になったので gdb で読み込んでみました。
今回は view-dialog の起動時の不具合なので、普通に引数で渡せばおっけーですね。kde4-cpd のようなデーモン的モジュールはプロセスアタッチが必要でしょうけど。
$ gdb kde4-dialog/view-dialog GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... (gdb) b main Breakpoint 1 at 0x80510e7: file /home/naruhiko/common-printing-dialog/kde4-dialog/view-dialog.cpp, line 11. (gdb)
"b main" でブレークポイントかけたとき、ちゃんとファイル名と行数が出てるから大丈夫なようですね。ぶい。
まーとりあえず最後まで実行してみましょうかってことで、
(gdb) run Starting program: /home/naruhiko/common-printing-dialog/build/kde4-dialog/view-dialog [Thread debugging using libthread_db enabled] [New Thread 0xb5e3b940 (LWP 15164)] [Switching to Thread 0xb5e3b940 (LWP 15164)] Breakpoint 1, main (argc=1, argv=0xbff4ac24) at /home/naruhiko/common-printing-dialog/kde4-dialog/view-dialog.cpp:11 11 int main(int argc, char* argv[]) { (gdb) cont Continuing. ASSERT failure in QVector<T>::operator[]: "index out of range", file /usr/include/qt4/QtCore/qvector.h, line 335 Program received signal SIGABRT, Aborted. 0xb7f2d422 in __kernel_vsyscall () (gdb) q The program is running. Exit anyway? (y or n) y
……あれ?*3
なんか違うエラー起きてね?
SIGABRT なんか出してちゃだめだろ。しかも Qt の中で (T_T)。
微妙に蒼くなりながら確認です。
切り分け切り分け
思いつく切り分けは
てなとこです。順に確認……しません。
だって Retail 版つくるのめんどくさいんだもん。別の環境で見ます。→見ました。何度も書くけど思いきりクラッシュしてました。
gdb の外では?
さすがにデバッガが外乱要素ってことはないと思うんですが、念のため。
$ kde4-dialog/view-dialog ASSERT failure in QVector<T>::operator[]: "index out of range", file /usr/include/qt4/QtCore/qvector.h, line 335 KCrash: Application 'view-dialog' crashing... sock_file=/home/naruhiko/.kde/socket-naruhiko-virtualbox/kdeinit4__0 Warning: connect() failed: : No such file or directory KCrash cannot reach kdeinit, launching directly. KCrash failed to exec(), errno = 2
……だよなー。やっぱり。
プリントキューがある場合でも起きるか
これはけっこう大きな違いじゃないかと思ってました。
つまり、デバッグメッセージから見るとベクタの範囲外参照で SEVABRT してます。
わたしゃ Linux のことはよく知りませんが、ふつーベクタの範囲外参照とかいちいちチェックしてたら遅くなるのでサボったりするんじゃないでしょうか?
だから、今回の現象自体が実は「非デバッグ版でエラーがすり抜けるために他のエラーと区別がつかない」という現象なんじゃないかと疑っておるわけです。
という考察は的外れだけどちょこっと当たってもいないこともない。KCrash っていうぐらいだからその場で止まってくれればいいのに、なぜだか処理を継続しちゃうのね。それがファイル名不正のエラーハンドラに合流するってことだと踏んでるんだけど、さて結果は如何に……
ということでプリントキューを一個作ってやると、
$ kde4-dialog/view-dialog CUPSOptionsBox::sizeHint() = QSize(18, 18) CUPSOptionsBox::sizeHint() = QSize(18, 18) CUPSOptionsBox::sizeHint() = QSize(18, 18) Layout 2: plwidth: 181 pwidth: 412 Processing group "General" Processing group "C1L0" Processing group "C1L1" Processing group "C1L2" Processing group "C1L4" CPConfMatrixWidget::add( "Application Name" , 1 , 1 ); CPConfMatrixWidget::add( "General" , 2 , 1 ); CPConfMatrixWidget::add( "Output Control Extra 4" , 3 , 1 ); CPConfMatrixWidget::add( "Output Control Extra 2" , 1 , 2 ); CPConfMatrixWidget::add( "Output Control Extra 1" , 2 , 2 ); CPConfMatrixWidget::add( "Output Control Common" , 3 , 2 ); Adding option "ColorModel" Adding option "Duplex" Adding option "InputSlot" Adding option "PageRegion" ... Refreshing preset list... There are 0 presets. Loading presets for printer "Ricoh-Aficio-MP-7500" After loading, there are 0 presets. Refreshing preset list... There are 0 presets.
となってちゃんとダイアログが起動します。
おーし、ということはプリントキューが一個も存在しないときにいわゆる境界領域バグを起こしてる可能性が高いですね♪
ちょっと面白くなってきました。「エラーハンドリングのミス」とか「エラーメッセージの手抜き」とかじゃさすがにやる気がしない。
ということで次回は今回エラートラップしてるところからバックトレースしていってエラー箇所を突き止めるなんて話になりますかね。少しワクワクしますね。
しかし私出勤前に徹夜でこのエントリ書いてるので一旦打ち切り。ただでさえ私のブログは一エントリが長すぎると町で評判なので。