国产av一二三区|日本不卡动作网站|黄色天天久久影片|99草成人免费在线视频|AV三级片成人电影在线|成年人aV不卡免费播放|日韩无码成人一级片视频|人人看人人玩开心色AV|人妻系列在线观看|亚洲av无码一区二区三区在线播放

網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

AI原生語(yǔ)言MoonBit遇上靜態(tài)分析,迸發(fā)高性能、資源受限場(chǎng)景下的獨(dú)特潛力

0
分享至


本文作者:東燈

原標(biāo)題:用 MoonBit 做靜態(tài)分析:從分析簡(jiǎn)單語(yǔ)言到 MCIL

一、前言

你是否曾在編寫(xiě)代碼時(shí),對(duì)那些能未卜先知的工具感到好奇?當(dāng)C/C++編譯器警告你“變量可能未初始化”,或TypeScript的IDE提示某個(gè)對(duì)象“可能為空”,它們并不是運(yùn)行了你的程序,而僅僅是“掃描”了你的源代碼,就精準(zhǔn)地預(yù)見(jiàn)到了潛在的運(yùn)行時(shí)風(fēng)險(xiǎn)。這背后隱藏的,正是編程世界中一項(xiàng)強(qiáng)大而優(yōu)雅的技術(shù)——靜態(tài)分析。

然而,對(duì)于大多數(shù)應(yīng)用程序開(kāi)發(fā)者而言,編譯器和靜態(tài)分析工具的運(yùn)作原理仿佛一個(gè)神秘的黑匣子。我們受益于它們,卻不一定理解其內(nèi)在的設(shè)計(jì)邏輯與通用模式。

本文旨在為你揭開(kāi)這層神秘面紗。無(wú)論你是會(huì)寫(xiě)普通應(yīng)用程序的程序員,還是對(duì)程序底層原理感興趣的探索者,我們都將一同踏上旅程,從零開(kāi)始理解:為什么看似正確的代碼會(huì)被分析工具“挑刺”?這些工具是如何從繁雜的語(yǔ)法結(jié)構(gòu)中提取出可分析的邏輯的?更重要的是,它們?yōu)槭裁炊疾捎昧祟?lèi)似的設(shè)計(jì)哲學(xué)?

我們將以MCIL(MoonBit C Intermediate Language) 這一成熟的分析框架作為最終案例,展示MoonBit這一新興的AI原生編程語(yǔ)言,如何優(yōu)雅地用于C語(yǔ)言的靜態(tài)分析工作,探究它在高性能、資源受限場(chǎng)景下的獨(dú)特潛力。

跟隨本文的指引,你不僅將掌握靜態(tài)分析的核心思想,更能理解其設(shè)計(jì)與實(shí)現(xiàn)的普適性規(guī)律。讓我們一同探索,如何讓機(jī)器“看懂”代碼的意圖,并提前發(fā)現(xiàn)那些隱藏的缺陷。

二、我們要做什么

讓我先展示最終的效果。假設(shè)有這樣一段代碼:


    
      
      
      var x
var y = input()
if y > 0 {
x = y + 1
}
return x


這是一門(mén)我們自己設(shè)計(jì)的簡(jiǎn)單語(yǔ)言。它支持變量聲明、賦值、if 條件語(yǔ)句、while 循環(huán)和 return 語(yǔ)句,而且所有塊都在函數(shù)作用域中,沒(méi)有塊級(jí)作用域。

這段代碼有一個(gè) bug:變量 x 只在 if 的 then 分支里被賦值了,else 分支是空的。如果 y <= 0,程序會(huì)走 else 分支,這時(shí)候 x 從來(lái)沒(méi)有被賦值,但 return x 卻要使用它的值。這就是“使用未初始化變量”的錯(cuò)誤,但是因?yàn)樵诰幾g器的層面,這段代碼在邏輯上/類(lèi)型上是正確的。

我們要寫(xiě)的靜態(tài)分析器能夠自動(dòng)檢測(cè)這種問(wèn)題。更重要的是,我們會(huì)理解為什么靜態(tài)分析器要這樣設(shè)計(jì),以及這種設(shè)計(jì)如何讓分析變得既簡(jiǎn)單又強(qiáng)大。

三、從源碼到 AST:詞法分析與語(yǔ)法分析

在開(kāi)始靜態(tài)分析之前,我們需要先把源代碼變成結(jié)構(gòu)化的數(shù)據(jù)。這個(gè)過(guò)程分兩步:詞法分析和語(yǔ)法分析。

  • 詞法分析器(Lexer)把字符流變成 Token 流。比如 var x = 0 會(huì)被識(shí)別成四個(gè) Token:關(guān)鍵字 Var、標(biāo)識(shí)符 Ident("x")、賦值符號(hào) Eq、整數(shù) IntLit(0)。詞法分析器從頭到尾掃描字符,跳過(guò)空白和注釋?zhuān)鶕?jù)當(dāng)前字符決定生成什么類(lèi)型的 Token。

  • 語(yǔ)法分析器(Parser把 Token 流變成抽象語(yǔ)法樹(shù)(AST)。AST 是程序的樹(shù)形表示,體現(xiàn)了代碼的層次結(jié)構(gòu)。我們使用遞歸下降的方法:為每種語(yǔ)法成分寫(xiě)一個(gè)解析函數(shù),函數(shù)之間相互調(diào)用。處理運(yùn)算符優(yōu)先級(jí)時(shí),為每個(gè)優(yōu)先級(jí)層寫(xiě)一個(gè)函數(shù),低優(yōu)先級(jí)的函數(shù)調(diào)用高優(yōu)先級(jí)的函數(shù)。

我們的 AST 定義如下:


    
      
      
      // 表達(dá)式
enum Expr {
Int(Int) // 整數(shù): 0, 42
Var(String) // 變量: x, y
BinOp(BinOp, Expr, Expr) // 二元運(yùn)算: x + 1
Call(String, Array[Expr]) // 函數(shù)調(diào)用: input()
Not(Expr) // 邏輯非: !x
}


// 語(yǔ)句
enum Stmt {
VarDecl(String, Expr?) // 變量聲明: var x 或 var x = 0
Assign(String, Expr) // 賦值: x = 1
If(Expr, Array[Stmt], Array[Stmt]) // if-else
While(Expr, Array[Stmt]) // while 循環(huán)
Return(Expr) // 返回
}


我們之前的代碼就會(huì)被這樣解析為 AST:


完整的 Lexer/Parser 代碼我們將會(huì)在文章結(jié)尾的倉(cāng)庫(kù)鏈接中提供,大約 400 行。這部分不是本文的重點(diǎn)——我們關(guān)心的是拿到 AST 之后怎么做分析。

四、編譯器與靜態(tài)分析器的關(guān)系

繼續(xù)之前,讓我們先看一下整體的圖景。傳統(tǒng)編譯器和靜態(tài)分析器走的是兩條不同的路,但它們有共同的起點(diǎn):


編譯器和靜態(tài)分析器共享從源代碼到 IR 的前半段流程。區(qū)別在于 IR 之后:編譯器繼續(xù)往下走,最終生成可執(zhí)行文件;靜態(tài)分析器則“切斷”了這條路,轉(zhuǎn)而去分析 IR 本身,輸出的是警告和錯(cuò)誤報(bào)告,而不是機(jī)器碼。

兩者共享同一個(gè)洞察:直接在 AST 上工作很困難,轉(zhuǎn)換成 IR 之后會(huì)容易很多這就是為什么 CIL(C Intermediate Language)這類(lèi)框架存在——它們提供一種“分析友好”的中間表示,保留了源語(yǔ)言的語(yǔ)義,但結(jié)構(gòu)上更容易分析。

1、為什么不能直接在 AST 上做分析?

直接在 AST 上做靜態(tài)分析在理論上是可行的,但在實(shí)踐中會(huì)極其痛苦。原因并不在于分析目標(biāo)本身復(fù)雜,而在于 AST 將控制流隱含在語(yǔ)法結(jié)構(gòu)之中:if、while、break、continue、提前 return 等都會(huì)迫使分析代碼顯式模擬控制流的所有可能執(zhí)行路徑,并引入不動(dòng)點(diǎn)迭代、路徑合并等邏輯。結(jié)果是,分析器的復(fù)雜度迅速被語(yǔ)法細(xì)節(jié)主導(dǎo),而不是由分析問(wèn)題本身決定。更糟的是,這種寫(xiě)法幾乎無(wú)法復(fù)用:即使“未初始化變量分析”和“空指針?lè)治觥痹诔橄笊隙际峭活?lèi)數(shù)據(jù)流分析,它們?cè)?AST 上的實(shí)現(xiàn)卻必須重復(fù)編寫(xiě)幾乎相同的控制流處理代碼。因此,直接在 AST 上遞歸分析往往導(dǎo)致代碼臃腫、易錯(cuò)、不可擴(kuò)展,也缺乏統(tǒng)一的抽象層次。

五、 CIL 的核心思想:把控制流“拍平”

CIL(C Intermediate Language)是加州大學(xué)伯克利分校開(kāi)發(fā)的一個(gè) C 程序分析框架。它的核心思想很簡(jiǎn)單但很強(qiáng)大:不要在 AST 上做分析,而是先把 AST 轉(zhuǎn)換成一種更適合分析的中間表示(IR)。

這個(gè) IR 有兩個(gè)關(guān)鍵特征:


1、用“ 基本塊 ”取代嵌套的控制結(jié)構(gòu)

基本塊是一段順序執(zhí)行的代碼,中間沒(méi)有分支,也沒(méi)有跳轉(zhuǎn)目標(biāo)。換句話說(shuō),如果你開(kāi)始執(zhí)行一個(gè)基本塊的第一條指令,你一定會(huì)順序執(zhí)行到最后一條指令,不會(huì)中途跳走,也不會(huì)有別的地方跳進(jìn)來(lái)。

基本塊之間用顯式的跳轉(zhuǎn)連接。比如:


    
      
      
      if cond {       ──?    Block0: if cond goto Block1 else Block2
A Block1: A; goto Block3
} else { Block2: B; goto Block3
B Block3: ...
}


while cond { ──? Block0: goto Block1
A Block1: if cond goto Block2 else Block3
} Block2: A; goto Block1 ← 向后跳轉(zhuǎn)
Block3: ...


if 變成條件跳轉(zhuǎn),while 變成一個(gè)循環(huán)——Block2 執(zhí)行完后跳回 Block1 重新檢查條件。

2、用“三地址碼”取代復(fù)雜的表達(dá)式

三地址碼是一種簡(jiǎn)化的指令格式,每條指令最多涉及三個(gè)“地址”(變量)。比如 x = y + z * w 這樣的復(fù)合表達(dá)式,會(huì)被拆成:


    
      
      
      t1 = z * w

t2 = y + t1

x = t2


其中 t1、t2 是編譯器生成的臨時(shí)變量。

在代碼中,我們這樣定義 IR:

              // 指令:三地址碼格式
enum Instr {
BinOp(Operand, BinOp, Operand, Operand) // dest = left op right
Copy(Operand, Operand) // dest = src
Call(Operand, String, Array[Operand]) // dest = func(args...)
}

// 終結(jié)指令:基本塊的出口
enum Terminator {
CondBr(Operand, Int, Int) // if cond goto block1 else block2
Goto(Int) // goto block
Return(Operand) // return value
}

// 基本塊
struct Block {
id : Int
instrs : Array[Instr] // 塊內(nèi)的指令序列
term : Terminator // 終結(jié)指令
preds : Array[Int] // 前驅(qū)塊
succs : Array[Int] // 后繼塊
}

讓我們看看之前的例子轉(zhuǎn)換成 IR 之后長(zhǎng)什么樣:


現(xiàn)在控制流的結(jié)構(gòu)一目了然。Block 0 是入口,執(zhí)行完之后根據(jù)條件跳到 Block 1 或 Block 2。Block 1 和 Block 2 最后都跳到 Block 3,Block 3 返回。

這種結(jié)構(gòu)有一個(gè)專(zhuān)門(mén)的名字:控制流圖Control Flow Graph,CFG。圖的節(jié)點(diǎn)是基本塊,邊是跳轉(zhuǎn)關(guān)系。我們可以畫(huà)出來(lái):


六、數(shù)據(jù)流分析:在 CFG 上“流動(dòng)”信息

有了 CFG,我們就可以用一種非常優(yōu)雅的方式來(lái)做分析:讓信息在圖上“流動(dòng)”。

以“未初始化變量檢測(cè)”為例。我們想知道:在程序的每個(gè)點(diǎn),哪些變量已經(jīng)被定義過(guò)了?

我們可以這樣在 CFG 上進(jìn)行思考:

  • 在程序入口(Block 0 的開(kāi)頭),只有函數(shù)參數(shù)是“已定義”的,局部變量都是“未定義”的。

  • 每條賦值語(yǔ)句會(huì)“產(chǎn)生”一個(gè)定義。比如 x = 0 之后,x 就變成“已定義”了。

  • 每條賦值語(yǔ)句也會(huì)“殺死”之前的定義。比如 x = 1 會(huì)讓之前 x = 0 的定義失效。

  • 在控制流的匯合點(diǎn)(比如 Block 3 的開(kāi)頭),信息需要“合并”。Block 3 可能從 Block 1 到達(dá),也可能從 Block 2 到達(dá)。如果一個(gè)變量在 Block 1 結(jié)尾是“已定義”的,但在 Block 2 結(jié)尾是“未定義”的,那么在 Block 3 開(kāi)頭它就是“可能未定義”的。

這就是數(shù)據(jù)流分析的基本思路。我們給每個(gè)基本塊的入口和出口關(guān)聯(lián)一個(gè)“狀態(tài)”(在這個(gè)例子里,狀態(tài)是“哪些變量已定義”的集合),然后定義:

1. 傳遞函數(shù)給定一個(gè)塊的入口狀態(tài),如何計(jì)算出口狀態(tài)?就是模擬塊內(nèi)每條指令的效果。

2. 合并函數(shù)當(dāng)多條邊匯合到一個(gè)點(diǎn)時(shí),如何合并多個(gè)狀態(tài)?比如取交集(“所有前驅(qū)都定義了才算定義”)或取并集(“任一前驅(qū)定義了就算定義”)。

接下來(lái)我們從入口開(kāi)始,不斷迭代,直到所有塊的狀態(tài)不再變化(達(dá)到“不動(dòng)點(diǎn)”)。

這個(gè)過(guò)程可以用一個(gè)通用的算法框架來(lái)實(shí)現(xiàn):

  1. 把所有塊加入工作表

  2. 從工作表取出一個(gè)塊

  3. 根據(jù)前驅(qū)的狀態(tài)和合并函數(shù),計(jì)算這個(gè)塊的入口狀態(tài)

  4. 根據(jù)傳遞函數(shù),計(jì)算這個(gè)塊的出口狀態(tài)

  5. 如果出口狀態(tài)變了,把所有后繼加入工作表

  6. 重復(fù) 2-5,直到工作表為空

最后,我們可以把這個(gè)框架抽象成一個(gè)通用的函數(shù),用戶只需要提供傳遞函數(shù)和合并函數(shù):


    
      
      
      struct ForwardConfig[T] {
init : T // 入口的初始狀態(tài)
transfer : (Block, T) -> T // 傳遞函數(shù):入口狀態(tài) -> 出口狀態(tài)
merge : (T, T) -> T // 合并函數(shù):多個(gè)狀態(tài) -> 一個(gè)狀態(tài)
equal : (T, T) -> Bool // 判斷狀態(tài)是否相等(用于檢測(cè)不動(dòng)點(diǎn))
copy : (T) -> T // 復(fù)制狀態(tài)(避免共享引用)
}


fn forward_dataflow[T](fun_ir : FunIR, config : ForwardConfig[T]) -> Result[T] {
// 初始化每個(gè)塊的狀態(tài)
// 迭代直到不動(dòng)點(diǎn)
// ...
}


這個(gè)框架的美妙之處在于:不管你分析的是什么問(wèn)題(未初始化變量、空指針、整數(shù)溢出……),只要能定義傳遞函數(shù)和合并函數(shù),就能套用同一個(gè)框架,而不是手寫(xiě)多遍復(fù)雜的邏輯去適配很小的思維改動(dòng)。

七、前向分析 vs 后向分析

剛才說(shuō)的是“前向分析”(Forward Analysis):信息從程序入口向出口流動(dòng)。但有些分析天然是“后向”的(Backward Analysis)。

比如“活躍變量分析”(Liveness Analysis):我們想知道在程序的每個(gè)點(diǎn),哪些變量的值在之后還會(huì)被用到。這個(gè)問(wèn)題要從程序出口往回看。如果一個(gè)變量在某點(diǎn)之后不再被使用,那它就是“死”的,之前對(duì)它的賦值就是無(wú)用的(死代碼)。

后向分析和前向分析是對(duì)稱(chēng)的:信息從出口向入口流動(dòng),傳遞函數(shù)從“入口狀態(tài)→出口狀態(tài)”變成“出口狀態(tài)→入口狀態(tài)”,合并函數(shù)作用于后繼而不是前驅(qū)。


    
      
      
      struct BackwardConfig[T] {
init : T // 出口的初始狀態(tài)
transfer : (Block, T) -> T // 傳遞函數(shù):出口狀態(tài) -> 入口狀態(tài)
merge : (T, T) -> T // 合并后繼的狀態(tài)
equal : (T, T) -> Bool
copy : (T) -> T
}


活躍變量分析的傳遞函數(shù)這樣寫(xiě):


    
      
      
      fn liveness_transfer(block : Block, out_state : LiveSet) -> LiveSet {
let live = out_state.copy()
// 從后向前處理指令(因?yàn)槭呛笙蚍治觯?br/> for i = block.instrs.length() - 1; i >= 0; i = i - 1 {
let instr = block.instrs[i]
// 先移除這條指令定義的變量
match get_def(instr) { Some(v) => live.remove(v), None => () }
// 再加入這條指令使用的變量
for v in get_uses(instr) { live.add(v) }
}
live
}


為什么要“先移除定義,再加入使用”?我們不妨考慮 x = x + 1 這條指令。在這條指令之前,x 必須是活躍的(因?yàn)槲覀円x取它)。但在這條指令之后,x 的舊值就不需要了(因?yàn)槲覀儗?xiě)入了新值)。所以在后向分析中,我們要先處理定義(消除活躍性),再處理使用(產(chǎn)生活躍性)。

對(duì)于合并函數(shù),活躍變量分析使用并集:如果一個(gè)變量在任意一條出邊上是活躍的,它在當(dāng)前點(diǎn)就是活躍的。這是因?yàn)槌绦蚩赡茏呷我庖粭l分支,只要有可能被用到,變量就必須保持活躍。

八、檢測(cè)未初始化變量

現(xiàn)在讓我們來(lái)實(shí)現(xiàn)一個(gè)實(shí)用的分析:檢測(cè)可能未初始化的變量。

思路是這樣的:我們用“定值可達(dá)性分析”來(lái)跟蹤每個(gè)程序點(diǎn)可能到達(dá)的變量定義。如果在某個(gè)點(diǎn)使用了一個(gè)變量,但沒(méi)有任何定義能到達(dá)這個(gè)點(diǎn),那就是未初始化使用。

定值可達(dá)性分析是前向的。每條賦值語(yǔ)句產(chǎn)生一個(gè)新定義,同時(shí)殺死同一變量的舊定義。在匯合點(diǎn),多個(gè)分支的定義集合取并集(因?yàn)槿我庖粭l路徑的定義都可能到達(dá))。

有了定值可達(dá)性的信息,檢測(cè)就很直接了:

              for block in fun_ir.blocks {  let mut defs = reaching.defs_in[block.id]  for instr in block.instrs {    // 檢查使用的變量    for var in get_uses(instr) {      if not(defs.has_def(var)) && not(is_param(var)) {        warn("Variable may be uninitialized: " + var)      }    }    // 更新定義    match get_def(instr) {Some(var) => defs = defs.update(var, current_def)None=> ()    }  }}

讓我們?cè)谥暗睦由蠝y(cè)試一下:


    
      
      
      Warning: Variable may be uninitialized: x (at Block 3, Return)


太棒了!這就是我們想要的結(jié)果!

九、MCIL:真實(shí)的 C 語(yǔ)言分析

我們剛才教學(xué)使用的項(xiàng)目叫做 MiniCIL,是一個(gè)參考 CIL 項(xiàng)目編寫(xiě)的簡(jiǎn)易教學(xué)項(xiàng)目,它的 DSL 只有幾種簡(jiǎn)單的語(yǔ)句。真正的 C 語(yǔ)言要復(fù)雜得多。而我們編寫(xiě)了一個(gè)CIL 的完整 MoonBit 實(shí)現(xiàn):MCIL,它有能力處理完整的 C 語(yǔ)言,做非常復(fù)雜的靜態(tài)分析工作。

MCIL 和 MiniCIL 的架構(gòu)是一樣的:


    
      
      
      C 源代碼 → Lexer/Parser → AST → cabs2cil → CIL IR → 分析


MCIL 的 Lexer 要處理 C 語(yǔ)言的所有 Token:sizeoftypedef、struct、-> 等等。Parser 要處理 C 語(yǔ)言的完整語(yǔ)法:函數(shù)指針、復(fù)合字面量、designated initializer、GCC 擴(kuò)展等等。cabs2cil 轉(zhuǎn)換要處理類(lèi)型推導(dǎo)、隱式轉(zhuǎn)換、常量折疊、作用域解析等等。

但是它們核心的分析框架和思想是相通的,理解了 MiniCIL,讀 MCIL 的代碼就會(huì)容易很多。

下面是一個(gè) MCIL 做 C 語(yǔ)言的一些簡(jiǎn)單靜態(tài)分析的實(shí)例:


1、C 語(yǔ)言分析會(huì)遇到的困難

如果有對(duì) MCIL 感興趣的讀者,下面這幾條 C 語(yǔ)言靜態(tài)分析會(huì)遇到的主要困難對(duì)你非常重要:

  1. 指針和別名:我們剛才的 DSL 只有簡(jiǎn)單變量,但 C 語(yǔ)言有指針。當(dāng)你寫(xiě) *p = 1的時(shí)候,你修改的是哪個(gè)變量?如果 p 可能指向 xy,這條語(yǔ)句就可能修改兩者中的任何一個(gè)。更糟糕的是,pq 可能指向同一塊內(nèi)存(別名),修改 *p 會(huì)影響 *q 的值。跟蹤指針的指向關(guān)系叫做別名分析,是靜態(tài)分析中最困難的問(wèn)題之一。

  2. 過(guò)程間分析:我們教學(xué)中的分析只看單個(gè)函數(shù)。但當(dāng)你調(diào)用 foo(x) 的時(shí)候,foo 會(huì)修改 x 指向的內(nèi)存嗎?會(huì)釋放它嗎?如果只分析單個(gè)函數(shù),這些信息都丟失了。過(guò)程間分析要構(gòu)建調(diào)用圖,跟蹤函數(shù)之間的數(shù)據(jù)流。MCIL 實(shí)現(xiàn)了簡(jiǎn)單的過(guò)程間分析,可以檢測(cè) free(p)后對(duì) p 的使用。

  3. 復(fù)雜的類(lèi)型系統(tǒng):C 語(yǔ)言的類(lèi)型系統(tǒng)充滿陷阱:數(shù)組退化成指針、函數(shù)指針的復(fù)雜語(yǔ)法、struct 的內(nèi)存布局、union 的類(lèi)型雙關(guān)等等。MCIL 的 cabs2cil 轉(zhuǎn)換會(huì)處理這些,把它們規(guī)范化成統(tǒng)一的形式。比如,所有隱式類(lèi)型轉(zhuǎn)換都變成顯式的 CastE,數(shù)組到指針的轉(zhuǎn)換通過(guò) StartOf 表達(dá)。

  4. C 語(yǔ)言的未定義行為:有符號(hào)整數(shù)溢出、空指針解引用、越界訪問(wèn)、use-after-free……C 標(biāo)準(zhǔn)把這些都定義為“未定義行為”(UB),編譯器可以假設(shè)它們不會(huì)發(fā)生。靜態(tài)分析工具要檢測(cè)這些問(wèn)題,但又不能太保守導(dǎo)致誤報(bào)(因?yàn)橛行┻壿嬁赡芷褪怯眠@種 UB 實(shí)現(xiàn)得快)。


十、總結(jié)

在這篇文章中,我們學(xué)習(xí)了靜態(tài)分析的基本流程:從源代碼經(jīng)過(guò)詞法分析、語(yǔ)法分析得到 AST,再轉(zhuǎn)換成基本塊和顯式跳轉(zhuǎn)構(gòu)成的 CFG,最后用數(shù)據(jù)流分析框架在 CFG 上迭代直到不動(dòng)點(diǎn)。我們實(shí)現(xiàn)了活躍變量分析和未初始化變量檢測(cè)作為例子,展示了該靜態(tài)分析思想的通用性。

另外 CIL 其實(shí)已經(jīng)是 200x 年代的產(chǎn)物了,在 2002 年《CIL: Intermediate Language and Tools for Analysis and Transformation of C Programs》中第一次發(fā)表后,工具逐步成熟并公開(kāi)發(fā)布,并開(kāi)始被逐漸被應(yīng)用于各種工業(yè)項(xiàng)目中,它相對(duì)精簡(jiǎn),到現(xiàn)在仍然是學(xué)習(xí)靜態(tài)分析的優(yōu)秀例子。

不過(guò),隨著編譯器技術(shù)的發(fā)展,以 SSAStatic Single Assignment 形式為核心的 LLVM/Clang 編譯基礎(chǔ)設(shè)施逐漸成熟,并在工業(yè)界成為事實(shí)標(biāo)準(zhǔn),這類(lèi)框架在統(tǒng)一中間表示、跨階段優(yōu)化以及代碼生成方面展現(xiàn)出更強(qiáng)的通用性與擴(kuò)展性,因而在實(shí)際工程中逐步取代了以 CIL 為代表的、主要面向單語(yǔ)言靜態(tài)分析的中間表示工具。感興趣的讀者也可以自行拓展這方面內(nèi)容,學(xué)習(xí)更加現(xiàn)代,更加強(qiáng)大的靜態(tài)分析技術(shù)。

參考文獻(xiàn):

CIL 原論文:

《CIL: Intermediate Language and Tools for Analysis and Transformation of C Programs》

Mini MoonBit C Intermediate Language(教學(xué)使用的代碼):

https://github.com/Lampese/MiniCIL

MoonBit C Intermediate Language(MCIL):

https://github.com/Lampese/MCIL

特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點(diǎn)推薦
美媒:大陸攻臺(tái)時(shí)間確定,臺(tái)官員:要想臺(tái)灣回歸,必須滿足三條件

美媒:大陸攻臺(tái)時(shí)間確定,臺(tái)官員:要想臺(tái)灣回歸,必須滿足三條件

快看張同學(xué)
2026-02-27 17:13:59
湖南一男子殺鴨從鴨肚中剖出多顆金色顆粒,灼燒鑒定為黃金,當(dāng)事人:當(dāng)?shù)睾拥涝山?,可能是鴨子覓食時(shí)誤食

湖南一男子殺鴨從鴨肚中剖出多顆金色顆粒,灼燒鑒定為黃金,當(dāng)事人:當(dāng)?shù)睾拥涝山穑赡苁区喿右捠硶r(shí)誤食

揚(yáng)子晚報(bào)
2026-02-27 07:34:01
突然被扣費(fèi),連續(xù)數(shù)月不知情! 上海已有多人遭遇! 快查, 你的錢(qián)有沒(méi)有"消失"?

突然被扣費(fèi),連續(xù)數(shù)月不知情! 上海已有多人遭遇! 快查, 你的錢(qián)有沒(méi)有"消失"?

新浪財(cái)經(jīng)
2026-02-27 17:11:04
差點(diǎn)上演“麥迪時(shí)刻”,穆雷26中12砍39分&最后時(shí)刻連飆三分

差點(diǎn)上演“麥迪時(shí)刻”,穆雷26中12砍39分&最后時(shí)刻連飆三分

懂球帝
2026-02-28 13:58:08
WTT新加坡大滿貫:男單4強(qiáng)已出其2!王楚欽零封名將,約戰(zhàn)勒布倫

WTT新加坡大滿貫:男單4強(qiáng)已出其2!王楚欽零封名將,約戰(zhàn)勒布倫

全言作品
2026-02-28 16:06:17
執(zhí)教勝率72.5%!超禪師、科爾高居歷史第一,實(shí)力不輸斯波被低估

執(zhí)教勝率72.5%!超禪師、科爾高居歷史第一,實(shí)力不輸斯波被低估

你的籃球頻道
2026-02-28 14:03:39
知名脫口秀演員因發(fā)布挑動(dòng)性別對(duì)立、制造婚育焦慮信息被禁言

知名脫口秀演員因發(fā)布挑動(dòng)性別對(duì)立、制造婚育焦慮信息被禁言

大象新聞
2026-02-27 20:37:03
汪小菲吐槽小汪寶心眼太多,回應(yīng)玥箖上學(xué)問(wèn)題,筱梅或成了導(dǎo)火索

汪小菲吐槽小汪寶心眼太多,回應(yīng)玥箖上學(xué)問(wèn)題,筱梅或成了導(dǎo)火索

查爾菲的筆記
2026-02-28 13:39:27
臺(tái)北媒體放話:中國(guó)臺(tái)北男籃有信心戰(zhàn)勝中國(guó)男籃,關(guān)鍵戰(zhàn)一觸即發(fā)

臺(tái)北媒體放話:中國(guó)臺(tái)北男籃有信心戰(zhàn)勝中國(guó)男籃,關(guān)鍵戰(zhàn)一觸即發(fā)

籃球看比賽
2026-02-28 16:58:44
痛心!江西跑友劉濤去世,僅51歲,生前堅(jiān)持晨跑,是3家公司老板

痛心!江西跑友劉濤去世,僅51歲,生前堅(jiān)持晨跑,是3家公司老板

離離言幾許
2026-02-25 10:43:45
春節(jié)前將牛肉飯忘在辦公室!節(jié)后牛肉飯長(zhǎng)出15厘米高“黑色叢林”!

春節(jié)前將牛肉飯忘在辦公室!節(jié)后牛肉飯長(zhǎng)出15厘米高“黑色叢林”!

天津人
2026-02-28 07:09:58
中方正式宣布:更換國(guó)內(nèi)供應(yīng)商,從此不再合作!荷蘭后悔也沒(méi)用了

中方正式宣布:更換國(guó)內(nèi)供應(yīng)商,從此不再合作!荷蘭后悔也沒(méi)用了

林子說(shuō)事
2026-02-28 14:29:57
樊振東落選!世界杯名單公布,王勵(lì)勤說(shuō)到做到,溫瑞博成最大黑馬

樊振東落選!世界杯名單公布,王勵(lì)勤說(shuō)到做到,溫瑞博成最大黑馬

體育就你秀
2026-02-28 12:34:51
中國(guó)駐符拉迪沃斯托克總領(lǐng)館:18-65歲在俄長(zhǎng)期居留男性 須同意在俄軍事單位等至少服役1年

中國(guó)駐符拉迪沃斯托克總領(lǐng)館:18-65歲在俄長(zhǎng)期居留男性 須同意在俄軍事單位等至少服役1年

閃電新聞
2026-02-26 12:56:09
為了掏空老百姓的口袋、故意捏造出來(lái)的5大騙局,早知道早好

為了掏空老百姓的口袋、故意捏造出來(lái)的5大騙局,早知道早好

貓叔東山再起
2026-02-28 10:00:03
李奇微晚年在回憶錄里寫(xiě)道:一場(chǎng)朝鮮戰(zhàn)爭(zhēng),打出了三個(gè)超級(jí)大國(guó)

李奇微晚年在回憶錄里寫(xiě)道:一場(chǎng)朝鮮戰(zhàn)爭(zhēng),打出了三個(gè)超級(jí)大國(guó)

飯小妹說(shuō)歷史
2026-02-27 14:32:55
博士讀著讀著導(dǎo)師變后媽?zhuān)厴I(yè)還延期了…還有更離譜的嗎?

博士讀著讀著導(dǎo)師變后媽?zhuān)厴I(yè)還延期了…還有更離譜的嗎?

超級(jí)數(shù)學(xué)建模
2026-02-22 22:38:39
殯儀館工作人員紅衣、黃發(fā)主持九旬老人告別儀式,館方致歉并承諾整改

殯儀館工作人員紅衣、黃發(fā)主持九旬老人告別儀式,館方致歉并承諾整改

極目新聞
2026-02-27 21:17:24
臉在江山在?事實(shí)證明,失去黃曉明的楊穎,又回到了她的“怪圈”

臉在江山在?事實(shí)證明,失去黃曉明的楊穎,又回到了她的“怪圈”

觀察鑒娛
2026-02-28 10:07:44
俄羅斯警告中國(guó):美打伊朗是個(gè)陰謀,就是想要逼解放軍進(jìn)行決戰(zhàn)

俄羅斯警告中國(guó):美打伊朗是個(gè)陰謀,就是想要逼解放軍進(jìn)行決戰(zhàn)

健身狂人
2026-02-28 16:33:55
2026-02-28 18:04:50
開(kāi)源中國(guó) incentive-icons
開(kāi)源中國(guó)
每天為開(kāi)發(fā)者推送最新技術(shù)資訊
7604文章數(shù) 34503關(guān)注度
往期回顧 全部

科技要聞

狂攬1100億美元!OpenAI再創(chuàng)融資神話

頭條要聞

美以襲擊伊朗 華人緊急逃離德黑蘭:沒(méi)想到來(lái)得這么快

頭條要聞

美以襲擊伊朗 華人緊急逃離德黑蘭:沒(méi)想到來(lái)得這么快

體育要聞

球隊(duì)主力全報(bào)銷(xiāo)?頂風(fēng)擺爛演都不演了

娛樂(lè)要聞

疑似王一博被爆私密聊天記錄

財(cái)經(jīng)要聞

沈明高提共富建議 百姓持科技股國(guó)家兜底

汽車(chē)要聞

嵐圖泰山黑武士版3月上市 搭載華為四激光智駕方案

態(tài)度原創(chuàng)

時(shí)尚
旅游
親子
數(shù)碼
公開(kāi)課

被章若楠、秦嵐帶火的鞋子竟然是它?春天這樣穿又美又氣質(zhì)!

旅游要聞

2026年柳州龍王出游,即將登場(chǎng)!時(shí)間、路線定了!重要提醒→

親子要聞

12歲之前要瘋狂刺激前庭覺(jué),每天堅(jiān)持鍛煉,越玩越專(zhuān)注,越聰明!#兒童運(yùn)動(dòng) #身高管理 #感統(tǒng)訓(xùn)練 #...

數(shù)碼要聞

像素風(fēng)格主題設(shè)計(jì),微星推出PTT論壇PC_Shopping看板聯(lián)名主板

公開(kāi)課

李玫瑾:為什么性格比能力更重要?

無(wú)障礙瀏覽 進(jìn)入關(guān)懷版