信息检索报告_iFixR:缺陷报告驱动程序修复
引用
Koyuncu A , Liu K , Tegawendé F. Bissyandé, et al. iFixR: Bug Report driven Program Repair[C]// the 2019 27th ACM Joint Meeting. ACM, 2019.
摘要
在現代軟件開發中,問題跟蹤系統通常用于收集用戶和開發人員的反饋。軟件維護的一個最終自動化目標就是為用戶報告的 bug 生成補丁。盡管這一雄心壯志與自動化程序修復的勢頭相一致,但到目前為止,文獻主要集中在生成和驗證設置上,其中故障定位和補丁生成由定義良好的測試套件驅動。然而,一方面,關于存在相關測試用例的常見假設在大多數開發設置中并不成立:許多 bug 被報告,而可用的測試套件無法揭示它們。另一方面,對于許多項目來說,bug 報告的數量通常超過了對它們進行分類的可用資源。為了提高補丁生成工具的使用率,我們研究了一種由缺陷報告驅動的新修復流程 iFixR:(1)缺陷報告被輸入到基于 IR 的故障定位器中;(2)由修復模式生成補丁并通過回歸測試進行驗證;(3) 向開發人員提出了生成補丁的優先順序列表。我們在 Defects4J 數據集上評估 iFixR,我們對該數據集進行了擴充(即錯誤與 bug 報告相關聯)和精心的組織(即測試用例的時間軸是自然分割的)。iFixR 使用基于 IR 的故障定位器為 21/44 個 Defects4J 錯誤生成真實/可信補丁。iFixR 準確地將一個真實的/合理的補丁放在了其中 8/13 個故障的前 5 個建議中。
1 簡介
這篇論文。我們提出研究一個由錯誤報告驅動的程序修復系統的可行性,從而用基于信息檢索(IR)的故障定位取代傳統的基于頻譜的故障定位。最后,我們提出了一個新的程序修復工作流 iFixR,它通過模擬手動調試的基本步驟來考慮實際的修復設置。iFixR 在以下約束下工作:當錯誤報告被提交到問題跟蹤系統時,再現該錯誤的相關測試用例可能不容易獲得。
因此,iFixR 在本研究中被用來評估 APR 在有限測試套件的實際限制下的可行性。iFixR 使用自然語言編寫的錯誤報告作為主要輸入。最終,我們做出以下貢獻:
(1)我們提出了一個程序修復系統的體系結構,以適用于維護人員處理用戶報告的缺陷的約束。特別是,iFixR 用基于信息檢索(IR)的故障定位取代了傳統的基于頻譜的故障定位。
(2)我們提出了一種策略,優先考慮補丁,以便向開發人員推薦。事實上,假設只有回歸測試用例的存在來驗證補丁候選,許多補丁可能會在與報告 bug 相關的未來測試用例上失效。我們會按照補丁的順序,先呈現正確的補丁。。
(3)我們評估和討論 iFixR 在 Defects4J 基準測試上的性能,以便與最先進的 APR 工具進行比較。為此,我們為 APR 針對 bug 報告提供了一個改進的 Defects4J 基準。bug 被小心地與相應的 bug 報告聯系起來,對于每一個 bug,我們能夠分離出在相關修復之后引入的未來測試用例。
總體而言,實驗結果表明,在實際的軟件開發周期中,自動補丁生成的集成是一個很有前途的研究方向。特別是,我們的研究結果表明,與基于頻譜的故障定位錯誤相比,基于 IR 的故障定位錯誤導致的過擬合補丁較少。此外,iFixR 提供的結果可與大多數最先進的 APR 工具相媲美,盡管它是在修復后知識(即未來測試用例)不可用的約束下運行的。最后,iFixR 的優先級策略傾向于將更正確/合理的補丁放在推薦列表的頂部。
2 動機
我們通過回顧 APR 的兩個基本步驟來闡述我們工作的動機:
(1)在故障定位過程中,相關程序實體被識別為必須更改的可疑位置。通常,最先進的 APR 工具利用基于頻譜的故障定位(SBFL),它使用通過和失敗測試用例的執行覆蓋信息來預測錯誤語句。我們剖析了 Defects4J 數據集,以突出針對用戶報告的 bug 進行故障定位的實際挑戰。
(2)一旦生成了一個補丁候選,補丁驗證步驟確保它實際上與修復程序相關。目前,廣泛使用的基于測試的 APR 技術使用測試套件作為修復預言。然而,這受到測試套件不完整性的挑戰,并且在修復過程中可能進一步不符合開發人員的需求和期望。
3 方法
圖 2 概述了我們提出的 iFixR 方法的工作流程。對于有缺陷的程序,我們考慮以下問題:
(1)bug 在哪里?我們將程序用戶提交的自然語言 bug 報告作為輸入。我們依賴于此報告中的信息來定位 bug 位置。
(2)我們應該如何改變代碼?我們應用在實際錯誤修復中反復出現的修復模式。修復模式是按照抽象語法樹的結構選擇的,該樹表示所識別的可疑代碼的代碼實體。
(3)哪些補丁是有效的?我們對在發現缺陷時編碼功能需求的正面測試用例的可用性沒有任何假設。然而,我們利用現有的測試用例來確保,至少補丁不會使程序倒退。
(4)我們首先推薦哪些補丁?在沒有完整的測試套件的情況下,我們不能保證所有通過回歸測試的補丁都能修復錯誤。我們依靠啟發式來重新排列已驗證補丁的優先級,以增加將正確補丁放在列表頂部的概率。
圖 2 FixR 程序修復的工作流
3.1 輸入:錯誤報告
問題跟蹤系統被開源和商業領域的軟件開發社區廣泛使用。盡管開發人員可以使用問題跟蹤系統跟蹤他們遇到的 bug 和要實現的功能,問題跟蹤系統允許用戶參與,作為收集生產中軟件執行情況反饋的通信渠道。
表 3 說明了當 LANG 庫代碼的用戶在使用 NumberUtils API 時遇到問題時的一個典型錯誤報告。提供了錯誤行為的描述。有時,用戶可能會在錯誤描述中包含一些關于如何重現 bug 的信息。通常,用戶只需插入代碼片段或轉儲執行堆棧跟蹤。
表 3 bug 報告示例
在這項研究中,在 162 個 bug 報告的數據集中,我們注意到只有 27 個是由同時也是項目開發人員的用戶報告的。報告了 15 個錯誤,并再次由同一個項目貢獻者修復。這表明在大多數情況下,bug 報告確實是由需要項目開發人員注意的軟件用戶真正提交的。
給定有缺陷的程序版本和錯誤報告,iFixR 必須展開工作流程,以精確識別(在語句級別)錯誤代碼的位置。在這一步中,不能依賴未來的測試用例。我們認為,如果這樣的測試用例能夠觸發該 bug,那么在軟件向用戶交付之前,持續集成系統將幫助開發人員處理該 bug。
3.2 不帶測試用例的故障定位
為了識別程序源代碼中有缺陷的代碼位置,我們求助于基于信息檢索(IR)的故障定位(IRFL)。總的目標是利用 bug 報告中使用的術語和源代碼之間的潛在相似性來識別相關的錯誤代碼位置。文獻包括大量關于 IRFL 的工作,研究人員系統地從給定的 bug 報告中提取標記,以在由源代碼文件集合形成的文檔搜索空間中生成匹配的查詢,并通過從源代碼中提取的標記索引。IRFL 方法然后根據相關性的概率(通常用相似性得分來衡量)對文檔進行排序。高排名的文件被預測為可能包含錯誤代碼的文件。
在這項工作中,我們開發了一種算法,根據最先進的 IRFL 工具的輸出(即文件)對可疑語句進行排序,從而生成一個基于 IR 的細粒度故障定位器,該定位器隨后將容易地集成到具體的補丁生成管道中。
3.2.1 對可疑文件進行排名。
我們利用現有的 IRFL 工具。考慮到從大量 bug 報告中提取標記的代價高昂,常常是調優 IRFL 工具的必要條件,我們選擇了一個由作者提供數據集和預處理數據的工具。我們使用 D&C 作為在線可用的文件級 IRFL 的具體實現,這是一個基于機器學習的 IRFL 工具,使用 70 維特征向量(缺陷報告中的 7 個特征和源代碼文件中的 10 個特征)的相似矩陣:D&C 使用多個分類器模型,每個分類器模型針對特定的 bug 組進行訓練報告。給出一個錯誤報告,不同分類器的不同預測被合并,生成一個可疑代碼文件列表。我們的 D&C(算法 1 中的第 2 行)的執行是可處理的,因為我們只需要預處理那些必須定位的 bug 報告。已提供經過培訓的分類器。我們確保不會導致數據泄漏(也就是說,分類器沒有使用我們希望在這項工作中定位的 bug 報告進行訓練)。
3.2.2 可疑陳述
補丁生成需要有關必須更改的代碼實體的細粒度信息。對于 iFixR,我們建議為基于頻譜的故障定位生成標準輸出,以便于集成和重用最先進的補丁生成技術。首先,我們基于最近一項大規模的錯誤修復研究的結論,將可疑位置的搜索空間限制在更容易出錯的語句中。在詳細調查了來自 Java 項目的 16000 多個實際補丁的基于抽象語法樹(AST)的代碼差異之后,以下特定的 AST 語句節點比其他節點更容易出錯:IfStatements、ExpressionStatements、FieldDeclarations,ReturnStatements 和 VariableDeclarationStatements。算法 1 的第 7-17 行詳細說明了生成可疑語句的排序列表的過程。
算法 1 描述了我們在 iFixR 中使用的故障定位方法的過程。在返回的 IRFL 可疑文件列表中選擇前 k 個文件及其計算的可疑度得分。然后對每個文件進行解析,只保留從中提取文本標記的相關易出錯語句。bug 報告的摘要和描述也會被分析(詞法上)以收集它的所有標記。由于 bug 報告中可能出現的堆棧跟蹤和其他代碼元素的具體性質,我們使用正則表達式檢測堆棧跟蹤和標記代碼元素改進分詞過程,它基于標點符號,駝峰式大小寫分裂(例如 findNumber 分裂成 find 和 number)以及蛇形命名法分裂(例如 find_number 分裂成 find 和 number)。然后在對所有標記執行詞干分析之前,使用停止詞刪除,以創建與術語的根的同質性(即通過合并相同術語的變體)。每個標記包(用于 bug 報告和每個語句)最終用于構建一個特征向量。我們使用向量之間的余弦相似度來對與 bug 報告相關的文件語句進行排序。
考慮到 k 個文件,每個文件的語句對于 bug 報告都有自己的相似性分數,我們用關聯文件的可疑度評分來加權這些分數。最后,我們使用加權得分對語句進行排序,并生成一個代碼位置(即文件中的語句)的排序列表,以推薦作為候選故障位置。
3.3 基于修復模式的補丁生成
在自動程序修復中,一個常見且可靠的策略是基于修復模式(也稱為修復模板或程序轉換模式)生成具體的補丁。在這項工作中,我們考慮 Kim 等人的 PAR 系統。具體地說,我們建立在 kPAR 上,一種開源的 PAR java 實現。表 4 提供了本工作中使用的修復模式的枚舉。如圖 3 所示,修復模式對更改操作的配方進行了編碼,這些操作應用于改變代碼元素。
表 4 在 iFixR 中實現的修復模式

圖 3 “Insert Cast Checker”固定模式示意圖
對于給定的報告錯誤,一旦我們的故障定位器生成可疑語句的列表,iFixR 會反復嘗試為每個語句選擇修復模式。修復模式的選擇是基于每一個可疑語句的上下文信息(即抽象語法樹 AST 中的所有節點)進行的。具體地說,iFixR 解析代碼并以廣度優先的策略遍歷可疑語句 AST 的每個節點,從其第一個子節點遍歷到最后一個葉節點。如果一個節點與上下文修復模式匹配(即,相同的 AST 節點類型),那么該修復模式將應用于通過改變修復模式中配方后匹配的代碼實體來生成修補程序候選。無論節點是否匹配修復模式,iFixR 都會不斷遍歷其子節點,并搜索修復模式以依次生成候選修補程序。此過程將迭代執行,直到遇到葉節點為止。
3.4 帶回歸測試的補丁驗證
對于每一個報告的 bug,基于模式匹配的故障定位和代碼變異將產生一組候選補丁。在一個典型的基于測試的 APR 系統中,這些候選補丁必須讓程序通過所有測試用例(包括一些正面測試用例,這些測試用例編碼了與 bug 相關的實際功能需求)。因此,補丁候選集被積極修剪,以刪除所有不符合這些要求的補丁。在我們的工作中,根據我們的調查結果,這些測試用例可能在報告錯誤時不可用,我們假設 iFixR 無法推理未來的測試用例來選擇候選補丁。
相反,當 bug 被報告時,我們只依賴于代碼庫中可用的過去的測試用例。這樣的測試用例被用來執行回歸測試,這將確保,至少被選中的補丁不會阻礙已經存在的、未更改的軟件部分的行為,這些部分已經被開發人員在他們當前的測試套件中明確編碼。
3.5 輸出:補丁推薦列表
最終,iFixR 會為開發人員生成一個補丁程序建議的排名推薦列表。到目前為止,修補程序的順序主要受工作流中兩個步驟的影響:
(1)定位:我們的語句級 IRFL 生成一個要優先修改的語句的排序列表。
(2)模式匹配:錯誤代碼實體的 AST 節點被分解成子節點,并以廣度優先的方式迭代導航,以連續生成候選補丁。
最終,生成的補丁列表具有一定的順序,該順序帶有故障定位的偏差,并通過預先設置的修復模式匹配的廣度優先策略進行噪聲處理。
我們建議采用以下啟發式方法重新排列候選修補程序的優先級:
(1)最小變化:我們喜歡最小化補丁程序和有缺陷程序之間的差異的補丁。
(2)故障定位可疑度:當兩個候選補丁具有相同的編輯腳本大小時,使用基于 IR 的故障定位過程中產生的懷疑分數(相關語句的)來打破這種平局
(3)受影響的代碼元素:在對修復模式和相關 APR 的性能進行手動分析之后,我們發現一些更改操作與 bug 修復無關。在對文獻中的修復模式和相關 APR 的性能進行人工分析后,我們發現有些更改操作與 bug 修復無關。因此,對于相應的預定義模式,iFixR 系統性地將其生成的補丁相對于任何其他補丁的優先級降低。這些補丁是由以下方式產生的:(i) 突變一個文字表達式,(ii) 將一個變量突變為一個方法調用或最終靜態變量,或 (iii) 插入一個沒有參數的方法調用。
4 研究問題
評估的目標是評估為用戶報告的 bug 自動生成補丁的可行性,同時調查預期的瓶頸以及社區為實現這一長期努力必須接受的研究方向。為此,我們重點關注以下與 iFixR 工作流中不同步驟相關的研究問題。
RQ1:故障定位。基于 IR 的故障定位在多大程度上能夠為 APR 場景提供可靠的結果?我們研究比較了我們的細粒度 IRFL 實現與經典的基于頻譜的定位時的性能差異。
RQ2:過擬合。基于 IR 的故障定位在多大程度上能指向受過擬合影響較小的位置?我們特別研究了不完整測試套件通常對過擬合問題的影響。
RQ3:補丁排序。iFixR 的補丁排序策略的有效性如何?我們通過重新模擬軟件維護周期的真實案例,研究了 iFixR 的整體工作流程,當一個 bug 被報告時:未來的測試用例無法用于補丁驗證。
5 評估結果
在這一部分中,我們將呈現之前列舉的研究問題的調查結果。為了評估 iFixR,我們依賴于 Defects4J,它在 Java APR 文獻中被廣泛用作基準。此外,為了真實地評估 iFixR,我們重新組織了數據集測試套件,以準確地模擬用戶提交 bug 報告時的上下文。
5.1 RQ1:故障定位
故障定位是程序修復的第一步,我們評估了在 iFixR 中開發的基于 IR 的故障定位的性能。正如 Liu 等人最近研究的那樣,不應該期望 APR 工具能夠修復當前故障定位系統無法定位的錯誤。盡管如此,通過 iFixR,我們必須證明我們的細粒度 IRFL 提供了與 APR 文獻中使用的 SBFL 工具相當的性能。
表 5 提供了關于 bug 定位的性能測量。SBFL 是基于 GZoltar 測試框架的兩個不同版本進行的,但總是基于 Ochiai 排名指標。最后,由于故障定位工具會輸出一個可疑語句的排名列表,因此結果是以是否將正確的位置放在前 k 個可疑語句下為標準。在本工作中,我們認為如果有任何一個錯誤語句被定位,則該錯誤被定位。
表 5:錯誤定位結果。
總的來說,結果表明,當應用于 Defects4J bug 數據集上時,我們的 IRFL 實現與常見的基于頻譜的故障定位實現相當。雖然性能結果相似,但 SBFL 是通過考慮未來的測試案例來應用的。為了突出 IRFL 的實際意義,我們為每個可定位在前 10 名的 bug 計算了從 bug 報告日期到該 bug 提交相關測試用例日期之間經過的時間。根據圖 6 所示的分布,平均而言,IRFL 可以將這個時間縮短 26 天。
圖 6:從 bug 報告到提交測試用例之間的運行時間分布
最后,為了強調未來測試用例對基于頻譜的故障定位的重要性,我們考慮了所有 Defects4J 的 bug,并計算了有和沒有未來測試用例的定位性能。表 6 中列出的結果證實,在大多數 bug 情況下,定位是不可能的。只有 10 個 bug(395 個中)可以在報告 bug 時 SBFL 的前 10 個可疑語句中被定位。相比之下,我們的 IRFL 在沒有相關測試用例觸發 bug 的相同條件下,定位了 72 個 bug。
表 6 缺陷定位報告
在 iFixR 中,基于 IR 的細粒度故障定位與基于 Spectrum 的故障定位在定位 Defects4J 錯誤方面一樣準確。此外,它沒有要求測試用例的限制,而這些測試用例在報告錯誤時可能是不可用的。
5.2 RQ2:過擬合
補丁生成試圖用合適的修復模式來突變可疑的 bug 代碼。APR 的一個共同挑戰在于如何有效地選擇錯誤的語句。在典型的基于測試的 APR 中,測試用例驅動這些語句的選擇。然而,測試套件的不完整性目前被懷疑經常會導致生成的補丁的過度擬合。
我們執行補丁生成實驗來研究本地化偏差的影響。我們將我們的 IRFL 實現與基于測試的 APR 文獻中常用的 SBFL 實現進行比較。我們回顧一下,這些實驗中的補丁驗證步驟沒有對未來的測試用例做任何假設(即,所有的測試用例都像在經典的 APR 流水線中一樣被利用)。對于每個 bug,根據故障定位系統(IRFL 或 SBFL)得出的可疑語句中 bug 語句的等級,補丁生成可以產生更多或更少的相關補丁。表 7 詳細介紹了修復性能與錯誤語句在故障定位輸出中的位置的關系。結果是以考慮故障定位器返回的 top-k 語句所能找到的可信和正確補丁的數量來提供的。
表 7 IRFL 與 SBFL 對 Defects4J 的 bug 生成的正確/合理補丁數量的影響
img總的來說,我們發現 IRFL 和 SBFL 的定位信息導致了相似的修復性能。實際上 IRFL 支持的 APR 在 Lang 項目 bug 上的表現優于 SBFL 支持的 APR,在 Math 項目 bug 上的表現也優于 SBFL 支持的 APR。總體而言,有 6 個使用 IRFL 輸出修復的 bug,不能使用 SBFL 輸出修復(盡管假設有 bug 觸發測試用例可以運行 SBFL 工具)。
我們調查了兩種定位方案中可信補丁的情況,以描述這些補丁看起來只對測試套件進行過擬合的原因。表 8 詳細列出了兩種場景的過擬合原因。
表 8 分析補丁看似合理但不正確的原因
img對 Defects4J 數據集的實驗表明,基于 IR 的故障定位所提供的代碼位置比基于頻譜的故障定位所建議的代碼位置導致的過擬合補丁更少。
5.3 RQ3:補丁排序
前面的實驗集中在補丁生成上,而我們最后的實驗則評估了 iFixR 的完整流程,因為它被想象成可以滿足開發者在實踐中可能面臨的限制:未來的測試用例,即那些編碼了錯誤程序沒有滿足的功能要求的測試用例,在錯誤被報告時可能無法獲得。因此,我們拋棄了 Defects4J 數據集的未來測試用例,并生成必須推薦給開發人員的補丁。因此,評估協議包括評估在多大程度上正確/合理的補丁被放置在建議列表的頂部。
5.3.1 整體性能
表 9 詳細介紹了 iFixR 推薦補丁的性能:我們介紹了在推薦補丁列表的前 k 名中生成并呈現正確/合理補丁的 bug 數量。在沒有未來的測試用例來驅動補丁驗證過程的情況下,我們使用啟發式方法對補丁候選者重新進行優先級排序,以確保最先推薦的補丁最終是正確的(或者至少在相關測試用例被執行時是可信的)。我們將介紹不重排優先級和重排優先級兩種情況的結果。
表 9 iFixR 在 Defects4J 基準上的補丁推薦的總體性能
img回顧一下,鑒于重新組織的基準單獨包括了未來的測試用例,我們可以利用它們來系統化評估補丁的合理性。然而,補丁的正確性仍然是通過與開發者提供的、基準中可用的實際錯誤修復進行比較來手動決定的。總的來說,我們注意到 iFixR 的性能是很有希望的,因為對于 13 個 bug,iFixR 能夠在每個 bug 的前 5 個推薦補丁中提出一個可信的補丁。在這些可信的補丁中,有 8 個最終被發現是正確的。
5.3.2 與最先進的基于測試的 APR 系統的比較
為了客觀地定位 iFixR 的性能(它不需要未來的測試用例來定位 bug、生成補丁并呈現分類的補丁推薦列表),我們統計了 iFixR 能夠提出正確/可信補丁的 bug 數量。我們考慮 iFixR 的三種情況。
(1)開發者將只得到前 5 個推薦的補丁,這些補丁只經過回歸測試驗證:在這種情況下,iFixR 在用合理或正確的補丁修復的 bug 數量上比最先進的技術要好一半。
(2)向開發者提供所有(即,不僅是前 5 名)生成的補丁,并通過回歸測試進行驗證:在這種情況下,只有 4 種(16 種中的)最先進的 APR 技術優于 iFixR.all。
(3)開發人員看到的是所有生成的補丁,這些補丁已經用增強的測試套件進行了驗證(即用未來的測試用例樂觀地進行驗證):在這種配置下,iFixR 的性能優于所有最先進的,除了 SimFix,SimFix 使用復雜的技術來提高故障定位精度和搜索修復成分。應該注意的是,在這種情況下,我們的優先級策略并沒有應用到生成的補丁中。iFixR 代表了我們實驗的參考性能,它評估了優先級。
表 10 提供了比較矩陣。當我們考慮到 Defects4J bug 的數量時,iFixR 在補丁推薦方面提供了合理的性能,這些錯誤在前 5 名中被成功修補(在我們假設沒有相關測試案例來驗證補丁候選者的情況下)。性能結果甚至可以與文獻中許多最先進的基于測試的 APR 工具相媲美。
表 10 iFixR 與最先進的 APR 工具的比較
img5.3.3 iFixR 補丁的特性
在表 11 中,我們描述了 iFixR 推薦的正確和合理的補丁的特征 5。總的來說,更新和插入的修改是成功的;大多數補丁影響的是一條語句,并且精確地影響了一個語句中的表達式實體。
表 11 改變 iFixR 的正確補丁的屬性
img5.3.4 iFixR 所修復的 bug 的多樣性
最后,在表 12 中,我們剖析了 iFixR5 能夠為其推薦正確或合理補丁的 bug 的性質。關于 bug 報告的優先級信息是從問題跟蹤系統中收集的,而根本原因則是通過分析 bug 報告和修復來推斷的。
總的來說,我們注意到 13 個 bug 中,有 9 個被標記為主要問題。解決了 12 個不同的 bug 類型(即根本原因)。相比之下,R2Fix 只關注了 3 種簡單的 bug 類型。
表 12 剖析 iFixR 成功修復的 BUG
img6 結論
在這項研究中,我們研究了從錯誤報告中自動生成補丁的可行性。為此,我們實現了 iFixR,一個 APR 的變體,適應了用戶報告錯誤時測試用例不可用的限制。所提出的系統重新審視了基本步驟,特別是故障定位、補丁生成和補丁驗證,這些步驟都緊緊依賴于基于測試的 APR 系統中的正向測試用例。
在不對測試用例的可用性做任何假設的情況下,我們在重新組織 Defects4J 基準后,證明了 iFixR 可以為不同的用戶報告的 bug 生成和推薦優先正確的(和更可信的)補丁。我們甚至發現 iFixR 的修復性能與 Defects4J 數據集上的大多數基于測試的 APR 系統相當。
致謝
本文由南京大學軟件學院 2020 級碩士吳青衡翻譯轉述。
總結
以上是生活随笔為你收集整理的信息检索报告_iFixR:缺陷报告驱动程序修复的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 道指上涨超2100点创纪录 苹果市值重回
- 下一篇: win7旗舰版重置密码忘了怎么办 如何重