- Việc loại Rust chỉ vì sự tồn tại của
unsafevà dùng tiêu chí cho rằng chỉ Fil-C mới an toàn đã bỏ qua phạm vi áp dụng trong phần mềm thực tế và các đánh đổi kỹ thuật - Fil-C biến các truy cập bộ nhớ sai trong C/C++ thành panic, nhưng phải trả giá bằng việc không tương thích ABI, suy giảm hiệu năng gấp nhiều lần trong một số tình huống, và đưa GC vào
- Trong khoảng 5 triệu dòng mã Rust trên Android, đã phát hiện 1 lỗ hổng an toàn bộ nhớ tiềm tàng được sửa trước khi phát hành, ước tính 0,2 lỗi trên mỗi triệu dòng; thấp hơn hơn 1.000 lần so với dữ liệu C/C++ trước đây là khoảng 1.000 lỗi
- Không cần phải chỉ chọn một giữa công nghệ ngăn được 99,9% vấn đề trong mọi chương trình và công nghệ ngăn được 100% vấn đề trong 90% chương trình; với phần mềm khó chấp nhận các ràng buộc của Fil-C, những lựa chọn thay thế như Rust là phù hợp
- An toàn bộ nhớ cần được xem xét cùng với hiệu năng, ABI, GC và ngăn chặn data race; nếu phê bình Rust là chưa đủ, thì ít nhất cũng phải áp dụng cùng tiêu chuẩn đó cho C/C++ thông thường và Zig không dùng Fil-C
Mô hình trách nhiệm của Rust và các ngôn ngữ hệ thống truyền thống
- Thảo luận về an toàn bộ nhớ trong các ngôn ngữ lập trình hệ thống không dùng GC chủ yếu xoay quanh khác biệt về mô hình trách nhiệm giữa Rust và C/C++/Zig
- Rust chấp nhận cái giá là từ chối cả một số chương trình có thể an toàn, nhằm ngăn biên dịch các chương trình có thể gây ra vấn đề an toàn bộ nhớ
unsafelà lối thoát cho phép vượt qua một số bảo đảm, chẳng hạn như dereference con trỏ thô- Các ngôn ngữ họ C phần lớn giao việc bảo đảm an toàn bộ nhớ cho lập trình viên
- Mức độ hỗ trợ khác nhau giữa các ngôn ngữ, như RAII và smart pointer của C++ hay
defercủa Zig, nhưng về nguyên tắc chúng không chặn truy cập bộ nhớ sai
Lựa chọn mà Fil-C bổ sung
- Fil-C cung cấp một cách tiếp cận mới để chạy mã C và C++ một cách an toàn về bộ nhớ
- Khi xảy ra truy cập bộ nhớ sai như truy cập ngoài phạm vi hoặc use-after-free, nó gây ra panic
- Kết hợp GC với InvisiCaps, cơ chế theo dõi vùng nhớ mà con trỏ có thể truy cập
- Với Zig, một chế độ biên dịch mới lấy cảm hứng từ Fil-C cũng đã được đề xuất
- Nếu một số dự án C/C++ phổ biến cung cấp bản phát hành được biên dịch bằng Fil-C, lựa chọn để giảm lỗ hổng an toàn bộ nhớ có thể tăng lên
Tiêu chí coi Rust là không an toàn
- Nhà phát triển Fil-C từng đánh giá trên Twitter rằng Rust không phải là ngôn ngữ an toàn bộ nhớ, với lý do
unsafecó thể vượt qua một số bảo đảm - Nhà phát triển Zig Andrew Kelley cũng mô tả chế độ lấy cảm hứng từ Fil-C trong tiêu đề issue liên quan là chế độ biên dịch “thực sự an toàn bộ nhớ, không như Rust”
- Một số thảo luận yêu cầu rằng nếu người dùng Rust thật sự coi trọng an toàn bộ nhớ, họ nên bỏ Rust và quảng bá Fil-C an toàn hơn
- Tiêu chí này so sánh Rust với Fil-C trong khi bỏ qua chi phí thực tế của Fil-C, thể hiện thái độ tương tự lời phê bình mà cộng đồng Rust thường nhận là cuồng tín
Ràng buộc khi áp dụng Fil-C
- Fil-C không phải là phương án thay thế drop-in không tốn chi phí
- Không tương thích ABI với các chương trình được biên dịch không dùng Fil-C
- Có thể chậm hơn gấp nhiều lần trong một số tình huống
- Đưa GC vào
- Với các chương trình như tiện ích đơn giản, nơi khó cảm nhận suy giảm hiệu năng hoặc không cần liên kết động, các ràng buộc này có thể không mang tính quyết định
- Ngược lại, cũng có nhiều dự án phổ biến không thể chấp nhận GC và việc không tương thích ABI; những chương trình khó áp dụng Fil-C ở dạng hiện tại thường phù hợp với Rust
Dữ liệu lỗ hổng từ mã Rust thực tế
- Dữ liệu để đánh giá tính bảo mật thực chất của Rust hiện vẫn chưa nhiều, nhưng chưa phát hiện nhiều lỗ hổng an toàn bộ nhớ có thể bị khai thác trong phần mềm Rust
- Trong hơn 5 triệu dòng mã Rust của Android, đã phát hiện 1 lỗ hổng an toàn bộ nhớ tiềm tàng và sửa trước khi phát hành
- Mật độ lỗ hổng ước tính là 0,2 lỗi trên mỗi triệu dòng
- Dữ liệu C/C++ trước đây của Android là khoảng 1.000 lỗi trên mỗi triệu dòng
- Mật độ trong mã Rust đang được theo dõi là thấp hơn hơn 1.000 lần so với C/C++
- Con số có thể khác nhau tùy dự án, nhưng đây là bằng chứng rằng trong môi trường thực tế, Rust làm giảm đáng kể rủi ro đưa vấn đề an toàn bộ nhớ vào mã
Vì sao không cần chọn duy nhất một bên
- Lựa chọn giả định giữa công nghệ ngăn được 99,9% vấn đề trong mọi chương trình và công nghệ ngăn được 100% vấn đề trong 90% chương trình cho thấy cả phạm vi áp dụng lẫn mức độ phòng ngừa đều quan trọng
- Dù chưa biết tỷ lệ thực tế, không cần chỉ chọn một trong hai cách tiếp cận
- Các dự án C/C++/Zig có thể chấp nhận đánh đổi có thể cung cấp binary Fil-C
- Phần mềm không thể dùng Fil-C có thể được viết bằng ngôn ngữ loại bỏ hoàn toàn hoặc phần lớn rủi ro lỗ hổng an toàn bộ nhớ
Vì sao vẫn chọn Rust dù có thể dùng GC
- Việc dùng Rust vẫn hợp lý ngay cả khi có các lựa chọn dựa trên GC như Go hay Fil-C
- Những chương trình có thể viết bằng ngôn ngữ dựa trên GC thường không cần
unsafe, còn những chương trình cầnunsafethường không thể dùng GC - Có thể đánh giá các bảo đảm và tính năng ngôn ngữ khác, như ngăn chặn data race, quan trọng hơn rủi ro nhỏ về an toàn bộ nhớ
- Fil-C biến các lỗ hổng an toàn bộ nhớ trong C/C++ hiện có thành crash
- Điều này tốt hơn lỗ hổng bảo mật, nhưng nếu mật độ trước đây khoảng 1.000 lỗi trên mỗi triệu dòng vẫn giữ nguyên, sẽ còn nhiều crash cần sửa
- Trong quá khứ cũng từng có lỗ hổng bảo mật tận dụng khả năng khiến chương trình crash của kẻ tấn công
Tiêu chuẩn nhất quán về an toàn bộ nhớ
- Nếu ngay cả 0,2 lỗi trên mỗi triệu dòng của Rust cũng không thể chấp nhận, thì cần áp dụng phê bình tương tự hoặc nghiêm khắc hơn cho C/C++ thông thường và Zig không dùng Fil-C
- Việc chấp nhận các lựa chọn thay thế kém an toàn hơn Rust nhưng lại loại riêng Rust vì
unsafelà không áp dụng nhất quán chủ nghĩa tuyệt đối về an toàn bộ nhớ
1 bình luận
Ý kiến trên Lobste.rs
Có vẻ OP đã tiếp nhận một cách khó chịu phát biểu của Andrew Kelly rằng Zig có thể biên dịch thành tệp thực thi hoàn toàn an toàn bộ nhớ mà không cần lối thoát, kể cả với toàn bộ phụ thuộc C/C++, với chi phí hiệu năng khoảng 1~6 lần tùy tần suất theo dõi con trỏ
Người viết xem đây là đòn công kích Rust và ở cuối bài cũng công kích Zig, nhưng Fil-C và chế độ build mới của Zig là đóng góp tích cực cho hệ sinh thái, đồng thời đưa ra điểm thiết kế và sự đánh đổi khác với Rust
Tôi hiểu điều đó theo nghĩa là nếu làm theo kiểu lập trình hướng dữ liệu mà đội Zig ưa chuộng thì có thể kéo chi phí hiệu năng xuống gần mức 1 lần
Cũng không quá vô lý nếu đọc như một cách khiêu khích không cần thiết, và sau đó Andrew đã đổi tiêu đề sang bớt kích động hơn
Trái với thường lệ, khi lời châm chọc nhẹ kiểu “ngôn ngữ của các anh không an toàn bộ nhớ” nhắm vào mình thì quy mô phản ứng của các lập trình viên Rust là khá lớn
Tôi cũng rất thích Rust, nhưng cần tiếp nhận chuyện này công bằng
Hơn nữa, C đã được kiểm chứng hình thức của seL4 còn an toàn hơn nữa
Zig có ưu điểm là dễ kết thúc đúng cách khi cấp phát bộ nhớ thất bại và biên dịch cũng nhanh
Tôi không biết Fil-C có an toàn bộ nhớ hơn Rust hay không, nhưng với nhu cầu của tôi thì garbage collector và việc không tương thích với C ABI là trở ngại mang tính quyết định
Nếu làm mọi thứ đơn luồng thì có thể tránh race condition, và nếu thêm garbage collector thì có thể có an toàn bộ nhớ, nhưng điều hay ở Rust là nó cung cấp cả hai mà không cần hai sự đánh đổi đó
Vì rất coi trọng an toàn bộ nhớ nên Fil-C và triển khai Fil-C ABI của Zig đương nhiên là lựa chọn hiển nhiên
Các dự án Rust có phụ thuộc C sẽ bị suy yếu về đảm bảo an toàn, và dù chỉ dùng Rust thuần cũng được nhưng khá bất tiện
Rust cũng nên triển khai Fil-C ABI để có thể build an toàn các phụ thuộc C rồi liên kết với Rust, tôi không hiểu vì sao điều này lại gây tranh cãi
Nếu triển khai chức năng tương tự thì tôi muốn nó chỉ được dùng như biện pháp hỗ trợ nhằm cải thiện mã FFI trong bản build debug
Cách đặt garbage collector và kiểm tra mọi phép toán ở runtime không phù hợp với mọi trường hợp sử dụng
Trước khi xem Fil-C là thứ chỉ dành cho utility đơn giản, nên xem bài thuyết trình về Fil-C tại hội nghị Software Should Work
Người thuyết trình đã trình bày bằng một chiếc laptop Linux mà toàn bộ user space, kể cả OpenOffice Impress, đều được dựng bằng Fil-C
Nó có thể không phù hợp với một số chương trình C/C++, nhưng có vẻ không phải công nghệ đồ chơi như người viết nghĩ
Vì xuất thân từ Python nên an toàn bộ nhớ vốn là tiền đề mặc định, và lý do tôi chọn Rust có ba điều
Thứ nhất, nó có hệ thống kiểu mạnh để đảm bảo tính đúng đắn ngay tại thời điểm biên dịch, và an toàn bộ nhớ đạt được nhờ
#![forbid(unsafe_code)]cùng việc kiểm toán phụ thuộc bằng cargo-geiger lại là cách diễn đạt kém thú vị nhất trong số đóThứ hai, nó cung cấp một hệ sinh thái giúp dễ chia sẻ mã đã được viết an toàn một lần sang nhiều ngôn ngữ và môi trường thực thi
Thứ ba, nó có syntax sugar giúp viết mã cấp cao thuận tiện, như
try!(x)thời đóZig và Fil-C dường như không đáp ứng được khả năng mã hóa các bất biến vào hệ thống kiểu để compiler bắt lỗi logic bằng mẫu typestate hay newtype
Tính không tương thích ABI của Fil-C cũng gây vấn đề khi viết các mô-đun biên dịch an toàn cho runtime hiện có như CPython trên shared web hosting
comptimecòn biểu đạt mạnh hơn RustCó những sự đánh đổi về thời gian biên dịch, độ dài dòng, và việc phần lớn hệ sinh thái không đi xa đến mức đó, nhưng thực sự là làm được và khá thú vị
Tôi tò mò vì sao công nghệ như Fil-C không xuất hiện từ 20 năm trước
Nhưng không ai muốn trả cái giá đó bằng CPU hay bộ nhớ, tức là bằng chi phí
Giai đoạn 2004~2018 thì có ý tưởng, nhưng họ cho rằng bản thân ý tưởng về C an toàn bộ nhớ là ngớ ngẩn; giai đoạn 2018~2023 thì đã đổi suy nghĩ nhưng không tìm ra cách đạt được mức tương thích cực cao
Fil-C giai đoạn đầu 2023~2024 có độ tương thích và hiệu năng thấp hơn nhiều, và đến cuối 2024 thì bước đột phá InvisiCaps đã mang lại mức tương thích cao hiện nay cùng hiệu năng chấp nhận được
Điều khiến họ đổi suy nghĩ vào khoảng năm 2018 là quan sát rằng các biến thể C dùng trên GPU là một dạng đơn giản của C an toàn bộ nhớ
Nếu diễn giải thiện chí nhất câu “nếu phe Rust thực sự coi trọng an toàn bộ nhớ thì nên ủng hộ Fil-C an toàn hơn và bỏ Rust”, thì ý của nó là giờ đã có Fil-C nên hãy ngừng nỗ lực viết lại thế giới bằng Rust, quay về C/C++ và giữ hệ sinh thái thư viện thống nhất như trước
Dù thư viện Rust có thể dùng từ C/C++, vẫn có những lập trình viên không muốn điều đó, nên theo logic này nếu người dùng Rust thừa nhận giải pháp tốt hơn và từ bỏ thì sự chia rẽ sẽ biến mất
Nhưng Fil-C có những sự đánh đổi mà Rust không có, là garbage collector và chỉ hỗ trợ x86-64 Linux
Ngoài an toàn bộ nhớ ra, Cargo và việc không có global namespace cũng là những lý do quan trọng để dùng Rust, và thật đáng tiếc khi sự chia rẽ giữa các phe ngôn ngữ lại gắn với một cuộc chiến văn hóa rộng hơn
Tôi chỉ muốn làm ra thư viện mà ai cũng sẵn lòng dùng
Trong số các lập trình viên C có thể cũng có người không muốn thư viện C++, lại còn có Zig và Odin xuất hiện nữa, nên kể cả Rust biến mất thì sự phân mảnh vẫn còn
Tôi tự hỏi liệu Rust có thực sự tạo ra một kiểu phân mảnh đặc biệt khác hay không
comptimeRust mã hóa được nhiều ràng buộc hơn nên là ngôn ngữ gốc lý tưởng