1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2024-11-21 13:25:53 +02:00

Updates for Rust 1.82 (#2449)

Rust 1.82 adds `&raw` expressions, and marks some attributes as unsafe.
This commit is contained in:
Andrew Walbran 2024-11-01 07:39:56 +00:00 committed by GitHub
parent 2bba470415
commit f8882190f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 100 additions and 72 deletions

View File

@ -55,6 +55,9 @@ jobs:
- name: Setup Rust cache
uses: ./.github/workflows/setup-rust-cache
- name: Update Rust
run: rustup update
- name: Build Rust code
run: cargo build
@ -89,7 +92,9 @@ jobs:
sudo apt install gcc-aarch64-linux-gnu
- name: Install toolchain
run: rustup target add ${{ matrix.target }}
run: |
rustup update
rustup target add ${{ matrix.target }}
- name: Build Rust code
working-directory: ${{ matrix.directory }}
@ -140,6 +145,9 @@ jobs:
sudo apt update
sudo apt install gettext
- name: Update Rust
run: rustup update
- name: Install mdbook
uses: ./.github/workflows/install-mdbook

View File

@ -20,7 +20,8 @@ use jni::sys::jstring;
use jni::JNIEnv;
/// HelloWorld::hello method implementation.
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
pub extern "system" fn Java_HelloWorld_hello(
mut env: JNIEnv,
_class: JClass,

View File

@ -6,14 +6,13 @@ Similarly, you can export Rust functions and call them from C.
You can do it by hand if you want:
```rust
extern "C" {
fn abs(x: i32) -> i32;
unsafe extern "C" {
safe fn abs(x: i32) -> i32;
}
fn main() {
let x = -42;
// SAFETY: `abs` doesn't have any safety requirements.
let abs_x = unsafe { abs(x) };
let abs_x = abs(x);
println!("{x}, {abs_x}");
}
```

View File

@ -3,14 +3,13 @@
We can declare external functions by hand:
```rust
extern "C" {
fn abs(x: i32) -> i32;
unsafe extern "C" {
safe fn abs(x: i32) -> i32;
}
fn main() {
let x = -42;
// SAFETY: `abs` doesn't have any safety requirements.
let abs_x = unsafe { abs(x) };
let abs_x = abs(x);
println!("{x}, {abs_x}");
}
```

View File

@ -42,8 +42,8 @@ Build, push, and run the binary on your device:
<details>
`#[no_mangle]` disables Rust's usual name mangling, so the exported symbol will
just be the name of the function. You can also use
`#[export_name = "some_name"]` to specify whatever name you want.
`#[unsafe(no_mangle)]` disables Rust's usual name mangling, so the exported
symbol will just be the name of the function. You can also use
`#[unsafe(export_name = "some_name")]` to specify whatever name you want.
</details>

View File

@ -19,7 +19,8 @@
use std::os::raw::c_int;
/// Analyze the numbers.
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
pub extern "C" fn analyze_numbers(x: c_int, y: c_int) {
if x < y {
println!("x ({x}) is smallest!");

View File

@ -8,7 +8,7 @@ Now let's use the new `Registers` struct in our driver.
<details>
- Note the use of `addr_of!` / `addr_of_mut!` to get pointers to individual
fields without creating an intermediate reference, which would be unsound.
- Note the use of `&raw const` / `&raw mut` to get pointers to individual fields
without creating an intermediate reference, which would be unsound.
</details>

View File

@ -17,49 +17,57 @@ use log::error;
use smccc::psci::system_off;
use smccc::Hvc;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
error!("sync_exception_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
error!("irq_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
error!("fiq_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
error!("serr_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
error!("sync_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
error!("irq_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
error!("fiq_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
error!("serr_lower");
system_off::<Hvc>().unwrap();

View File

@ -29,7 +29,8 @@ use smccc::Hvc;
/// Base address of the primary PL011 UART.
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.

View File

@ -29,7 +29,8 @@ use smccc::Hvc;
/// Base address of the primary PL011 UART.
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.

View File

@ -29,7 +29,8 @@ use smccc::Hvc;
/// Base address of the primary PL011 UART.
const PL011_BASE_ADDRESS: *mut u8 = 0x900_0000 as _;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.

View File

@ -23,7 +23,8 @@ mod exceptions;
const PSCI_SYSTEM_OFF: u32 = 0x84000008;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
// SAFETY: this only uses the declared registers and doesn't do anything
// with memory.

View File

@ -13,7 +13,6 @@
// limitations under the License.
use core::fmt::{self, Write};
use core::ptr::{addr_of, addr_of_mut};
// ANCHOR: Flags
use bitflags::bitflags;
@ -124,7 +123,7 @@ impl Uart {
// of a PL011 device which is appropriately mapped.
unsafe {
// Write to the TX buffer.
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
(&raw mut (*self.registers).dr).write_volatile(byte.into());
}
// Wait until the UART is no longer busy.
@ -139,7 +138,7 @@ impl Uart {
} else {
// SAFETY: We know that self.registers points to the control
// registers of a PL011 device which is appropriately mapped.
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
// TODO: Check for error conditions in bits 8-11.
Some(data as u8)
}
@ -148,7 +147,7 @@ impl Uart {
fn read_flag_register(&self) -> Flags {
// SAFETY: We know that self.registers points to the control registers
// of a PL011 device which is appropriately mapped.
unsafe { addr_of!((*self.registers).fr).read_volatile() }
unsafe { (&raw const (*self.registers).fr).read_volatile() }
}
}
// ANCHOR_END: Uart

View File

@ -20,8 +20,8 @@ for all these functions.)
inline assembly code, and ignore its contents afterwards. We need to use
`inout` rather than `in` because the call could potentially clobber the
contents of the registers.
- This `main` function needs to be `#[no_mangle]` and `extern "C"` because it is
called from our entry point in `entry.S`.
- This `main` function needs to be `#[unsafe(no_mangle)]` and `extern "C"`
because it is called from our entry point in `entry.S`.
- `_x0`–`_x3` are the values of registers `x0`–`x3`, which are conventionally
used by the bootloader to pass things like a pointer to the device tree.
According to the standard aarch64 calling convention (which is what

View File

@ -2,7 +2,7 @@
- Use [`pointer::read_volatile`] and [`pointer::write_volatile`].
- Never hold a reference.
- Use [`addr_of!`] to get fields of structs without creating an intermediate
- Use `&raw` to get fields of structs without creating an intermediate
reference.
[`pointer::read_volatile`]: https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.read_volatile
@ -19,7 +19,8 @@
- Some existing crates for volatile access to hardware do hold references, but
this is unsound. Whenever a reference exist, the compiler may choose to
dereference it.
- Use the `addr_of!` macro to get struct field pointers from a pointer to the
struct.
- Use `&raw` to get struct field pointers from a pointer to the struct.
- For compatibility with old versions of Rust you can use the [`addr_of!`] macro
instead.
</details>

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#[link_section = ".vector_table.interrupts"]
#[no_mangle]
#[unsafe(link_section = ".vector_table.interrupts")]
// SAFETY: There is no other global variable of this name.
#[unsafe(no_mangle)]
pub static __INTERRUPTS: [usize; 1] = [0];

View File

@ -17,13 +17,15 @@ use log::{error, info, trace};
use smccc::psci::system_off;
use smccc::Hvc;
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
error!("sync_exception_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
trace!("irq_current");
let intid =
@ -31,37 +33,43 @@ extern "C" fn irq_current(_elr: u64, _spsr: u64) {
info!("IRQ {intid:?}");
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
error!("fiq_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
error!("serr_current");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
error!("sync_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
error!("irq_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
error!("fiq_lower");
system_off::<Hvc>().unwrap();
}
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
error!("serr_lower");
system_off::<Hvc>().unwrap();

View File

@ -50,7 +50,8 @@ const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
const PL031_IRQ: IntId = IntId::spi(2);
// ANCHOR: main
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.

View File

@ -15,7 +15,6 @@
#![allow(unused)]
use core::fmt::{self, Write};
use core::ptr::{addr_of, addr_of_mut};
// ANCHOR: Flags
use bitflags::bitflags;
@ -126,7 +125,7 @@ impl Uart {
// of a PL011 device which is appropriately mapped.
unsafe {
// Write to the TX buffer.
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
(&raw mut (*self.registers).dr).write_volatile(byte.into());
}
// Wait until the UART is no longer busy.
@ -141,7 +140,7 @@ impl Uart {
} else {
// SAFETY: We know that self.registers points to the control
// registers of a PL011 device which is appropriately mapped.
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
// TODO: Check for error conditions in bits 8-11.
Some(data as u8)
}
@ -150,7 +149,7 @@ impl Uart {
fn read_flag_register(&self) -> Flags {
// SAFETY: We know that self.registers points to the control registers
// of a PL011 device which is appropriately mapped.
unsafe { addr_of!((*self.registers).fr).read_volatile() }
unsafe { (&raw const (*self.registers).fr).read_volatile() }
}
}
// ANCHOR_END: Uart

View File

@ -13,8 +13,6 @@
// limitations under the License.
// ANCHOR: solution
use core::ptr::{addr_of, addr_of_mut};
#[repr(C, align(4))]
struct Registers {
/// Data register
@ -63,7 +61,7 @@ impl Rtc {
pub fn read(&self) -> u32 {
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
unsafe { addr_of!((*self.registers).dr).read_volatile() }
unsafe { (&raw const (*self.registers).dr).read_volatile() }
}
/// Writes a match value. When the RTC value matches this then an interrupt
@ -71,7 +69,7 @@ impl Rtc {
pub fn set_match(&mut self, value: u32) {
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }
unsafe { (&raw mut (*self.registers).mr).write_volatile(value) }
}
/// Returns whether the match register matches the RTC value, whether or not
@ -79,7 +77,7 @@ impl Rtc {
pub fn matched(&self) -> bool {
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() };
let ris = unsafe { (&raw const (*self.registers).ris).read_volatile() };
(ris & 0x01) != 0
}
@ -90,7 +88,7 @@ impl Rtc {
pub fn interrupt_pending(&self) -> bool {
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
let ris = unsafe { addr_of!((*self.registers).mis).read_volatile() };
let ris = unsafe { (&raw const (*self.registers).mis).read_volatile() };
(ris & 0x01) != 0
}
@ -102,14 +100,14 @@ impl Rtc {
let imsc = if mask { 0x01 } else { 0x00 };
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
unsafe { addr_of_mut!((*self.registers).imsc).write_volatile(imsc) }
unsafe { (&raw mut (*self.registers).imsc).write_volatile(imsc) }
}
/// Clears a pending interrupt, if any.
pub fn clear_interrupt(&mut self) {
// SAFETY: We know that self.registers points to the control registers
// of a PL031 device which is appropriately mapped.
unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }
unsafe { (&raw mut (*self.registers).icr).write_volatile(0x01) }
}
}

View File

@ -4,7 +4,8 @@ In your Chromium build, add a new Rust target to `//ui/base/BUILD.gn`
containing:
```rust
#[no_mangle]
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
pub extern "C" fn hello_from_rust() {
println!("Hello from Rust!")
}
@ -32,7 +33,7 @@ subsequent exercises. If you've succeeded, you will be able to use right-click
## Where to find help
- The options available to the [`rust_static_library` gn template][0]
- Information about [`#[no_mangle]`][1]
- Information about [`#[unsafe(no_mangle)]`][1]
- Information about [`extern "C"`][2]
- Information about gn's [`--export-rust-project`][3] switch
- [How to install rust-analyzer in VSCode][4]
@ -45,9 +46,9 @@ This example is unusual because it boils down to the lowest-common-denominator
interop language, C. Both C++ and Rust can natively declare and call C ABI
functions. Later in the course, we'll connect C++ directly to Rust.
`allow_unsafe = true` is required here because `#[no_mangle]` might allow Rust
to generate two functions with the same name, and Rust can no longer guarantee
that the right one is called.
`allow_unsafe = true` is required here because `#[unsafe(no_mangle)]` might
allow Rust to generate two functions with the same name, and Rust can no longer
guarantee that the right one is called.
If you need a pure Rust executable, you can also do that using the
`rust_executable` gn template.

View File

@ -6,7 +6,7 @@
specifies a single function, to be called from C++, called `hello_from_rust`,
taking no parameters and returning no value.
- Modify your previous `hello_from_rust` function to remove `extern "C"` and
`#[no_mangle]`. This is now just a standard Rust function.
`#[unsafe(no_mangle)]`. This is now just a standard Rust function.
- Modify your `gn` target to build these bindings.
- In your C++ code, remove the forward-declaration of `hello_from_rust`.
Instead, include the generated header file.

View File

@ -10,7 +10,7 @@ Creating pointers is safe, but dereferencing them requires `unsafe`:
fn main() {
let mut s = String::from("careful!");
let r1 = &mut s as *mut String;
let r1 = &raw mut s;
let r2 = r1 as *const String;
// SAFETY: r1 and r2 were obtained from references and so are guaranteed to

View File

@ -51,11 +51,11 @@ mod ffi {
pub d_name: [c_char; 1024],
}
extern "C" {
pub fn opendir(s: *const c_char) -> *mut DIR;
unsafe extern "C" {
pub unsafe fn opendir(s: *const c_char) -> *mut DIR;
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
pub fn readdir(s: *mut DIR) -> *const dirent;
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
// See https://github.com/rust-lang/libc/issues/414 and the section on
// _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).
@ -64,9 +64,9 @@ mod ffi {
// to macOS (as opposed to iOS / wearOS / etc.) on Intel and PowerPC.
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
#[link_name = "readdir$INODE64"]
pub fn readdir(s: *mut DIR) -> *const dirent;
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
pub fn closedir(s: *mut DIR) -> c_int;
pub unsafe fn closedir(s: *mut DIR) -> c_int;
}
}