Author: Wang Jiangtong
This is a brief introduction to This Week in Rust 2021, Rust 2021(1.56). The 409 tweets are about RFC2845, supertrait_ITEM_shadowing, Rust security, And the 413 tweet about OpenSUSE 2021 Rust Survey and Rust security.
Community news and updates
Rust 2021 (1.56)
Rust 2021 has been released on October 21 as expected, as can be seen in the official blog post Announcing Rust 1.56.0 and Rust 2021 or the official Edition Guide. You can update to version 1.56.0 with the following command:
$ rustup update stable
Copy the code
This Week in Rust #404: Rust 2021 and Periodic Service Discovery is a summary of the latest 5.11 release and how to migrate to the new release to use the new features. New features not mentioned in the preview restore features removed from Rust 1.0 using @ binding values, as in the following example:
struct Matrix {
data: Vec<f64>,
row_len: usize,}// Before, we need separate statements to bind
// the whole struct and also read its parts.
// Previously, to get the value of an attribute in a structure, we had to first bind the value of the structure to a variable and then get the value from its dependent attribute
let matrix = get_matrix();
let row_len = matrix.row_len;
// or with a destructuring pattern:
// Or use decomposition mode
let Matrix { row_len, .. } = matrix;
// Rust 1.56 now lets you bind both at once!
// Now, with @, Rust 1.56 can do both
let matrix @ Matrix { row_len, .. } = get_matrix();
Copy the code
RFC 2845: Supertrait Item Shadowing
In general, RFC 2845 modifies the scoped method orientation so that when a generic implementation’s child traits and parent traits have a method of the same name, the parent method traits are no longer considered unless explicitly declared, eliminating the problem that the compiler previously considered method name confusion.
For example:
mod traits {
trait Super {
fn foo(&self);
}
trait Sub: Super {
fn foo(&self); }}Copy the code
Both traits have the method foo of the same name. If we define another generic type:
use traits::Sub;
fn use_trait_obj(x: Box<dyn Sub>) {
x.foo();
}
Copy the code
The compiler generates the following alarm:
error[E0034]: multiple applicable items in scope
--> src\main.rs:10:4
|
10 | x.foo();
| ^^^ multiple `foo` found
|
note: candidate #1 is defined in the trait `traits::Super`
--> src\main.rs:2:2
|
2 | fn foo(&self);
| ^^^^^^^^^^^^^^
= help: to disambiguate the method call, write `traits::Super::foo(x)` instead
note: candidate #2 is defined in the trait `traits::Sub`
Copy the code
The practical problem, as in this example, is that for both the underlying library that defines the parent trait and the superlibrary that defines the child trait, if the developer updates the underlying library so that the parent trait has the same method as the child trait, the code will be alerted when the method is called using generics, and these alarms may cause a chain reaction. Modifying these alarms can be very laborious and requires both libraries to be aware of each other to eliminate name confusion. Logically, however, the underlying library should not be aware of the superlibrary, nor should users who also develop or use the superlibrary necessarily be aware of the underlying library.
Therefore, to address this issue, RFC 2845 decided to use methods in child traits in preference to methods with the same name in the parent trait unless explicitly stated. Such as:
fn generic_fn<S: Sub>(x: S) {
// This:
x.foo();
// is the same as:
X.foo () will use Sub::foo instead of Super::foo
Sub::foo(x);
// also still possible:
// But Super::foo can be called with an explicit declaration
Super::foo(x);
}
Copy the code
If both child and parent traits are introduced, the user needs to explicitly declare which method to use since the relationship between the two traits is side-by-side:
fn generic_fn<S: Sub+Super>(x: S) {
// Error: both Sub::foo and Super::foo are in scope
x.foo();
}
Copy the code
Similarly, when writing a method in a child trait, you need to declare whether you use your own method or the parent’s method:
trait Super {
fn foo(&self);
}
trait Sub: Super {
fn foo(&self);
fn bar(&self) {
// Is and will continue to be an error
self.foo(); }}Copy the code
Rust and memory security
OpenSUSE 2021 Rust Survey
From 2006 to 2021, from personal projects to the establishment of Rust Foundation and the release of Rust version 2021, Rust, as one of the emerging development languages, has gradually become a new hot topic due to its characteristics of high reliability, high performance and high productivity, and has become the most popular language in StackOverflow survey for six consecutive years. From September 8 to October 7, 2021, OpenSUSE helped survey 1,360 people about their thoughts on Rust and how to use the Rust tool chain. A detailed report can be found in Results from the OpenSUSE 2021 Rust Survey. Here are some of the findings:
- attitude
- 44% consider Rust to be important to their projects and work (rating 4-5/5; 599/1360)
- 57% believe Rust will become increasingly important to their future projects and work (rating 4-5/5; 778/1360)
- 60% think Rust will become increasingly important to other developers and projects in the future (rating 4-5/5; 820/1360)
- use
Although the data may be slightly biased because most of the respondents are from the Rust community, this survey can still partially prove the importance of Rust in the present and future.
Rust and memory security
Rust aims to achieve high performance that matches C and C++, but another advantage of Rust over C and C++ is memory security.” You Really Shouldn’t Roll Your Own Crypto: An Empirical Study of patching in Cryptographic Libraries” states that 27.2% of the security problems in the Cryptographic Libraries were algorithms back then, but 37.2% of the problems were memory security after all the patching, The median number of errors found was 4.18 years. Openssl, the well-known C library for cryptography and security protocols, confirmed an average of one problem per 1,000 lines of code.
Google’s investigation of the Chromium project came to a similar conclusion: 70% of the security issues were memory security issues, such as C/C++ error Pointers. At the same time, the non-secure bug root error is the same. In addition, more than 50 percent of safety problems are more than 1 year old, and about 25 percent are more than 3 years old.
Google’s current solution is to sandbox each site and Tab, but this solution is not perfect. Processes are the smallest unit of sandbox isolation, but the cost of processes is not free. For example, in the Android environment, too many processes can affect device security, such as killing other processes in the background. At the same time, the process of sharing information between web pages is still needed, and more and more processes will exceed the process required by Chromium, affecting the running efficiency.
Rust: Possible solutions
In addition to sandbox, Google is also exploring new solutions, such as developing its own C++ library, hardware migration, and using other more secure languages. Google’s September 21, 2021 blog post provides a brief overview of the solutions being implemented, using compile-time and run-time checks to ensure Pointers are correct, and exploring Rust.
Runtime checking has performance overhead and is not always suitable for mobile devices with small memory; For compile-time checking, the implementation of C++ borrowing checking is not very easy. Google’s documentation on C++ Borrowing Trouble: The Difficulties Of A C++ borrow-checker can be seen.
For Rust, Google is concerned about the compatibility of C++ and Rust’s code. Rust is still being tested in Chrome development, but is beginning to be used in various projects, such as android. Since 2019, the Android Open Source Project has supported Rust as a development language for operating systems, as a way to replace C and C++ with less sandbox isolation.
Integrate Rust into the Android project
When Rust was integrated into the Android open source project, Google made some improvements. Instead of using Cargo as the default build system and package manager, Google uses homegrown Soong to call RUSTC. The reasons for this are:
- Maintain the system that was established before. Before Rust was introduced, Soong had a sophisticated system for building C libraries and dependencies, while Android controlled compiler versions and global compiler variables to ensure that libraries were compiled in a certain way. If Cargo is used, these Settings are no longer controlled by Soong and can result in different versions of the same library, affecting memory and storage usage.
- Ensure system stability and control. Although Cargo can do some control through Cargo. Toml, Soong doesn’t understand how Cargo. Toml affects RUSTC, so it’s better to just use Soong.
- Maintain a closed architecture. Self-contained and host configuration insensitive builds, known as closed builds, are required for Android to generate reproducible builds. Cargo relies on the build.RS script and does not yet provide a seal guarantee.
- Ensure scalability. Cargo is not designed to be integrated into existing build systems and therefore does not expose its build units. Each Cargo call compiles the entire Crate dependency graph with the given Cargo. Toml, which causes Crate to be built multiple times in an entire project, which is too crude for Soong. Soong needs smaller building blocks to control the scale of use of Rust.
Cargo compiles Rust binaries through the build.rs script and handles some of the pre-build tasks in the process, such as setting up the environment. Therefore, avoiding build.RS can to some extent avoid using Cargo. Meanwhile, Google open Source projects have other reasons to avoid using build.rs:
- Build.rs can execute arbitrary code on the build host, which can lead to additional security issues or security checks if a tripartite library is used.
- The build.rs script of a tripartite library may not be a closed build or reusable. At the same time, it is not uncommon for build.rs scripts to retrieve files outside of the build folder, however this means that build.rs is not a closed build and requires additional local patches or upstream collaboration to resolve this issue.
- Build.rs is the most commonly used function room to build the C library, but Soong has solved this problem and no additional build.rs is required.
- For similar reasons, other libraries are built to avoid the use of build scripts and instead use them in android.bp files to inform the architecture.
Rust’s interaction with the prememory C code base
Google also reached a conclusion about Rust’s interaction with an existing C code base. Generally speaking, on the Android platform, the interaction between languages is implemented by defining the Foreign Function Interface (FFI). Rust can provide FFI interfaces for C, and C has an adequate Application Binary Interface (ABI), so interaction between C and Rust is not a big problem.
Interactions between Rust and C++ are more difficult. Although Rust and C++ ‘s interactive support both use the ABI of C, the nature of both languages makes it difficult for the two languages themselves to translate each other’s functionality directly. For Google, the interaction problems between Rust and C libraries are rooted in the large number of existing C/C++ libraries. Google focused on investigating the possibility of using C++ functions in Rust, looking at exported C++ functions and compatibility supported by Rust through the C ABI and compatibility libraries, and finally sorting the expressible types into the following categories:
- Types that can be supported by primitive types, including Pointers and references to those Pointers. Rust’s existing FFI handles them correctly, and Android’s own build system generates the bindings automatically.
- The types that can be supported by CXX compat crate currently include STD ::string, STD ::vector, and C++ methods. As long as the user defines the types and functions they want to be compatible with, the Crate generates the correct corresponding code for compatibility.
- For some types, although they cannot be supported directly, the interfaces that use them have been manually modified to add Rust support, such as the types used by AIDL and Protobufs.
- Types that may be added to CXX Crate in the future, such as STD :: Optional and STD ::chrono:: Duration.
- Types we do not intend to support or need to support, such as mutex, native_handle, STD ::local&.
- Other types that do not fall into any of the above categories, such as STD :: String passed by value. STD :: String passed as a value is not currently supported by any CXX Crate.
Google then looked at the C++ libraries most commonly used on android (liblog, libbase, libutils, libcutils, libhidlbase, libbinder, libhardware, libz, libcrypto, Libui and Mainline analyzed and categorized all the external C++ functions and parameters used by these libraries to determine if they could communicate with Rust.
- Common C++ library
- Mainline module
For libraries, 87% fell into the top four categories; For Mainline modules, 90% fall into the first four categories. The current interaction analysis of the year-long Android open source project is as follows:
That said, primitive types and CXX crate provide most of the Rust and C++ interoperability required for android locks, and most of the other types have solutions as well. The interoperability between Rust and C++ makes it possible to develop using Rust in an android environment.
reference
- Rust in the Android platform
- Integrating Rust Into the Android Open Source Project
- Rust/C++ interop in the Android Platform