題:
通過運行時分析在C程序中查找無效代碼
user2284570
2014-06-22 16:45:26 UTC
view on stackexchange narkive permalink

我有一個用C + POSIX編寫的大型應用程序,其中有很多函數從未在其中調用。但是,由於代碼的大小,很難手動跟踪它們。
有人建議將gcc與 -Wunused 和lto一起使用,但是它沒有返回任何使用過的函數,

所以我認為我需要一個代碼覆蓋工具來在運行時分析程序。人們建議我使用gcov或valgrind,但我找不到如何使用它們來打印無效函數列表的方法。僅gcov透露只有68%的已編譯函數被使用,但我沒有列出它們的任何方法。

那麼有人知道一個好的工具嗎?如果可以,請告訴我如何使用為此,它(歡迎使用命令行示例)

我刪除了源代碼中未使用的所有功能。只有這樣的函數才保留在源代碼中:

  if(條件語句){有些東西; dead_function(); some_stuff;}  

其中條件語句在運行時永遠不會為真,並且刪除 dead_function()將導致刪除語句以避免未定義的錯誤。

因此,您要查找的實際上不是未使用的函數(使用了`dead_function` *),而是無效代碼。這需要完全不同的技術!請注意,運行時分析只會發現並非在特定程序執行中運行過的代碼-該代碼可能在不同的情況下仍然有效。
@Gilles:這有點是gcov的問題...如何結合不同發射的結果?我有參數。也就是說,該程序僅做一件事:查找非常大的素數,因此可以輕鬆測試所有情況。這也是為什麼我嘗試刪除無效代碼*(對性能至關重要)*的原因。
似乎您不希望刪除*功能*,但是希望刪除*條件代碼*。我有那個權利嗎?
@IraBaxter:不,因為我目前不太在意函數中未使用的語句。我只想刪除完全沒用的功能(例如處理浮點數的功能)*。
請記住,除了加載時間和內存佔用量外,從未調用的代碼對性能幾乎沒有影響。為了幫助您將盡可能多的代碼移入許多小型DLL或.so共享庫中-從未實際使用過的庫將永遠不會加載。如果您遇到嚴重的性能問題,則可能有被調用的代碼,但從未使用過結果-lint可以幫助您找到這些代碼。
儘管我同意將閒置的代碼(包括被註釋掉的代碼)放在身邊是不雅觀的,但您可以放心,鏈接器應該能夠為您處理這些問題。如果找到工具,請確保該工具正確處理了函數指針。例如,在我的工作中,我們依靠由http://en.wikipedia.org/wiki/Branch_table驅動的http://en.wikipedia.org/wiki/Finite-state_machine來實現我們最重要的功能從不直接調用,而僅間接調用。回調可能也會發生同樣的情況。
@Mawg:如果沒有其他功能的調用,則鏈接器只能執行此操作。但就我而言,這些調用存在,但是在程序運行時它們從未使用過。我認識到這與死條件代碼刪除有關。
@SteveBarnes:由於CPU緩存的原因,從未在小型程序中調用過的代碼會產生影響。使用共享庫僅適用於在程序內部沒有鏈接調用的函數,而不適用於運行時從未調用的函數。鏈接器解決方案也是如此。
我所知道的用例中唯一的“免費”或幾乎免費的解決方案是,該函數被更高級別的代碼“使用”,但實際上從未調用過:a)編寫一些確保您確信的測試所有用例,然後b)在每個函數中添加`printf(__ func__);'作為第一行,*在gcc *中,這將在每次調用該函數時打印該函數的名稱-運行r測試捕獲輸出,然後輸出任何不包含的名稱在輸出中不被調用。
@SteveBarnes:我希望有很多功能可以像gcov一樣自動執行。我可能只是忘記了列出它們的選項,但找不到它。
使用您的映射文件來獲取代碼中所有函數的列表,並使用gcov列出所有被調用的函數,從第一個列表中減去該列表,您就會得到一個未被調用的函數列表。一個簡短的python腳本或一些awk魔術應該可以解決問題。
當然,如果您使用http://gcovr.com/guide.html gcovr,則應該能夠快速識別出永遠不會執行的代碼行。
@SteveBarnes:我沒有正確遵循指南,因此無法找到相關的選項,該選項將列出不屬於gcov輸出中使用的68%的功能。
@user2284570-請參閱我的新答案。
無論採用哪種解決方案,如果使用跳轉表(函數指針)都會出現問題。
@Mawg我不直接使用跳轉表。也許編譯器可以自動生成一些,但我不使用它們。
沒有很多。我們傾向於將它們大量用於嵌入式狀態/狀態耦合。還要提防回調函數。
三 答案:
#1
+4
Steve Barnes
2014-06-22 18:04:43 UTC
view on stackexchange narkive permalink

您可以將 splint alluse 標誌一起使用,以檢查未使用的功能,但就我個人而言,我將使用 doxygen 產生呼叫map-沒有父項的任何函數都可能未被使用-只要注意函數表中可能沒有被直接調用但狀態機之類的任何函數都可以從表索引中調用。

Doxygen是處理大型代碼庫的寶貴工具,值得在任何情況下學習如何使用。Doxygen是免費的,可在多個平台上使用,它還傾向於鼓勵隨時隨地編寫代碼。

對於僅被無法訪問的代碼調用的代碼,您將不得不使用完整的靜態分析工具(例如LDRA)(代價高昂),這將使您指向無法訪問的代碼。在這種情況下,最好先刪除所有無法訪問的代碼,然後再查找未調用的函數。另外,您將需要一個確定可以執行100%功能的測試套件-然後您可以在運行測試套件時在程序上使用探查器或覆蓋工具(例如gcov)。如果您的測試已經行使了全部功能,而您所覆蓋的部分覆蓋率為0%,那麼這些部分就不會被稱為 ,但是 呼叫無法訪問的用戶,並刪除該代碼以使鏈接程序始終不會抱怨。

“ *您可以將夾板與alluse標誌一起使用*”我還是不明白。您能提供一個命令行示例嗎?對於doxygen,答案是否定的!我剛剛刪除了代碼中未使用的所有功能。僅保留那些在代碼中使用過的代碼,但是某些條件語句使它們在運行時從不調用。呼叫圖無法提供數百種功能。我絕對需要一個可讀的輸出,其中包含未調用的函數,並帶有聲明它們的區域的文件名和行號。
Steel沒有詳細的示例...所以我不知道該怎麼辦...
@user2284570對於您最初發布的問題,此答案是正確的。您不應該以使答案無效的方式更改問題!如果您將“更新”編輯還原為問題,然後問一個新問題會更好。
當然,要當心由函數指針調用的函數,例如回調和狀態/事件跳轉表。
@Mawg沒有此類功能。
#2
+3
Harri
2018-09-20 02:35:13 UTC
view on stackexchange narkive permalink

鑑於@ user2284570處於通過測試覆蓋100%用例的舒適狀態,動態代碼分析將提供答案。在其他情況下,刪除功能,其調用和條件將需要進行徹底的審查。

任何代碼覆蓋率工具都將以一種或另一種形式報告功能覆蓋率。主要的抱怨似乎是報告未使用(這裡是無效)功能的確切位置。我不能說其他工具,但是我們公司有一個文本格式報告選項,其中包含用於源文件名和行數據的佔位符。由於需要一個具體的命令行示例,所以這裡是一個:

  $ csgcc -o myapp mycode.c $ ./myapp --run-all-tests $ cmcsexeimport -m myapp.csmes -e myapp.csexe --title = mytests $ cmreport --function-coverage -m myapp.csmes --format-unexecuted ='%f:%l' 

這將打印出失效的函數像這樣的位置:

  mycode.c:101mycode.c:213mycode.c:1032  

本地大學生寫了更詳細的說明

在消除未使用的函數之後,您還需要分析Branch Coverage,並刪除多餘的if()語句和其他語句。只是提防評估表達式的副作用。但是幸運的是,您的代碼覆蓋範圍很完美,可以檢測到回歸。

我必須說,自那時以來,我最終使用了逐步的手動調試來刪除無效代碼。因此,我不會嘗試您的工具。
#3
+1
Steve Barnes
2015-04-29 10:48:44 UTC
view on stackexchange narkive permalink

要回答您的修訂問題-如果您使用 gcc -fprofile-arcs -ftest-coverage 選項編譯了 all 代碼,然後運行了一系列測試確保涵蓋了所有功能和所有可能性(可能跨越多次運行)。

gcov 實用程序希望您能完成一些工作-它不只是具有“告訴我未調用的內容”的選項,因此您將不得不找到那些未被調用的功能。

可以在每個源文件上將 gcov -function-summaries 選項一起使用,您將生成一組輸出文件,其中將包括功能摘要-查找包含 never 0%的任何內容,以查找未執行的功能。

I建議添加一個您永遠不會調用的函數,或者知道一個尚未刪除的函數-這將使您看到輸出結果-然後可以使用 grep 來查找所有內容。

下一步是使用 grep 或類似於在代碼中所有這些功能存在的所有位置查看 gcov 輸出的內容-您應該看到包含調用的整個分支的執行計數為0 這將為您擴展測試-為您錯過的用例 -或刪除代碼提供一個良好的起點。

然後,它完全不能滿足我的需要:整理未使用的函數並告訴文件路徑中的行。發布此問題之前,我與kcachegrind所做的相同。手動排序功能是可以的,嘗試嘗試找到它們也可以,但是如果您有很多,則不是這樣。
我猜您將不得不僱用可以編碼的人來做到這一點!工具不會為您做很多事情,否則您將變得多餘。
我不需要自動刪除的內容。我需要一些可以在運行時列出未使用功能的列表,而該列表中沒有使用過的函數。我還需要它們的聲明路徑。我也是為自己做的。因此,期望我幾年不會寫自己的答案。
Steel無法自動將未使用的功能從所謂的功能中分類出來……同時,我意識到了在65Ko上生成安全隨機素數擬合的計算要求。


該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 3.0許可。
Loading...