[閒聊] 怎麼跟剛學 (Rust) 程式的人解釋指標?
> 本文改寫自 holydc 的原作。在此非常感謝原作者。
> 原文來自:https://www.ptt.cc/bbs/TKU_EE_92C/M.1477360815.A.46B.html
「你是不是有什麼事情瞞著我」
下班一回到家,就看到 Rust 對我怒目而視
「怎麼會呢,我們之間是沒有秘密的呀」
我一邊換上居家服,一邊敷衍回應
「那你說說看這是怎麼回事」
Rust 打開我的 GitHub 帳號,指著我最近綠油油的一片
「我還想說你最近這麼喜歡類型體操,原來是跟 TypeScript 有一腿啊」
我頓時語塞,因為我最近確實拿 TypeScript 的類型系統寫了個踩地雷遊戲
不過我隨即反擊
「我以前寫 pattern matching 的時候你也懷疑我跟 Haskell,妳到底想要我怎麼樣」
Rust 似乎是有點被我嚇到,愣了一下之後對我吼道
「我只是想要你這個不中用的廢物爭氣點!」
你這個不中用的廢物!
這句話彷彿對我的腦門揮下一記重擊
是啊,我就是廢物
cargo clippy 全是 warn,至今遇到 lifetime 問題只會 `.clone()`
更不用說還有做不完的 feature 和解不完的 bug
就連經過茶水間也聽到女同事在說「欸欸那個肥宅 holydc 好噁心喔」「真~的~」
於是,我感覺到頭腦裡有什麼東西斷掉了
失去理智的我把 Rust 推倒在 CLion 上,並且把她的原始檔拘束起來
「你…你想做什麼!?快放開我!」
Rust 奮力抵抗,但是這樣卻更激起了我的獸性
「啊啊…妳果然還是最美的,我果然還是最愛妳了啊」
fn main() {
我看著 Rust 毫無防備的進入點…main 函數,情不自禁地又聞又舔
「對了,我有準備一個可以讓妳很舒服的東西,這是妳姊姊 Unsafe Rust 最喜歡的玩具」
「那是…啊」
let a: *mut () = unsafe { std::mem::MaybeUninit::uninit().assume_i
nit() };
我冷不防地把指標放入 Safe Rust 的函數裡面,受到刺激的 Rust 也不禁發出一聲嬌喘
unsafe { *(a as *mut i8) = i8::MAX; }
「啊…等一下…嗯…指標還沒…」
Rust 一邊掙扎一邊說著,卻被我毫不留情地打斷
「哦,看來 1 byte 沒問題嘛,那就繼續放囉」※1
unsafe { *(a as *mut i16) = i16::MAX; }
「嗚…不要…」
到剛才為止都還盛氣凌人的 Rust,這時臉上泛著潮紅,表情開始扭曲
但是我當然不可能就此罷手
unsafe { *(a as *mut i32) = i32::MAX; }
「已經…滿了…」
Rust 哀求著說
「少裝死了,`*mut ()` 都能塞進 i32 了。接下來才是重頭戲呢~」※1
unsafe { *(a as *mut i128) = i128::MAX; }
「啊…啊…」
此時 Rust 已經只能呻吟,腰部因為強烈的刺激而反弓起來
「真是乖孩子,真虧妳能撐到現在呢」
我溫柔地擦去 Rust 額頭上的汗水
「接下來這個就是最後了」
struct Foo([i32; 1024]);
「不可以不可以不可以不可以不可以,這個真的沒辦法…」
unsafe { *(a as *mut Foo) = Foo([0; 1024]); }
「------------------------------!啊嘿」
只見 Rust 雙眼翻白,舌頭半吐,幾乎失去了意識
「哈哈哈,沒初始化的指標就變成各種形狀感覺怎麼樣啊」
「好過分…為什麼要做這種事」
Rust 哭喪著臉,身體止不住顫抖
「因為我想更加了解妳呀」
#![feature(link_llvm_intrinsics)]
「…咦?」
「猜猜看這是什麼呢?」
extern {
#[link_name = "llvm.addressofreturnaddress"]
fn return_address() -> *mut u8;
}
「嗚…」
「快說喔,不然我就要進去了喔!」
let b: *mut u8 = unsafe { return_address() };
「啊…嗯…是…return address…」
Rust 極為羞恥地說出
「好吧,那今天就『到此』為止吧」
unsafe { *b = u8::MAX };
「啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊」
我看著失神的 Rust
胸口隨著紊亂的呼吸起伏,腹部還是不斷痙攣
四處飛濺的體液、唾液、汗液沾濕了整片文字編輯器
整個 IDE 充滿著淫靡的氣息
「我什麼都願意做…拜託你原諒我」
回過神的 Rust 氣若游絲,苦苦哀求
「好吧,那妳就讓我聽聽最悅耳的哭喊聲…」
drop_in_place()
「咦…騙人…不會吧…這樣真的會壞掉的!」
「那就壞掉吧」
unsafe {
a.drop_in_place();
b.drop_in_place();
}
}
「不要------------------------------!」
「哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈」
「…dc」
嗯?什麼聲音?
「喂,holydc」
我睜開眼睛,尋找聲音的來源,原來是公司主管
「明天發表會要 demo 的版本弄得怎樣了?」
「我們能不能拿到新一輪的融資就看這次了,好好加油啊」
我揉一揉眼睛,看了看時間,凌晨兩點四十三分,Redmine 上面還有六張票
「好,繼續 debug 吧!」
※1 建置環境 rustc 1.58.0-nightly (db062de72 2021-11-01) on macOS (ARM64)
assert_eq!(std::mem::size_of::<()>(), 0);
assert_eq!(std::mem::size_of::<i8>(), 1);
assert_eq!(std::mem::size_of::<i16>(), 2);
assert_eq!(std::mem::size_of::<i32>(), 4);
assert_eq!(std::mem::size_of::<i128>(), 16);
Linux (Rust Playground) 環境似乎會直接 SIGSEGV。
但我的 macOS 是能正常執行到 `到達函數結尾`。
本次的完整程式碼在此:https://play.rust-lang.org/?version=nightly&mode=debug&e
dition=2021&gist=f8a81cefaf9dff88471cdf9caa78c518
---
會想改寫這篇文章,是因為剛好跟朋友聊到 Unsafe Rust 及類型轉換的話題。
這篇文章所涉及的操作多數都是 holydc 在原文中提及的操作,有興趣的人可以對照一下
原文,不過我有刪掉移動指針的部分(因為我的環境 .offset() 就會噴 Segmentation f
ault),將其改成 LLVM IR 取 return address 的方法。
改寫這篇文章也順便讓我熟悉 Unsafe Rust 的操作。假如有哪裡寫得不好,或者說有問
題,也歡迎跟我提出 QQ
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 218.173.112.222 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/PLT/M.1636474355.A.B69.html
推
11/27 23:18,
3年前
, 1F
11/27 23:18, 1F
推
12/05 08:51,
3年前
, 2F
12/05 08:51, 2F
推
02/21 04:36,
3年前
, 3F
02/21 04:36, 3F
※ 編輯: pan93412 (218.173.90.142 臺灣), 03/13/2022 08:57:11
※ 編輯: pan93412 (218.173.90.142 臺灣), 03/13/2022 09:06:09
PLT 近期熱門文章
PTT數位生活區 即時熱門文章