動的スライスを用いた バグ修正前後の実行系列の比較

Slides:



Advertisements
Similar presentations
シーケンス図の生成のための実行履歴圧縮手法
Advertisements

XHTML構文検証手法における スクリプト要素の静的解析アルゴリズム
プログラムの変更前後での 実行履歴の差分検出手法
プログラミング基礎I(再) 山元進.
情報伝播によるオブジェクト指向プログラム理解支援の提案
アクセス修飾子過剰性の変遷に着目したJavaプログラム部品の分析
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
変数間データフローグラフを用いた ソースコード間の移動支援
プログラムの動作を理解するための技術として
F11: Analysis III (このセッションは論文2本です)
リファクタリングのための 変更波及解析を利用した テスト支援ツールの提案
動的スライスを用いたバグ修正前後の実行系列の差分検出手法の提案
プログラム静的解析手法の効率化と 解析フレームワークの構築に関する研究
プログラム実行履歴を用いたトランザクションファンクション抽出手法
静的情報と動的情報を用いた プログラムスライス計算法
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
コードクローンに含まれるメソッド呼び出しの 変更度合の分析
コードクローンに含まれるメソッド呼び出しの 変更度合の調査
ソードコードの編集に基づいた コードクローンの分類とその分析システム
独習JAVA 6.8 コンストラクタの修飾子 6.9 メソッドの修飾子 6.10 ObjectクラスとClassクラス 11月28日(金)
コードクローンの分類に基づいた メソッド引き上げ手順の提案とその有効性評価
動的依存グラフの3-gramを用いた 実行トレースの比較手法
ポインタ解析におけるライブラリの スタブコードへの置換の効果
オブジェクト指向プログラムにおける エイリアス解析手法の提案と実現
インラインスクリプトに対するデータフロー 解析を用いた XHTML 文書の構文検証
シーケンス図を用いて実行履歴を可視化するデバッグ環境の試作
動的スライスを用いたバグ修正前後の実行系列の差分検出手法
利用関係に基づく類似度を用いたJavaコンポーネント分類ツールの作成
限られた保存領域を使用する Javaプログラムの実行トレース記録手法の 提案と評価
Javaプログラムの変更を支援する 影響波及解析システム
リファクタリング支援のための コードクローンに含まれる識別子の対応関係分析
プログラム動作理解支援を目的とした オブジェクトの振舞いの同値分割手法
動的データ依存関係解析を用いた Javaプログラムスライス手法
ソースコードの特徴量を用いた機械学習による メソッド抽出リファクタリング推薦手法
コードクローンの動作を比較するためのコードクローン周辺コードの解析
Javaバイトコードの 動的依存解析情報を用いた スライシングシステムの実現
コードクローン検出に基づくデザイン パターン適用支援手法の提案と実現
プログラム理解におけるThin sliceの 統計的調査による有用性評価
バイトコードを単位とするJavaスライスシステムの試作
コード片に共通した特性を自動抽出する ソースコード閲覧ツールの試作
コードクローンの理解支援を目的としたコードクローン周辺コードの解析
コードクローン分類の詳細化に基づく 集約パターンの提案と評価
Javaバーチャルマシンを利用した 動的依存関係解析手法の提案
コーディングパターンの あいまい検索の提案と実装
JAVAバイトコードにおける データ依存解析手法の提案と実装
JavaScriptを含んだHTML文書に対する データフロー解析を用いた構文検証手法の提案
オブジェクトの協調動作を用いた オブジェクト指向プログラム実行履歴分割手法
静的情報と動的情報を用いた Javaプログラムスライス計算法
同期処理のモジュール化を 可能にする アスペクト指向言語
依存関係の局所性を利用した プログラム依存グラフの 効率的な構築法
保守請負時を対象とした 労力見積のためのメトリクスの提案
オープンソースソフトウェアに対する コーディングパターン分析の適用
メソッドの同時更新履歴を用いたクラスの機能別分類法
アスペクト指向プログラミングの 動的プログラムスライスへの応用
蓄積されたオブジェクトの動作履歴を用いた 実行履歴削減手法の提案
エイリアス関係を考慮した Javaプログラム用静的スライシングツール
プログラムの一時停止時に 将来の実行情報を提供するデバッガ
動的スライスを用いたバグ修正前後の実行系列の差分検出手法の提案
動的スライスを用いたバグ修正前後の実行系列の差分検出手法の提案
コードクローン解析に基づく デザインパターン適用候補の検出手法
回帰テストにおける実行系列の差分の効率的な検出手法
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
メソッド抽出リファクタリングが 行われるメソッドの特徴調査
木構造の比較に基づく メソッド呼び出し履歴の変化の可視化手法
オブジェクト指向言語における セキュリティ解析アルゴリズムの提案と実現
識別子の読解を目的とした名詞辞書の作成方法の一試案
眞鍋 雄貴,石尾 隆 大阪大学 ※論文リストでの表記順序と, 発表順序は異なりますのでご注意ください
プログラム依存グラフを用いた ソースコードのパターン違反検出法
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
Presentation transcript:

動的スライスを用いた バグ修正前後の実行系列の比較 石尾 隆 大阪大学 ※本スライドは 松村 俊徳(2016年3月修了),石尾,井上: 動的スライスを用いたバグ修正前後の実行系列の差分検出手法の提案 SIGSE 2016年3月の発表をもとに構成しています

背景 デバッグ作業によってプログラムを修正したとき,「他に影響がない修正ができた」ことを確認したい デバッグ作業の手順 テストによるバグの発見 特定のテスト実行の分析による原因の特定 バグの修正 バグ修正結果のテストによる確認 回帰テストの実施による影響の有無の確認

アプローチ バグ修正の前後のテスト実行を比較して,その変化を検出する テスト自体によって確認できること: バグに対応するテストが通るようになる バグに関係ないテストの結果に変化がない 本手法で追加で確認できること: その修正に起因する変数の値の計算手順の変化の有無 その修正に起因する計算途中での条件分岐の変化の有無  バグ修正に起因しない変化は許容する

変化は観測しやすい,変化がないことは確認しにくい カバレッジで一部の変化は検出可能 今まで実行されなかった命令が実行されるようになる,など 一方で,カバレッジに変化がないから影響がなかった,というのは根拠に乏しい 「影響がない」といえるくらい強い基準が必要 厳しくメモリの状態を比較すると,実行ごとに変化するデータ(現在日時など)に反応してしまう

既存研究: 影響波及解析 プログラムに変更を加えたことにより影響がでる可能性のある部分を求める技術は存在する 代表的な手法 Call Graph 修正したメソッドを呼び出しているメソッドはテストが必要である.コストは小さいが不正確なことも. Static Slicing 修正したメソッドの実行結果を使う可能性のあるメソッドはテストが必要である.範囲が広すぎて使い物にならないことがある Dynamic Slicing 修正したメソッドの実行結果を使っていたメソッドはテストが必要である.テスト依存なので少しあやしい.

既存研究:デバッグ用の実行の比較 Differential Slicing Relative Debugging 同一プログラムの2つの実行(問題が起きる場合と起きない場合)を比較する 異なる計算結果となった原因を過去に遡る方向に依存関係をたどることで求める 修正されたプログラムの実行の比較ではない Relative Debugging 2つの似ているプログラムを同時に実行して,メモリ状態に差が起きた時点で実行を一時停止するデバッガ 差異があった場所で停止することはできるが,差異の情報を整理はしてくれない

本研究の提案 バグ修正前後の動的スライスを比較し,Java プログラムの動作の差分を検出する 動的スライス:  命令1回ずつの実行の関係を表現するグラフ 命令間でデータが流れた 条件分岐によって実行することを決定した 修正されたメソッドを基点としたスライスが異なれば,実際に影響を受けている 変数の値が変わっただけでは検出しない それによって経路が変わったら検出する

サンプルプログラム boolean foo(int i, int i2){ return i1 < i2; } int i; If( foo(1,2) ){ i = 0; }else{ i = 1; } System.out.print(i); 変更 boolean foo(int i, int i2){ return i1 > i2; }

フォワードスライス 修正前 修正後 return if(foo) i = 0 print(i) return if(foo) i = 1 命令1回ずつの実行を,データフローと制御条件で連結したもの 修正前 データフロー 条件分岐 データフロー return if(foo) i = 0 print(i) 修正後 return if(foo) i = 1 print(i) i=1は今まで実行されていなかった print(i)はiの定義元が異なっている バグ修正の影響を受けている

フォワードスライスの比較方法 単純なグラフ比較 頂点や辺の集合比較 グラフ上の経路の比較 2つのフォワードスライスの差分を検出可能  グラフが巨大になると計算コストが高くつく 頂点や辺の集合比較 カバレッジ計算(命令網羅率,分岐網羅率)に相当 グラフの比較に比べコストは低いが,検出漏れが多くなる グラフ上の経路の比較 グラフを経路という形に分解して比較する  フォワードスライスでは,分岐や合流が多数存在するため,経路数が組み合わせ爆発を起こす

アプローチ: 経路上の頂点集合の比較 修正前 修正後 return if(foo) i = 0 print(i) return メソッドの戻り値が通過する経路上の頂点集合に差がある=動作が異なる 修正前 return if(foo) i = 0 print(i) {} {if(foo)} {if(foo), i = 0} 修正後 return if(foo) i = 1 print(i) {} {if(foo)} {if(foo), i = 1}

試作した実装の計算手順 実行 トレース1 実行 トレース2 JUnit 実行 実行再現ツール 実行記録命令 プログラム P1, P2 (バグ修正前,後) 実行記録命令 埋め込みツール プログラム +実行記録命令 実行 トレース1 実行 トレース2 動的プログラム依存グラフ 実行再現ツール

適用実験 実験対象 実験環境 バグ修正データセットDefects4jに収録されているApache Commons Langのバグ10個を対象 バグ修正前後のバージョンでの,全てのテストケースを実行し差分を検出 ライブラリは実行の観測から除外 実験環境 OS:Ubuntu14.04 CPU: Intel Xeon 2.90GHz メモリ:256GB

計算時間 # 実行の記録 [s] PDGの計算 [s] スライス計算 [s] スライス比較 [s] 1 185 / 187 5,507 / 5,261 884 / 760 0.019 / 0.015 2 184 / 185 5,429 / 5,374 763 / 762 0.004 / 0.001 3 186 / 184 5,293 / 5,174 796 / 662 0.014 / 0.010 4 / 191 5,482 / 5,372 1,189 / 1637 N/A 5 186 / 185 5,274 / 5,286 1,234 / 1,224 0.003 / 0.001 6 189 / 188 5,320 / 5,171 2,546 / 2,916 NA 7 189 / 185 5,470 / 5,439 1,231 / 1,203 0.022 / 0.012 8 91 / 93 2,601 / 2,565 366 / 350 0.001 / 0.001 9 104 / 104 2,932 / 2,895 1,272 / 1918 1,231.148 / 1,909.242 10 104 / 107 2,906 / 2,795 427 / 416 0.616 / 0.400

フォワードスライスの比較結果 # 頂点 [個] 辺 [本] 経路 [通り] 固有な頂点 [個] 1 6,260 / 6,996 11,024 / 12,321 3.57×10^18 / 3.57×10^18 0 / 42 2 1,298 / 1,326 1,364 / 1,404 319 / 337 1 / 7 3 6,015 / 6,078 10,591 / 10,705 3.57×10^18/ 3.57×10^18 0 / 3 4 51,491,332 / 51,491,332 97,249,586 / 97,249,586 N/A 5 329 / 396 389 / 462 136 / 167 0 / 19 6 83,584,442 / 83,586,850 156,272,662 / 156,277,095 2.01×10^18/ 2.06×10^18 7 4,603 / 4,812 8,002 / 8,373 39 / 73 8 0 / 0 9 68,481,669 / 68,481,483 119,895,430 / 119,895,112 5.32×10^18/ 5.32×10^18 2 / 0 10 631,407 / 631,407 131,313 / 131,313

#1:修正前コード 文字列を数値に変換するメソッド 桁数で作る数値の型を判断 public static Number createNumber(final String str) throws NumberFormatException { ・ if (pfxLen > 0) { // we have a hex number final int hexDigits = str.length() - pfxLen; if (hexDigits > 16) { // too many for Long return createBigInteger(str); } if (hexDigits > 8) { // too many for an int return createLong(str); return createInteger(str); 桁数で作る数値の型を判断

#1:修正後コード public static Number createNumber(final String str) throws NumberFormatException { ・ if (pfxLen > 0) { // we have a hex number char firstSigDigit = 0; // strip leading zeroes for(int i = pfxLen; i < str.length(); i++) { firstSigDigit = str.charAt(i); if (firstSigDigit == '0') { // count leading zeroes pfxLen++; } else { break; } final int hexDigits = str.length() - pfxLen; if (hexDigits > 16 || (hexDigits == 16 && firstSigDigit > '7')) { // too many for Long return createBigInteger(str); if (hexDigits > 8 || (hexDigits == 8 && firstSigDigit > '7')) { // too many for an int return createLong(str); return createInteger(str);

#1:検出された差分 修正前はここで失敗し終了 修正メソッド 修正後は以降も実行される public void TestLang747() { assertEquals(Integer.valueOf(0x8000), NumberUtils.createNumber("0x8000")); assertEquals(Integer.valueOf(0x80000), NumberUtils.createNumber("0x80000")); assertEquals(Integer.valueOf(0x800000), NumberUtils.createNumber("0x800000")); assertEquals(Integer.valueOf(0x8000000), NumberUtils.createNumber("0x8000000")); assertEquals(Integer.valueOf(0x7FFFFFFF), NumberUtils.createNumber("0x7FFFFFFF")); assertEquals(Long.valueOf(0x80000000L), NumberUtils.createNumber("0x80000000")); assertEquals(Long.valueOf(0xFFFFFFFFL), NumberUtils.createNumber("0xFFFFFFFF")); // Leading zero tests assertEquals(Integer.valueOf(0x8000000), NumberUtils.createNumber("0x08000000")); assertEquals(Integer.valueOf(0x7FFFFFFF), NumberUtils.createNumber("0x007FFFFFFF")); assertEquals(Long.valueOf(0x80000000L), NumberUtils.createNumber("0x080000000")); assertEquals(Long.valueOf(0xFFFFFFFFL), NumberUtils.createNumber("0x00FFFFFFFF")); ・ 修正後は以降も実行される このメソッドは他の機能の実行でも利用されているが,それらのデータフロー,条件分岐には変化なし

まとめと今後の課題 バグ修正前後のプログラムの実行を比較する手法を試作した 今後の課題 修正によって影響された範囲だけを差分として見る 実行した日時の違いなど,異なる要因による変化と区別できる 差分が検出されれば,正しい影響か開発者が確認 検出されなければ違いがなかったと言えそう 今後の課題 判定の高速化,厳密化:現在取り組み中 開発者に有益な情報に絞った結果の表示:修正によって条件分岐が変化した if 文のリストの抽出など? 「予想通り影響を受けた・受けていない」といえるものでないと開発者が確認できない