飲酒プログラミング -ほぼリーディング-
ごきげんよう、かりあどです。 今回は飲酒プログラミングAdvent Calendarを書いていきます。
実は1日前に書く予定だったのですが、色々環境構築でハマってしまい後ろが空いていたので1日後ろにこっそりずらしました😇 (今までは会社貸与PC上に環境作っていたのですが、退職に伴い個人PCに作り直しました)
本日のワイン
自分はワインが好きなのですが、別に詳しいとかそんなことは全くなく適当な感想を書いているかもしれないのでその点はご容赦ください🙏 今回飲む竜眼種ですが、主に長野県で栽培されており、なかでも善光寺で栽培されていたことから善光寺ブドウとも呼ばれているらしいです。 飲んだ感想としては辛口なのですが、強いドライ感はなくすっきりした味わいの中にほのかに香る果実感と言った感じで日本食にとても合いそうな味わいです。 ざっくりいうと辛口よりのほんのり甘口と言った感じでしょうか。
本日のお題
今年のiOSDCでこんな発表をしました。
このスライドの後半でSanitizerCoverageというものが出てくるのですが、発表当時深く追いきれなかったところがあるので、そこら辺をなんとなくみていきたいと思います。
そもそもこのSanitizerCoverage使ってる人いるのかな、という気持ちはあるのですが、まあ実装されている以上誰かが使っているのでしょう。
SanitizerCoverageのドキュメントは基本的にClangのものを参考にしていきます。
ドキュメントを見ると実はSanitizerCoverageにはいくつかの種類があることがわかります。 その例として、 * Tracing PCs with guards * Inline 8bit-counters * PC-Table * Tracing PCs
などが挙げられます。まあほとんどExperimentalなんですけどね。 これらがswiftcには実装されているのか?みてみようと思います。
手がかりとしてまずはこのSanitizerCoverageに関するtestを見てみようと思います。
ちなみに今2杯目です。 そして書き始めるまでに環境構築で失敗してめっちゃ時間使いました。 ブランチを切り替えたりしていたのですが、次のようにハマったりしていました。
utils/update-checkoutがうまくいかない…
— kariad🍆/かりあど🍆 (@kariad_uu) 2019年12月18日
救いの手が
最近llvmがモノレポに移行したのでそれの影響だと思います。—cloneオプションをつけるとどうですか?
— kateinoigakukun (@kateinoigakukun) 2019年12月18日
感謝、圧倒的感謝...!
実際にチェックアウトしたディレクトリ構成を見ていたら以前は/swift-source/llvm
となっていたものが/swift/llvm-project/llvm
となっていることに気がつきました。
そのあともビルドしたらCMakeのエラーがでてよくわからなかったりしていましたが、なんとかNinjaのビルドを通すことに成功したみたいなので、もう少し先へ進めそうです。(13インチMacBook Proなのでビルドに1~2時間かかってます)
ついでに3杯目を注ぎにいきます。 また余談なのですが、ワインオープナーはウイングタイプよりもソムリエナイフタイプのがきれいに開けやすいと思います。
こういうやつ
testを読む
test/IRGen
のディレクトリにsanitize_coverage.swift
があります。
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=func %s | %FileCheck %s -check-prefix=SANCOV // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=bb %s | %FileCheck %s -check-prefix=SANCOV // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge %s | %FileCheck %s -check-prefix=SANCOV // RUN: %target-swift-frontend -emit-ir -sanitize=fuzzer %s | %FileCheck %s -check-prefix=SANCOV // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,trace-cmp %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_CMP // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,trace-bb %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_BB // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,indirect-calls %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_INDIRECT_CALLS // RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,8bit-counters %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_8BIT_COUNTERS // RUN: %target-swift-frontend -emit-ir -sanitize=fuzzer %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_CMP #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) import Glibc #elseif os(Windows) import MSVCRT #else #error("Unsupported platform") #endif // FIXME: We should have a reliable way of triggering an indirect call in the // LLVM IR generated from this code. func test() { // Use random numbers so the compiler can't constant fold #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) let x = arc4random() let y = arc4random() #else let x = rand() let y = rand() #endif // Comparison is to trigger insertion of __sanitizer_cov_trace_cmp let z = x == y print("\(z)") } test() // FIXME: We need a way to distinguish the different types of coverage instrumentation // that isn't really fragile. For now just check there's at least one call to the function // used to increment coverage count at a particular PC. // SANCOV_TRACE_CMP: call void @__sanitizer_cov_trace_cmp // SANCOV: call void @__sanitizer_cov
Swiftコンパイラのテストコードはlit(LLVM Integrated Tester)と呼ばれるツールを用いて行います。 使い方は公式ドキュメントだけではなく、日本語での説明もあるのでとても参考になります。
Swiftコンパイラに関する丁寧な日本語ドキュメントは結構あるのでとても助かります。
これらを参考に先ほどのテストをまずは実行してみます。
litが上のQiitaだと swift-source/llvm/utils/lit/lit.py
とされていますが、上述したとおりswift-source/llvm-project/llvm/utils/lit/lit.py
になっていることだけ注意です。
llvm-project/llvm/utils/lit/lit.py -sv build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/test-macosx-x86_64/IRGen/sanitize_coverage.swift
当然ですが成功しますね。 が、よくテストコードをみるとなんか怪しいです。FIXMEと書いてる時点でよく見なくても怪しいですが。
例えばこの行において
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,8bit-counters %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_8BIT_COUNTERS
-check-prefix
でSANCOV_8BIT_COUNTERS
をチェックする内容として記述されていますが、ファイル内でそのような定義は見当たりません。
ファイルで定義されているのは
// SANCOV_TRACE_CMP: call void @__sanitizer_cov_trace_cmp // SANCOV: call void @__sanitizer_cov
この二つだけです。 この二つ以外はテストとして記述はされているが、アサーションされていないと言った感じでしょうか?
試しにSANCOV_8BIT_COUNTERSについてClangのドキュメントを参考にこうなるであろうという期待結果のCHECKを追加してみます。
// SANCOV_8BIT_COUNTERS: __sanitizer_cov_8bit_counters
テストが失敗しました。 少なくともこの形では実装されていなさそうです。 ちなみにこちらもテストはないですが、Tracing PCs with guardsについては以下のように追記してみるとテストは通ります。
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_PC_WITH_GUARD // SANCOV_TRACE_PC_WITH_GUARD: call void @__sanitizer_cov_trace_pc_guard
上で貼ったスライドにもありますが、Tracing PCs with guardsについては実装されていることはわかります。
もうだいぶ酔ってきたのでそろそろ締めたい。
じゃあこのSANCOV_8BIT_COUNTERSが実装されているのか、についてコードを追っていくと、 それぞれを受け取るフラグの存在は確認できます。
うーん、今日はここまで... ここから先はまた今後調べてみます。
ワインはとても美味しかったです。 いろんなワイン飲んでいきたいですね。