1 / 34

プログラム変更支援を目的とした コードクローン情報付加手法の提案と実装

プログラム変更支援を目的とした コードクローン情報付加手法の提案と実装. 井上研究室 佐々木 亨. 研究の背景 . コードクローンとは ソースコード中に存在するコード片で、同形のコード片が他に存在するもの コピー&ペーストによるプログラム再利用などで生じる ソフトウェア保守を困難にする あるコード片にバグがあると、そのコードクローン全てについて修正の検討をしなければならない 機能を追加する場合も同様のことが言える. C1. C2. C3. C4. C5. クローンクラス. クローンクラス 同形のコードクローンの集合 例. クローンクラス1

hidi
Download Presentation

プログラム変更支援を目的とした コードクローン情報付加手法の提案と実装

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. プログラム変更支援を目的としたコードクローン情報付加手法の提案と実装プログラム変更支援を目的としたコードクローン情報付加手法の提案と実装 井上研究室 佐々木 亨 特別研究報告会

  2. 研究の背景  • コードクローンとは • ソースコード中に存在するコード片で、同形のコード片が他に存在するもの • コピー&ペーストによるプログラム再利用などで生じる • ソフトウェア保守を困難にする • あるコード片にバグがあると、そのコードクローン全てについて修正の検討をしなければならない • 機能を追加する場合も同様のことが言える 特別研究報告会

  3. C1 C2 C3 C4 C5 クローンクラス • クローンクラス 同形のコードクローンの集合 • 例 クローンクラス1 {C1,C4,C5} クローンクラス2 {C2,C3} 特別研究報告会

  4. コードクローン検出ツールCCFinder • ソースコードを字句解析してトークンの列に分解してから、トークン単位で直接比較することによりクローンを検出 • 数百万行規模のシステムにも実用時間で解析可能 • 実用的に意味のないクローンを検出しない • さまざまな企業のソフトウェアにも適用している 特別研究報告会

  5. CCFinderの出力 #begin{file description} 0 1475 3429 /home/test/test1.c 1 3213 9669 /home/test/test2.c 2 3584 11420 /home/test/test3.c : #end{file description} #begin{clone} #begin{set} 0 1250,3,2811 1258,17,2853 0 1260,3,2861 1268,13,2903 1 2962,3,8913 2970,10,8955 #end{set} #begin{set} 1 49,1,66 55,41,120 2 62,1,93 68,39,147 2 75,1,15981,37,213 #end{set} : : #end{clone} 解析対象のファイル群の情報 ファイルのID・ファイル行数・ ファイルパスなどからなる クローンクラス情報 クローンクラス ID1のファイルの49行目から55行目 ID2のファイルの62行目から68行目 ID2のファイルの75行目から81行目 特別研究報告会

  6. クローン情報を用いてソースコードを修正する際の問題点クローン情報を用いてソースコードを修正する際の問題点 • コードクローンに対する機能追加・修正中にクローン情報とソースコードで行番号のずれが生じる • 対処法 • 行番号のずれを意識しながら作業する • 効率が悪い • 修正箇所を間違える可能性 特別研究報告会

  7. 研究の目的 • コードクローンに対する機能追加・修正中に行番号のずれを意識せずに作業する • コードクローンの位置情報を、コメントとしてソースコードに埋め込む手法の提案とツールの実装を行う 特別研究報告会

  8. コードクローン情報の追加(コメントの利用)コードクローン情報の追加(コメントの利用) • 基本方針 • クローンクラスごとに割り付けたIDを利用する • クローンクラスに含まれる全行にコメントを追加する • コメントの形式 • クローンクラスの先頭行は“//@$クローンクラスのID@” • 先頭行以外は“//@クローンクラスのID@” • ある行が2つ以上のクローンクラスに属している場合はコンマで区切る 特別研究報告会

  9. コメント追加例 30: while(a>10){ 31: b=b+a; 32: a=a+1; 33: } 34: sum = a; 40: while(c>10){ 41: d=d+c; 42: c=c+1; 43: } 83: while(e>10){ 84: f=f+e; 85: e=e+1; 86: } 87: sum = e; //@$1@ //@1@ //@1@ //@1@ //@$1@ //@1@ //@1@ //@1@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ クローンクラス1 #begin{set} 130,1,4533,1,52 140,1,5843,1,65 183,1,10286,1,109 #end{set} クローンクラス2 #begin{set} 130,1,4534,1,55 183,1,10287,1,112 #end{set} 特別研究報告会

  10. while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c > 10){ d=d+c; c=c+1; } : while(e > 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c < 10){ d=d+c; c=c+1; } : while(e < 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ デバッグへの利用手順 while文の条件が間違っている while(a > 10){ b=b+a; a=a+1; } Sum = a; : while(c > 10){ d=d+c; c=c+1; } : while(e > 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c < 10){ d=d+c; c=c+1; } : while(e < 10){ f=f+e; e=e+1; } Sum = e; 1.あるバグを発見する 2.ソースコードにクローン情報の コメントを付加する 3.バグを修正する 4.修正部分のコメントを調べる 5.コメント中のクローンクラスのID を利用してクローンクラスの 先頭行を見つける 6.他の修正箇所を見つける 7.同様の修正を行う 8.不要になったコメントを除去する 特別研究報告会

  11. ツールの機能 • コメント追加機能 • コメントにはクローンクラスのIDを利用 • コメントはクローンクラスに含まれる全行に追加 • 追加はオリジナルファイルに行わず、編集用の一時的なファイルに行う • クローンクラス検索機能 • クローンクラスを指定し、そのコメントがあるファイル情報等を検索・表示 • 一時ファイル編集機能 • コメント追加後、ファイル編集のためにファイルを選択して開く • コメント除去機能 • 不要となったコメントを、クローンクラスのIDを指定して除去する • すべてのコメントを一括して除去する • 一時ファイル書き戻し機能 • 編集用の一時的なファイルの変更をオリジナルファイルに反映させる 特別研究報告会

  12. 適用実験 • 日本語入力システム「かんな」(http://canna.sourceforge.jp)のバージョン3.6と3.6p1の間でのセキュリティ問題の修正に対して擬似的なデバッグを行うことで適用した • ソースコードはC言語で記述、92ファイル、約9万行 • この修正は、バッファのオーバーフローを調べる処理の追加で、全20箇所にほぼ同じ修正を行っている • 具体的な追加コードは if(Request.type7.datalen!=SIZEOFSHORT*3) return (-1);    等 • 実行環境 FreeBSDPentium4 1.5GHz 512MB 特別研究報告会

  13. 具体例(修正前の「かんな」ソースコード) • 下図の2405行目の直前にオーバーフローの検査処理を追加する 2399 static 2400 ProcWideReq7(buf) 2401 BYTE *buf ; 2402 { 2403 ir_debug( Dmsg(10, "ProcWideReq7 start!!\n")); 2404 2405 buf += HEADER_SIZE; Request.type7.context = S2TOS(buf); 2406 buf += SIZEOFSHORT; Request.type7.number = S2TOS(buf); 2407 buf += SIZEOFSHORT; Request.type7.yomilen = (short)S2TOS(buf); 2408 ir_debug( Dmsg(10, "req->context =%d\n", Request.type7.context)); 2409 ir_debug( Dmsg(10, "req->number =%d\n", Request.type7.number)); 2410 ir_debug( Dmsg(10, "req->yomilen =%d\n", Request.type7.yomilen)); 2411 2412 return( 0 ) ; 2413 } 特別研究報告会

  14. 赤い部分のずれは2行 青い部分のずれは4行 行番号の増減を意識しながら作業するのは困難 ツールを利用しない場合- コードクローン位置情報のずれ 「かんな」バージョン3.6のコードクローン情報 #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770       : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820       : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443       : #end{set} #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770       : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820       : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443       : #end{set} #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770       : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820       : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443       : #end{set} この修正例において全部で20箇所101行もの処理を追加 2420行目に同様の2行分の修正を行ったとする 2405行目に追加したため ソースコードとコードクローン情報の間で行番号が2行ずつずれている 特別研究報告会

  15. 追加処理 この部分のコメントを見ればクローンクラス1311と1318に関して同様の 修正の検討をすればいいとわかる(実際に1311に対して修正を行っていた) ツールを利用する場合- コメント付加後に追加 2399 static //@$1311@,@$1318@ 2400 ProcWideReq7(buf) //@1311@,@1318@ 2401 BYTE *buf ; //@1311@,@1318@ 2402 { //@1311@,@1318@ 2403 ir_debug( Dmsg(10, "ProcWideReq7 start!!\n")); //@1311@,@1318@ 2404 //@1311@,@1318@ 2405 if(Request.type7.datalen!=SIZEOFSHORT*3) 2406 return (-1); 2407 buf += HEADER_SIZE; Request.type7.context = S2TOS(buf); //@1311@,@1318@ 2408 buf += SIZEOFSHORT; Request.type7.number = S2TOS(buf); //@1311@,@1318@ 2409 buf += SIZEOFSHORT; Request.type7.yomilen = (short)S2TOS(buf); //@1311@,@1318@ 2410 ir_debug( Dmsg(10, "req->context =%d\n", Request.type7.context)); //@$1317@ 2411 ir_debug( Dmsg(10, “req->number =%d\n", Request.type7.number)); //@1317@ 2412 ir_debug( Dmsg(10, "req->yomilen =%d\n", Request.type7.yomilen)); //@1317@ 2413 //@1317@ 2414 return( 0 ) ; //@1317@ 2415 } //@1317@ 行番号のずれを意識することなく作業することができる 特別研究報告会

  16. まとめと今後の課題 • まとめ • プログラム変更作業を支援するための、コードクローン情報付加手法の提案、ツールの試作をし、「かんな」のバグ修正作業に適用した • 今後の課題 • 実際のソフトウェア開発・保守現場での評価 特別研究報告会

  17. 終わり 特別研究報告会

  18. これ以降は発表に入れないスライド 特別研究報告会

  19. 定義 • 完全性 • 修正が必要な箇所のうち実際に検出された割合 • 効率性 • 検出されたうち実際に修正箇所である割合 • 検出された • ある修正箇所を特定したときに、その箇所にあるコメント内のクローンクラスIDをたどってたどり着ける箇所 特別研究報告会

  20. 評価内容 • 本ツールにおける「検出された数」の定義 • 修正箇所(関数単位)を節点として、同じクローンIDをもつ他の節点に辺をつなぐ • ある節点から到達することのできる節点の総数 //CL1 //CL1,2 //CL3 //CL2 総修正箇所は4箇所 検出された箇所は5箇所 検出された修正箇所は3箇所 完全性 (4箇所中3箇所)75% 効率性 (5箇所中3箇所)60% //CL2,3 特別研究報告会

  21. 評価結果 f値を見ると、本ツールはgrepより有効である 特別研究報告会

  22. CCFinderの最小一致トークン数を変化させた 補足実験 • コメント数 : 1修正箇所中のコメント数 特別研究報告会

  23. grepで検出されなかった唯一のクローン ・この部分を検索キーとすればgrepでも検出されるが、これだと他にも数多く検出される  (135行一致する f値は0.26) static ProcWideReq1(buf) BYTE *buf ; /* ARGSUSED */ { ir_debug( Dmsg(10, "ProcWideReq1 start!!\n") ); return( 0 ) ; } このようにgrepなどのコード片を指定して検索する場合は利用者の能力によって検索結果に差が出る しかし、 本ツールではその必要がないためその心配がない 特別研究報告会

  24. 1311は修正箇所で1318は修正しなくてよかったのはなぜ?1311は修正箇所で1318は修正しなくてよかったのはなぜ? クローンクラス1311 クローンクラス1312 クローンクラス1318 実際には1312に対して修正が行われていた つまり、1311に修正を行ったというより、 1312に対して修正を行っていた 特別研究報告会

  25. 編集用の一時ファイルの作成方法 • 対象のファイル群のパスの深さの最小値から、ディレクトリファイル階層を実現する 1 /home/Canna36/cmd/wtoc/wtoc.c 2 /home/Canna36/dic/ideo/pubdic/pod.c 3 /home/Canna36/doc/man/guide/tex/cannaindex.c 4 /home/Canna36/misc/is.c 5 /home/Canna36/sample/sample.c だと4と5が深さ4でパスが最も短い。深さ3番目からをこちらで新たに作った ディレクトリAppend_Comment_Files中に再現する 1’ / Append_Comment_Files /cmd/wtoc/wtoc.c 2’ / Append_Comment_Files /dic/ideo/pubdic/pod.c 3’ / Append_Comment_Files /man/guide/tex/cannaindex.c 4’ / Append_Comment_Files /misc/is.c 5’ / Append_Comment_Files /sample/sample.c となる。 特別研究報告会

  26. 既存のコードクローン検出手法(1/2) Bakerの手法 • 行単位でソースコードを比較してコードクローンを検出 Baxterらの手法 • C言語のソースファイルを入力,構文解析して,解析木(の部分木)を比較する [Baker1995] B. S. Baker: “On finding Duplication and Near-Duplication in Large Software System,” Proc. Second IEEE Working Conf. Reverse Eng., pp. 86-95, Tronto, Canada (Jul., 1995). [Baxter1998] I. D. Baxter, A. Yahin, L. Moura, M. Sant’Anna, and L. Bier: “Clone Detection Using Abstract Syntax Trees,” Proc. of ICSM ’98, pp. 368-377, Bethesda, Maryland (Nov., 1998). 特別研究報告会

  27. 既存のコードクローン検出手法(2/2) • Merloらの手法 • 手続き(メソッドや関数)の特徴メトリクスを比較して,計測値が似ていればコードクローンであると判定する [Balazinska1999] M. Balazinska, E. Merlo, M. Dagenais, B. Lague, and K.A. Kontogiannis, "Measuring Clone Based Reengineering Opportunities", Proc. 6th IEEE Int'l Symposium on Software Metrics (METRICS '99), pp. 292-303, Boca Raton, Florida, Nov. 1999. 特別研究報告会

  28. CCFinder: コードクローン検出ツール ソースコードを字句解析してトークンの列に直してからコードクローン検出を行う • (浅い)文法知識に基づいたソースコード変形 • クラススコープや名前空間による複雑な名前の正規化を行う • 初期化テーブルを取り除く • モジュールの区切りを認識する • 言語依存部分を取り替えることで,さまざまなプログラミング言語に対応 特別研究報告会

  29. コードクローン検出手順 (1)ソースコードを入力し,トークンの列にする (2)変形ルールにより,トークン列を変形する (3)パラメータ置換を行う (4)マッチングアルゴリズムによりコードクローンを検出する (5)コードクローンの位置(ファイル,行, カラム)を出力する 特別研究報告会

  30. 例題ソースコード 1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. } 10. static void goo(String [] a) throws RESyntaxException { 11. RE exp = new RE("[0-9,]+"); 12. int sum = 0; 13. for (int i = 0; i < a.length; ++i) 14. if (exp.match(a[i])) 15. sum += parseNumber(exp.getParen(0)); 16. System.out.println("sum = " + sum); 17. } 特別研究報告会

  31. 4-6行目と 13-15行目, 8-10行目と 17-19行目 1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) { 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. } 9. System.out.println("sum = " + sum); 10. } 11. static void goo(String [] a) throws RESyntaxException { 12. RE exp = new RE("[0-9,]+"); 13. int sum = 0; 14. for (int i = 0; i < a.length; ++i) { 15. if (exp.match(a[i])) 16. sum += parseNumber(exp.getParen(0)); 17. } 18. System.out.println("sum = " + sum); 19. } 特別研究報告会

  32. 1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. } 10. static void goo(String [] a) throws RESyntaxException { 11. RE exp = new RE("[0-9,]+"); 12. int sum = 0; 13. for (int i = 0; i < a.length; ++i) 14. if (exp.match(a[i])) 15. sum += parseNumber(exp.getParen(0)); 16. System.out.println("sum = " + sum); 17. } 特別研究報告会

  33. 修正する 修正のたびにコードクローンの位置情報を更新すると‥ 検出されなくなる クローンペア クローンでなくなる 特別研究報告会

  34. メニューバー ステータスバー 実装 • Javaで実装 • 動作環境 FreeBSD 特別研究報告会

More Related