Carbon Language - C++20/C++23 - Sanitizer

書(shū)接上一篇 ## ?? Carbon Language,在 Windows 系下運(yùn)行失敗。目前只能通過(guò) Windows WSL 系統(tǒng)體驗(yàn) Carbon。
Carbon 語(yǔ)言當(dāng)前的實(shí)現(xiàn)稱為 Explorer,其主要目的是作為語(yǔ)言的明確規(guī)范,官方提供在線體驗(yàn)網(wǎng)站,它是基于 LLVM 現(xiàn)代編譯器框架開(kāi)發(fā)的一個(gè)前端編譯器。
作為該目標(biāo)的一個(gè)擴(kuò)展,Explorer 還可以用作原型設(shè)計(jì)和驗(yàn)證語(yǔ)言更改的平臺(tái)。因此,它優(yōu)先于展示直接可讀的代碼,其次是性能、診斷質(zhì)量和其他常規(guī)實(shí)現(xiàn)。換言之,它的目標(biāo)受眾是從事 Carbon 設(shè)計(jì)的人,而不是任何Carbon 編程終端用戶。
- [Building on Windows](https://github.com/carbon-language/carbon-lang/issues/298)
- [Carbon on Windows WSL](https://cristianopizzamiglio.com/2022/08/14/carbon-wsl.html)
- [C++ Standard Libraries](https://docs.brew.sh/C++-Standard-Libraries)
- [So I tried Carbon... Aryan Garg](https://aryan401.hashnode.dev/carbon)
注意安裝基礎(chǔ)編譯工具套件或 clang 編譯器,Brew 需要用它來(lái)編譯 glibc 等基礎(chǔ)庫(kù):
GCC 10.9 開(kāi)始基礎(chǔ)運(yùn)行庫(kù)命名為 libc++,早期的版本則默認(rèn)為 libstdc,可以按需要安裝指定版本。
? ? brew install gcc@7
? ? brew install --cc=gcc-7 <formula>
最后編譯時(shí)通過(guò)了,也生成了 explorer,但是執(zhí)行時(shí),未能通過(guò) Sanizer 內(nèi)存安全檢查:
# https://github.com/carbon-language/carbon-lang/issues/2236
總之,安裝過(guò)程非常不順利,還是官方說(shuō)的那樣,如果可以使用 Rust,那就不必考慮 Carbon!

這個(gè)項(xiàng)目由谷歌內(nèi)部 C++ 和開(kāi)發(fā)工具組開(kāi)啟,因?yàn)?C++ 標(biāo)準(zhǔn)委員會(huì)無(wú)法在 C++ ABI 上達(dá)成共識(shí)。目標(biāo)是不用重寫(xiě)谷歌內(nèi)部巨大的 C++ 代碼,同時(shí)逐步提高安全和執(zhí)行效率。資源上,最多是主管級(jí)的支持。大公司里一個(gè)小組放出一個(gè)天馬行空的開(kāi)源項(xiàng)目很常見(jiàn),Google 開(kāi)源玩具 demo 也是老傳統(tǒng)。
演化論有個(gè)“生態(tài)位”的概念,即在一個(gè)穩(wěn)定的環(huán)境下,一個(gè)生態(tài)位一旦被先來(lái)者搶占,那后來(lái)者是沒(méi)有機(jī)會(huì)的,這個(gè)先來(lái)者就會(huì)一直占著這個(gè)生態(tài)位,直到環(huán)境發(fā)生變化。而軟件工業(yè)中的 C++ 就是這樣的一個(gè)地位。
自操作系統(tǒng)誕生以來(lái),編寫(xiě)內(nèi)存安全的代碼一直是一個(gè)比較困難的問(wèn)題,另一個(gè)問(wèn)題則是保證線程安全。2004 年以來(lái),微軟安全響應(yīng)中心(MSRC)已對(duì)所有報(bào)告過(guò)的微軟安全漏洞進(jìn)行了分類,據(jù)統(tǒng)計(jì)數(shù)據(jù),所有微軟年度補(bǔ)丁中約有 70% 是針對(duì)內(nèi)存安全漏洞的修復(fù)程序。
- https://github.com/google/sanitizers
- https://gcc.gnu.org/onlinedocs/gcc-11.3.0/gcc/Option-Index.html
- https://developers.redhat.com/blog/2021/05/05/memory-error-checking-in-c-and-c-comparing-sanitizers-and-valgrind
- [Definitions and One Definition Rule (ODR)](https://en.cppreference.com/w/cpp/language/definition)
- [Constraints and concepts (since C++20)](https://en.cppreference.com/w/cpp/language/constraints)
- [C++ compiler support](https://en.cppreference.com/w/cpp/compiler_support)
Sanitizers 是谷歌發(fā)起的開(kāi)源內(nèi)存安全檢查工具,項(xiàng)目本是 LLVM 項(xiàng)目的一部分,GNU GCC 編譯器也集成了。GCC 4.8 版本開(kāi)始支持地址、線程 Sanitizer,GCC 4.9 版本開(kāi)始支持 Leak Sanitizer 和 UB Sanitizer,這些都是查找隱藏 Bug 的利器。通過(guò)編譯器參數(shù)啟用,如 -fsanitize=address 使用地址檢查器。
- AddressSanitizer 檢查地址相關(guān)問(wèn)題,包括釋放后使用、重復(fù)釋放、堆溢出、棧溢出等等問(wèn)題。
- LeakSanitizer 檢查內(nèi)存泄漏問(wèn)題。
- ThreadSanitizer 檢查線程數(shù)據(jù)競(jìng)爭(zhēng)和死鎖問(wèn)題。
- MemorySanitizer 檢查使用未初始化內(nèi)存問(wèn)題。
- Undefied Behavior Sanitizer 未定義行為問(wèn)題。
Address Sanitize 支持功能:
01. Use after free (dangling pointer dereference)? 使用懸浮指針
02. Heap buffer overflow? ? 堆緩沖區(qū)溢出
03. Stack buffer overflow? ?棧緩沖區(qū)溢出
04. Global buffer overflow? 全局緩沖區(qū)溢出
05. Use after return? ? ? ? 通過(guò)返回值訪問(wèn)局部變量的內(nèi)存
06. Use after scope? ? ? ? ?訪問(wèn)已經(jīng)釋放的局部變量的內(nèi)存
07. Initialization order bugs? ?使用未初始化的內(nèi)存
08. Memory leaks? ? ? ? ? ? 內(nèi)存泄漏
C++20 是有史以來(lái)最大的 C++ 版本更新,但是不知什么原因它又沒(méi)有完全完工,是疫情版完成了后續(xù)的工作,C++23 “Pandemic Edition” is complete。要使用最新的功能,需要 GCC 或 CLang 13 這樣的版本。
C++20 引入了一個(gè)新概念,真的是概念,它的名字就叫 `concept`,其實(shí)是一個(gè)語(yǔ)法糖,它的本質(zhì)可以認(rèn)為是一個(gè)模板類型的 bool 變量。
? ? template < template-parameter-list >
? ? concept? concept-name = constraint-expression;
其中,constraint-expression 是一個(gè)可以被 eval 為 bool 的表達(dá)式或者編譯期函數(shù)。使用定義好的 concept 時(shí),constraint-expression 會(huì)根據(jù)上面 template-parameter-list 傳入的類型,執(zhí)行編譯期計(jì)算,判斷使用該concept的模板定義是否滿足。 如果不滿足,則編譯期會(huì)給定一個(gè)具有明確語(yǔ)義的錯(cuò)誤,即這個(gè) concept 沒(méi)有匹配成功。 注意到,上述匹配的行為都是在編譯期完成的,因此 concept 是 zero-cost 表達(dá)式。
Multiple declarations, Only one definition。
對(duì)于編譯器來(lái)說(shuō),任何一個(gè)翻譯單元中,只允許對(duì)任何變量、函數(shù)、類類型、枚舉類型、`concept` 或模板進(jìn)行一個(gè)定義。其中一些可能有多個(gè)聲明,但是定義只允許一個(gè),這就是 ODR 單一定義規(guī)則。
在整個(gè)程序中,包括標(biāo)準(zhǔn)庫(kù)和用戶定義庫(kù),ODR 規(guī)則使用的 non-inline 函數(shù)或變量只需要出現(xiàn)一個(gè)定義。編譯器不需要診斷這種違反,但違反它的程序的行為是未定義的,即 ODR Violation。
遵循 ODR 是構(gòu)建良好 C++ 程序的基礎(chǔ)。編寫(xiě) C++ 程序時(shí),代碼寫(xiě)在文件中,然而對(duì)于 ODR 原則來(lái)說(shuō),文件之間的邊界并不很重要,真正重要的是編譯單元,Translation Units。本質(zhì)上來(lái)說(shuō),一個(gè)編譯單元是對(duì)程序員提交給編譯器的文件執(zhí)行預(yù)處理后的結(jié)果,即一個(gè)源文件經(jīng)過(guò)預(yù)處理后,產(chǎn)生一個(gè)目標(biāo)文件。參考 C++ template:the complete guide。
預(yù)處理器按照條件編譯命令,#if,#ifdef 等等,去除掉未被選中的代碼塊,去除注釋,遞歸地插入 "#include" 指令所引用的文件,并將宏展開(kāi)。
Valgrind 可以檢測(cè)非常多的內(nèi)存錯(cuò)誤,但相對(duì)于 Sanitizer,對(duì)程序性能影響更大。
以下測(cè)試程序一般編譯通過(guò)并正常運(yùn)行,但是使用內(nèi)存檢查工具后,就可以發(fā)現(xiàn)潛在的越界問(wèn)題: