源代碼下載
- 前提條件是打開ss,不然毛都下載不下來
- google重新發明了一套下載、編譯、測試自家項目的工具(輪子)depot_tool(包括gcllient、GYP、GN和Ninja等),所有的代碼都需要利用這些工具從命令行下載編譯。于是我們需要讓終端也具備ss的能力。
- 下載polipo,終端執行
sudo polipo socksParentProxy=localhost:1080
- 終端執行
export https_proxy=127.0.0.1:8123
,搞定。嫌每次打開終端都要輸入這句很麻煩的話,可以把它加到bashrc里面。
- 下載polipo,終端執行
- 下載depot_tools。或者打開ss的全局模式,去googlesource.com網站上下載,或者終端執行
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
- 將depot_tools目錄添加到系統
$PATH
,執行gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
加入要同步的項目目錄
- 執行
gclient sync
進行同步,獲得pdfium的源代碼。同步時間會很長,因為同步下來的目錄大小大概是3.5G - 期間會提示“To use a proxy in this situation, please supply those settings in a .boto file pointed to by the NO_AUTH_BOTO_CONFIG environment var.” 可能需要配置一下polipo,不過我依然下載了全部代碼,編譯通過了。
編譯
沒有找到項目首頁里說的編譯文件build/gyp_pdfium
,因為據說google已經放棄GYP,只支持GN構建了。GN的用法參考這里。按照代碼目錄下的README.md的步驟編譯就好啦。我關掉了v8和xfa支持,編譯起來還挺快。幾個注意事項如下:
- pdfium默認靜態編譯,不放心的話在args.gn文件里加上一句
pdf_is_complete_lib = true
。這個條件定義在根目錄下的BUILD.gn里,它的關鍵在于設置了GN工具的參數complete_static_lib
為真。 - 如果想修改args.gn或者某個BUILD.gn里定義的參數重新編譯,執行下列命令即可:
ninja -C <out_dir> -t clean # 清除已生成文件 gn gen <out_dir> # 重新生成編譯文件 ninja -C <out_dir> # 編譯
- 編譯過程中如果出現
cc1plus: all warnings being treated as errors
的錯誤,去/build/config/compiler/BUILD.gn
文件里把treat_warnings_as_errors
改成false
用AFL對pdfium做模糊測試
AFL需要對測試對象插樁,所以得用afl-gcc
或afl-clang
來編譯測試對象。雖然對google新發明的這套編譯流程一竅不通,不過我還是找到兩種辦法。
方法1:利用chromium中的現成代碼
不知道為什么,chromium代碼是直接支持afl測試的,但是作為它的pdf解析器的pdfium卻去掉了相應的代碼,然后又在BUILD.gn中保留了這個選項。幸好我見過不少精分,還比較淡定。
- 首先下載chromium的afl支持文件,放到third_party/afl目錄下。其實管用的就那一個BUILD.gn,src目錄下就是afl的源代碼,我直接用的我本機上的。
- 在args.gn文件里里加上
use_afl = true
和optimize_for_fuzzing = true
的開關,重新編譯。 - 編譯完成后在你的
<out_dir>
目錄下會有afl-fuzz文件,以及業已插樁完畢pdfium_test。下面用afl的默認方式測試pdfium_test即可。不過測試速度很慢,exec_speed只有200/sec左右。
PS:從pdfium的BUILD.gn代碼里可以知道,它還支持libfuzzer和drfuzz的測試,開關為use_drfuzz
和use_libfuzzer
。不過默認也是沒有對應支持文件的,需要自己加,我就沒研究了。
方法2. 在toolchain中指定自己編譯的afl-gcc
GN工具用toolchains來制定構建項目用到的編譯器、鏈接器以及相應參數等。通常GN的主配置文件會根據主機和目標的架構設置default_toolchain
,比如pdfium就在build/config/BUILDCONFIG.gn
里對這樣設置Linux x86_64下的缺省toolchain。
if (is_clang) {
_default_toolchain = "http://build/toolchain/linux:clang_$target_cpu"
} else {
_default_toolchain = "http://build/toolchain/linux:$target_cpu"
}
其中is_clang
可以在args.gn里聲明,缺省似乎是is_clang = true
。想用哪個編譯器插樁,就去代碼中引號指明的對應文件里把cc = "xxx"
改成 cc = "afl-xxx"
,并對應地將is_clang
設為true
或false
。
不知道得到的pdfium用的什么編譯器編譯出來的?執行
objdump -s --section .comment out/Debug/pdfium_test
看看注釋里有無clang或gcc字樣就可以了。
其他pdf引擎的編譯
常見的C/C++編寫的pdf引擎有poppler(Evince、Xpdf、Libreoffice)、podofo(ImageMagick)和mupdf(SumatraPDF,Zathura)
編譯Podofo
采用了CMake編譯系統,使用模糊測試同樣需要指定CC
、CXX
和--disable-shared
。所以編譯命令形如:
CC=afl-gcc CXX=afl-g++ cmake -G "Unix Makefiles" ../podofo-0.9.5/ -DPODOF O_BUILD_SHARED:BOOL=FALSE -DPODOFO_BUILD_STATIC:BOOL=TRUE
如果提示找不到FREETYPE_LIBRARY
和FONTCONFIG_LIBRARY
,安裝libfreetype6-dev,libfontconfig1-dev包就行了。剩下的找不到libjpeg、libtiff之類不影響程序編譯。
編譯poppler
同樣采用了CMake,編譯命令形如:
CC=afl-gcc CXX=afl-g++ cmake ../poppler-0.64.0/ -DBUILD_SHARED_LIBS=OFF