中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

域名新聞網(wǎng)站種子資源

域名新聞網(wǎng)站,種子資源,唐河網(wǎng)站制作公司,浙江省住房和城鄉(xiāng)建設(shè)局網(wǎng)站簡介 近年來,越來越多的組織表示,如果新項(xiàng)目在技術(shù)選型時(shí)需要使用系統(tǒng)級開發(fā)語言,那么不要選擇使用C/C這種內(nèi)存不安全的系統(tǒng)語言,推薦使用內(nèi)存安全的Rust作為替代。 谷歌也聲稱,Android 的安全漏洞,從 20…

簡介

近年來,越來越多的組織表示,如果新項(xiàng)目在技術(shù)選型時(shí)需要使用系統(tǒng)級開發(fā)語言,那么不要選擇使用C/C++這種內(nèi)存不安全的系統(tǒng)語言,推薦使用內(nèi)存安全的Rust作為替代。

谷歌也聲稱,Android 的安全漏洞,從 2019 年的 223 個(gè)降低到 2022 年的 85 個(gè),經(jīng)過分析,谷歌認(rèn)為內(nèi)存漏洞減少的情況,主要與 Rust 代碼的比例增加有關(guān)。在 Android 13 中,就已經(jīng)有約 21%的新原生代碼以 Rust 開發(fā)。

微軟也宣布,Rust 將正式入駐 Windows 系統(tǒng)內(nèi)核;AWS在其基礎(chǔ)設(shè)施中越來越多地使用 Rust ;2022 年 12 月,Linux 內(nèi)核 6.1 發(fā)布,包括最初的 Rust 支持. . .

作為后來者,Rust是怎么做到內(nèi)存安全,且受到越來越多人的青睞呢?要知道,換做使用C/C++開發(fā),可能只有高級C/C++開發(fā)人員寫出的代碼才能如此穩(wěn)定,Rust是怎么保證任何一個(gè)使用它的人都能寫出內(nèi)存安全的代碼的呢?

下面,針對在C/C++中幾種常見的內(nèi)存安全問題為例,簡單分析下。


懸空指針

懸空指針主要是指,在C/C++中,某個(gè)對象已經(jīng)被釋放了,但是在某個(gè)角落還有一個(gè)指針指向這個(gè)對象,這個(gè)指針就是一個(gè)懸空指針。當(dāng)代碼運(yùn)行到這個(gè)地方,解引用這個(gè)懸空指針時(shí),就會(huì)出現(xiàn)未定義的行為

Rust解決這個(gè)問題的辦法就是Rust的精髓所在——生命周期。

int main()
{std::string *ptr = nullptr;{std::string = str;ptr = &str;}printf("%s", ptr->c_str());return 0;
}

上面是典型的C++中出現(xiàn)野指針的場景,這段代碼編譯器不會(huì)發(fā)出任何抱怨。

程序入口定義了一個(gè)std::string類型的指針ptr,并初始化為nullptr。進(jìn)入代碼塊后,在代碼塊中創(chuàng)建一個(gè)局部變量str,并且讓ptr指向這個(gè)局部變量。當(dāng)執(zhí)行流結(jié)束這個(gè)代碼塊后,棧上的變量str將會(huì)被釋放,但是此時(shí)指針ptr 還是指向這個(gè)局部變量str,代碼塊后續(xù)任何解引用指針ptr的地方都將是一個(gè)不可預(yù)期的行為。

我們用Rust實(shí)現(xiàn)一下這段代碼。

fn main()
{let str_ref;{let str_obj: String = String::new();str_ref = &str_obj;}println!("{str_ref }");
}

相同的邏輯,只是Rust中將指針改為了引用(引用就是一個(gè)指針)。當(dāng)執(zhí)行流結(jié)束代碼塊之后str_obj將會(huì)被釋放,但是此時(shí)str_ref 還指向這個(gè)局部變量。嘗試編譯一下。

在這里插入圖片描述

不出意外的,Rust的生命周期檢查器發(fā)現(xiàn)了這個(gè)問題,報(bào)錯(cuò)信息是borrowed value does not live long enough,他說str_obj的生命周期不夠長,引用str_ref在str_obj的生命結(jié)束后還在使用。

Rust在編譯時(shí)會(huì)嘗試為每個(gè)引用和被引用的對象分配一個(gè)生命周期,生命周期完全是Rust在編譯期虛構(gòu)的產(chǎn)物,在運(yùn)行期,引用就是一個(gè)地址,所以生命周期不會(huì)有任何運(yùn)行期開銷。有了生命周期,在編譯期,生命周期檢查器就會(huì)對比被引用對象和引用之間的生命周期關(guān)系,如下:

在這里插入圖片描述

黃色框表示str_obj的生命周期;引用str_ref 的生命周期是,str_ref 從初始化開始到str_ref 最后被使用的地方之間的代碼塊就是str_ref 的生命周期,所以這里白色方塊表示引用str_ref 的生命周期。生命周期檢查器準(zhǔn)則之一是,引用的最大生命周期不能超過被引用對象的生命周期,很明顯,這里違反了這條規(guī)則,所以無法通過編譯。

Rust解決野指針最重要的方法就是生命周期,這里只是介紹了最簡單的一個(gè)場景,在學(xué)習(xí)Rust時(shí),一定要理解生命周期的含義。


緩沖區(qū)溢出

在C++中,以vector為例,想要以索引的方式訪問某個(gè)對象時(shí),我們通常會(huì)使用vector的at方法進(jìn)行訪問,at方法會(huì)進(jìn)行數(shù)組越界檢測,這很安全。

但是vector可以通過data方法返回一個(gè)C/C++的原生數(shù)組,當(dāng)我們對原生數(shù)組進(jìn)行索引操作時(shí),完全是一種走鋼絲的行為。

因?yàn)闆]有任何越界檢測,此時(shí)如果發(fā)生緩沖區(qū)溢出,將會(huì)是一個(gè)未定義的行為。如果影響了其他變量,那么這將會(huì)是一個(gè)非常難排查的問題;如果改動(dòng)了不可寫的地址,那么會(huì)導(dǎo)致程序崩潰;如果運(yùn)氣好溢出的部分沒有影響到任何對象,那看起來將會(huì)是一切安好,但是我們并不總是有那么好的運(yùn)氣。

這種未定義的行為絕對不是我們想要的。來看看Rust是怎么做的。

fn main() {let vec: Vec<i32> = vec![1,2,3];let vec_ref: &[i32] = &vec[0 ..];for i in 0 .. 4 {println!("{}", vec_ref[i]);}

上面是在rust中創(chuàng)建了一個(gè)vector——vec,其長度為3(內(nèi)容為1、2、3),然后一個(gè)引用vec_ref(指針)指向這個(gè)vec。

緊接著使用引用vec_ref故意進(jìn)行了一次緩沖區(qū)溢出的輪詢操作, 此時(shí)我們能夠正常通過編譯。這當(dāng)然能夠編譯通過,千萬不要妄想Rust能夠在編譯期解決緩沖區(qū)溢出這種主要在運(yùn)行期出現(xiàn)的問題。

但是cargo run運(yùn)行時(shí)

在這里插入圖片描述

可以清楚的看到導(dǎo)致了panic,提示長度是3,但是index也是3,出現(xiàn)了緩沖區(qū)溢出的訪問。也就是說Rust對于緩沖區(qū)溢出的訪問會(huì)有一個(gè)已定義的行為——導(dǎo)致線程panic。但是新問題又來了,為什么一個(gè)引用(指針)vec_ref也有長度信息呢?

如果只是一個(gè)普通的引用當(dāng)然不會(huì)有長度信息,但是這里的引用vec_ref是對一個(gè)連續(xù)數(shù)據(jù)vec的引用。在Rust中,vec_ref準(zhǔn)確的說是一個(gè)切片。對一個(gè)連續(xù)數(shù)據(jù)的引用(切片),引用本身是一個(gè)胖指針,即該引用占兩個(gè)機(jī)器字(普通引用只是一個(gè)普通指針,內(nèi)存上只占用一個(gè)機(jī)器字)的內(nèi)存,第一個(gè)機(jī)器字是被引用的連續(xù)數(shù)據(jù)的首地址;第二個(gè)機(jī)器字是連續(xù)數(shù)據(jù)的長度。

下面是打印兩種引用占用內(nèi)存大小的代碼。

fn main() {let vec: Vec<i32> = vec![1,2,3];let vec_ref: &[i32] = &vec[0 ..];let num: i32 = 3;let num_ref: &i32 = &num;println!("vec_ref size_of:{} num_ref size_of:{}",std::mem::size_of_val(&vec_ref), std::mem::size_of_val(&num_ref))
}

輸出為vec_ref size_of:16 num_ref size_of:8。說明,引用(切片)vec_ref占用16Bytes,引用num_ref占用8Bytes,我的電腦是64位的電腦,剛好是兩個(gè)機(jī)器字和一個(gè)機(jī)器字。

除了切片之外,Rust中的原生數(shù)組也是帶有長度信息的,所以在使用原生數(shù)組出現(xiàn)緩沖區(qū)溢出時(shí),也會(huì)導(dǎo)致已定義的行為。

綜上,因?yàn)榫彌_區(qū)溢出主要是一個(gè)運(yùn)行期的行為,所以Rust也沒辦法做到在編譯期解決這個(gè)問題,但是通過胖指針的方式,Rust做到了在運(yùn)行期如果出現(xiàn)緩沖區(qū)溢出,那一定會(huì)有一個(gè)已定義的行為——線程panic。這肯定好過C/C++中緩沖區(qū)溢出后,各種未定義的奇葩問題。


對空指針進(jìn)行解引用

C/C++中對空指針解引用導(dǎo)致的崩潰問題更多的是開發(fā)人員個(gè)人編程習(xí)慣導(dǎo)致的。

在C/C++中,一個(gè)更好的編程習(xí)慣是在解引用指針之前,先對指針進(jìn)行判空操作,但是這樣簡單的一個(gè)判斷邏輯常常因?yàn)殚_發(fā)同學(xué)的“自信”,導(dǎo)致在很多地方偷懶忽略,然后直接對指針解引用后開始操作。往往越是自信不會(huì)為空的地方越是會(huì)給我們帶來最承重的打擊。

針對空指針解引用,首先Safe Rust中只有引用沒有指針,這里的引用和C++中的引用類似,本質(zhì)也是一個(gè)指針。Safe Rust中,在使用一個(gè)引用之前,必須對引用賦值,否則無法通過rustc的檢測。

fn main() {let s: String = String::new();let s_ref: &String = &s;
}

s是一個(gè)String類型的變量,s_ref是對s的一個(gè)引用。只有對s_ref賦值后才能對s_ref進(jìn)行使用。rustc通過強(qiáng)制檢測你的編碼實(shí)現(xiàn),杜絕了空指針的使用。

當(dāng)然,一定存在一個(gè)場景。某個(gè)引用,其需要引用的對象可能在程序運(yùn)行之初并沒有被創(chuàng)建,隨著程序的運(yùn)行才創(chuàng)建,創(chuàng)建后還需要讓這個(gè)引用指向這個(gè)剛創(chuàng)建的對象,也就是說需要Rust支持引用一開始為空,隨著程序的運(yùn)行才被賦值的情況。

上面這種場景下需要采用Option。Rust中,一切可能為空的東西都需要使用Option進(jìn)行包裹,不僅僅是引用。

fn main() {let mut s_ref_option: Option<&String> = None;let s: String = String::new();s_ref_option = Some(&s);
}

這一次s_ref_option因?yàn)榭赡転榭?#xff0c;所以被聲明為Option<&String>類型的None,語義為,有一個(gè)T&String類型的Option,這個(gè)Option目前包裹的值是None,但是后面可能會(huì)賦值,所以后續(xù)要想獲取s_ref_option中包裹的&String時(shí),你需要進(jìn)行檢查,因?yàn)椴淮_定后面會(huì)不會(huì)賦值。

緊接著,s才被創(chuàng)建,然后使用Some包裹后賦值給s_ref_option。

通過Option獲取其包裹的值通常有兩種做法,一種是安全的,一種是不安全的。安全的操作是在使用之前對Option進(jìn)行判空,顯而易見這很安全。

// 使用 s_ref_option 時(shí)判空
if let Some(v) = s_ref_option {//... v 是&String
}

但這在Rust中也不是強(qiáng)制的,開發(fā)人員也可以以一種不安全的方式使用Option——直接獲取Option中包裹的值。

// 不判空直接獲取Option中包裹的值
let s_ref: &String = s_ref_option.unwrap();

這和C/C++中直接進(jìn)行空指針解引用并沒有什么區(qū)別。

但是好在可以通過rustc中內(nèi)置的靜態(tài)代碼檢測工具clippy,對代碼進(jìn)行掃描,如果檢測到代碼中有使用unwrap,那么直接報(bào)error,clippy幫助檢查代碼中是否有這種危險(xiǎn)的使用。這可以理解為是Rust編程的一種規(guī)范,讓不寫unwrap作為Rust編程規(guī)范的一部分。

clippy中可以通過設(shè)置clippy::restriction集中的unwrap_used這條規(guī)范達(dá)到我們的目的,具體可以看我的另一篇博客 Rust代碼靜態(tài)分析工具Clippy淺析

綜上,Rust通過編譯器,強(qiáng)制檢測引用(指針)在使用之前必須賦值解決了這個(gè)問題。對于可能為空的對象,配合clippy使用,對于是否可以直接解引用可能為空的對象的選擇權(quán)留給開發(fā)者,也不為是一種比較好的方案。


非法釋放內(nèi)存

C/C++中存在非法釋放內(nèi)存的情況,比如double free、非法釋放棧上的內(nèi)存等等,這些操作都會(huì)導(dǎo)致程序的崩潰。

作為非GC系的語言,Rust也面臨釋放內(nèi)存資源的問題。但是當(dāng)你真正開始使用Safe Rust時(shí)會(huì)發(fā)現(xiàn),你基本不需要關(guān)心內(nèi)存的釋放,因?yàn)镽ust將C++中的精華RAII發(fā)揮到了極致。

對于需要進(jìn)行內(nèi)存管理的對象類型,其都會(huì)實(shí)現(xiàn)Drop 特型,定義如下:

pub trait Drop {// Required methodfn drop(&mut self);
}

實(shí)現(xiàn)該特型的類型,其實(shí)例在被釋放前都會(huì)調(diào)用這個(gè)方法,類型的實(shí)現(xiàn)者可以在drop中釋放自己管理的資源,這和C++中的析構(gòu)函數(shù)一樣。RAII在Rust中被大量采用,所以作為一個(gè)Rust的開發(fā)者,在Safe Rust中,你基本不需要再去進(jìn)行內(nèi)存管理。

總結(jié)

Rust作為一顆冉冉升起的新星,已經(jīng)得到了越來越多人的認(rèn)可,將其壓入你的技術(shù)棧,一定會(huì)是一個(gè)不錯(cuò)的選擇。


http://www.risenshineclean.com/news/3646.html

相關(guān)文章:

  • 鄭州做網(wǎng)站推國內(nèi)推廣平臺
  • 做seo網(wǎng)站地圖重要嗎寧波最好的推廣平臺
  • 京東商城網(wǎng)站建設(shè)方案書seo博客是什么意思
  • 番禺網(wǎng)站建設(shè)會(huì)計(jì)培訓(xùn)班的費(fèi)用是多少
  • wordpress 當(dāng)前分類名稱我們seo
  • ueeshop建站靠譜嗎百度點(diǎn)擊快速排名
  • 做網(wǎng)站公司找哪家公司重慶seo排
  • 重慶網(wǎng)站建設(shè)公司有哪些南京百度seo排名優(yōu)化
  • 手機(jī)app下載免費(fèi)安裝seo刷詞
  • 做網(wǎng)站的技術(shù)路線聊城疫情最新消息
  • 查詢網(wǎng)站開發(fā)無錫百度推廣開戶
  • 網(wǎng)站 引導(dǎo)頁 設(shè)計(jì)廣州網(wǎng)站排名專業(yè)樂云seo
  • 淘寶客網(wǎng)站做的好的seo指搜索引擎
  • 工信部網(wǎng)站備案信息查詢最近新聞?wù)?0字
  • 企業(yè)網(wǎng)絡(luò)推廣網(wǎng)站建設(shè)全球搜
  • 聊城網(wǎng)站優(yōu)化信息網(wǎng)頁廣告
  • 門戶網(wǎng)站建站注意事項(xiàng)國家免費(fèi)技能培訓(xùn)平臺
  • 怎么在自己做的網(wǎng)站上發(fā)視頻引擎網(wǎng)站
  • 深圳建設(shè)集團(tuán)網(wǎng)站首頁百度競價(jià)代運(yùn)營外包
  • 重慶網(wǎng)站制作那家好如何快速被百度收錄
  • 云南網(wǎng)站做的好的公司簡介愛站網(wǎng)站
  • 在線代理上網(wǎng)蘭州seo外包公司
  • 域名個(gè)人用戶可以做企業(yè)網(wǎng)站嗎谷歌seo網(wǎng)站建設(shè)
  • apk開發(fā)網(wǎng)絡(luò)運(yùn)營seo是什么
  • 建設(shè)部門網(wǎng)站查詢湖南百度推廣代理商
  • 邯鄲網(wǎng)站建設(shè)公司做網(wǎng)站設(shè)計(jì)哪里有
  • 網(wǎng)絡(luò)電商培訓(xùn)課程網(wǎng)站設(shè)計(jì)品牌營銷策略分析論文
  • 大型門戶網(wǎng)站程序泰州seo公司
  • 蘇州規(guī)劃建設(shè)局網(wǎng)站搜索引擎優(yōu)化的報(bào)告
  • 陜西省住房和城鄉(xiāng)建設(shè)廳官方網(wǎng)站成都計(jì)算機(jī)培訓(xùn)機(jī)構(gòu)排名前十