From d65e5902134444a0fa8bf1592f1565702f261c47 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Sat, 27 Feb 2021 16:49:13 -0800 Subject: [PATCH 01/10] Document raw pointer <-> usize casts. --- src/expressions/operator-expr.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 73284bb78..bfc6ce4ad 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -360,6 +360,10 @@ Here `*T` means either `*const T` or `*mut T`. * `char` casts to the value of the code point, then uses a numeric cast if needed. * `u8` to `char` cast * Casts to the `char` with the corresponding code point. +* Pointer to address cast + * Casting from a valid raw pointer to `usize` will produce a numeric address representing the pointer. +* Address to pointer cast + * Casting from `usize` to a raw pointer will produce a pointer with the same value as the original pointer if the `usize` was obtained through a pointer to address cast of a valid pointer of the same type. \* if integer-to-float casts with this rounding mode and overflow behavior are not supported natively by the hardware, these casts will likely be slower than From ec33e2b36049f7015b98e382d4dbe32e751f8ba9 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Sun, 7 Mar 2021 22:04:46 -0800 Subject: [PATCH 02/10] Address to pointer cast: hint at provenance. --- src/expressions/operator-expr.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index bfc6ce4ad..42ff7b4cb 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -361,9 +361,11 @@ Here `*T` means either `*const T` or `*mut T`. * `u8` to `char` cast * Casts to the `char` with the corresponding code point. * Pointer to address cast - * Casting from a valid raw pointer to `usize` will produce a numeric address representing the pointer. + * Casting from a valid raw pointer to `usize` will produce the address that is pointed to. Note that the pointer's provenance is lost in this conversion. * Address to pointer cast - * Casting from `usize` to a raw pointer will produce a pointer with the same value as the original pointer if the `usize` was obtained through a pointer to address cast of a valid pointer of the same type. + * Casting from `usize` to a raw pointer will produce a raw pointer to the same location as the original pointer, if the `usize` was obtained through a pointer to address cast of a valid pointer. + + Note that the two pointers are not equivalent. Dereferencing the pointer obtained from the address to pointer cast may be [undefined behavior] if aliasing rules are not followed. \* if integer-to-float casts with this rounding mode and overflow behavior are not supported natively by the hardware, these casts will likely be slower than @@ -377,6 +379,8 @@ expected. number, preferring the one with an even least significant digit if exactly halfway between two floating point numbers. +[undefined behavior]: ../behavior-considered-undefined.md + ## Assignment expressions > **Syntax**\ From b144532c3c0ed567a8f912d37a920091dcc277b4 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Sun, 7 Mar 2021 23:00:58 -0800 Subject: [PATCH 03/10] Pointer<->address cast: stylistic changes. --- src/expressions/operator-expr.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 42ff7b4cb..3ffcc1249 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -361,11 +361,17 @@ Here `*T` means either `*const T` or `*mut T`. * `u8` to `char` cast * Casts to the `char` with the corresponding code point. * Pointer to address cast - * Casting from a valid raw pointer to `usize` will produce the address that is pointed to. Note that the pointer's provenance is lost in this conversion. + * Casting from a valid raw pointer to `usize` will produce the address that is pointed to. + + The pointer's provenance is lost in this conversion. * Address to pointer cast * Casting from `usize` to a raw pointer will produce a raw pointer to the same location as the original pointer, if the `usize` was obtained through a pointer to address cast of a valid pointer. - Note that the two pointers are not equivalent. Dereferencing the pointer obtained from the address to pointer cast may be [undefined behavior] if aliasing rules are not followed. +
+ Warning: + The two pointers are not equivalent. + Dereferencing the pointer obtained from the address to pointer cast may be undefined behavior if aliasing rules are not followed. +
\* if integer-to-float casts with this rounding mode and overflow behavior are not supported natively by the hardware, these casts will likely be slower than @@ -379,8 +385,6 @@ expected. number, preferring the one with an even least significant digit if exactly halfway between two floating point numbers. -[undefined behavior]: ../behavior-considered-undefined.md - ## Assignment expressions > **Syntax**\ From f41e1a8117aaddffc6da229b1d9767844e57cdf5 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Tue, 27 Apr 2021 19:51:25 -0700 Subject: [PATCH 04/10] Reformat cast expression details. Now it's not one big list. --- src/expressions/operator-expr.md | 91 ++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 3ffcc1249..52d77d2fb 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -331,47 +331,29 @@ Here `*T` means either `*const T` or `*mut T`. ### Semantics -* Numeric cast - * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op - * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will - truncate - * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will - * zero-extend if the source is unsigned - * sign-extend if the source is signed - * Casting from a float to an integer will round the float towards zero - * `NaN` will return `0` - * Values larger than the maximum integer value will saturate to the - maximum value of the integer type. - * Values smaller than the minimum integer value will saturate to the - minimum value of the integer type. - * Casting from an integer to float will produce the closest possible float \* - * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* - * on overflow, infinity (of the same sign as the input) is produced - * note: with the current set of numeric types, overflow can only happen - on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)` - * Casting from an f32 to an f64 is perfect and lossless - * Casting from an f64 to an f32 will produce the closest possible f32 \*\* - * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* - * on overflow, infinity (of the same sign as the input) is produced -* Enum cast - * Casts an enum to its discriminant, then uses a numeric cast if needed. -* Primitive to integer cast - * `false` casts to `0`, `true` casts to `1` - * `char` casts to the value of the code point, then uses a numeric cast if needed. -* `u8` to `char` cast - * Casts to the `char` with the corresponding code point. -* Pointer to address cast - * Casting from a valid raw pointer to `usize` will produce the address that is pointed to. - - The pointer's provenance is lost in this conversion. -* Address to pointer cast - * Casting from `usize` to a raw pointer will produce a raw pointer to the same location as the original pointer, if the `usize` was obtained through a pointer to address cast of a valid pointer. - -
- Warning: - The two pointers are not equivalent. - Dereferencing the pointer obtained from the address to pointer cast may be undefined behavior if aliasing rules are not followed. -
+#### Numeric cast + +* Casting between two integers of the same size (e.g. i32 -> u32) is a no-op +* Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will + truncate +* Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will + * zero-extend if the source is unsigned + * sign-extend if the source is signed +* Casting from a float to an integer will round the float towards zero + * `NaN` will return `0` + * Values larger than the maximum integer value will saturate to the + maximum value of the integer type. + * Values smaller than the minimum integer value will saturate to the + minimum value of the integer type. +* Casting from an integer to float will produce the closest possible float \* + * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* + * on overflow, infinity (of the same sign as the input) is produced + * note: with the current set of numeric types, overflow can only happen + on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)` +* Casting from an f32 to an f64 is perfect and lossless +* Casting from an f64 to an f32 will produce the closest possible f32 \*\* + * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* + * on overflow, infinity (of the same sign as the input) is produced \* if integer-to-float casts with this rounding mode and overflow behavior are not supported natively by the hardware, these casts will likely be slower than @@ -385,6 +367,33 @@ expected. number, preferring the one with an even least significant digit if exactly halfway between two floating point numbers. +#### Enum cast + +Casts an enum to its discriminant, then uses a numeric cast if needed. + +#### Primitive to integer cast + +* `false` casts to `0`, `true` casts to `1` +* `char` casts to the value of the code point, then uses a numeric cast if needed. +8` to `char` cast +* Casts to the `char` with the corresponding code point. + +#### Pointer to address cast + +Casting from a valid raw pointer to `usize` will produce the address that is pointed to. + +The pointer's provenance is lost in this conversion. + +#### Address to pointer cast + +Casting from `usize` to a raw pointer will produce a raw pointer to the same location as the original pointer, if the `usize` was obtained through a pointer to address cast of a valid pointer. + +
+Warning: +The two pointers are not equivalent. +Dereferencing the pointer obtained from the address to pointer cast may be undefined behavior if aliasing rules are not followed. +
+ ## Assignment expressions > **Syntax**\ From b794f8a7c9bc69ba3a39da20e3f084800b501bde Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Tue, 27 Apr 2021 20:29:59 -0700 Subject: [PATCH 05/10] Expand on pointer<->address casts without mentioning provenance. --- src/expressions/operator-expr.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 52d77d2fb..62e6ab6cc 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -380,20 +380,34 @@ Casts an enum to its discriminant, then uses a numeric cast if needed. #### Pointer to address cast -Casting from a valid raw pointer to `usize` will produce the address that is pointed to. - -The pointer's provenance is lost in this conversion. +Casting from a raw pointer to an integer produces the machine address of the referenced memory. +If the integer type is smaller than the pointer type, the address may be truncated; using `usize` avoids this. #### Address to pointer cast -Casting from `usize` to a raw pointer will produce a raw pointer to the same location as the original pointer, if the `usize` was obtained through a pointer to address cast of a valid pointer. +Casting from an integer to a raw pointer interprets the integer as a memory address and produces a pointer referencing that memory.
Warning: -The two pointers are not equivalent. -Dereferencing the pointer obtained from the address to pointer cast may be undefined behavior if aliasing rules are not followed. +This interacts with the Rust memory model, which is still under development. +A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. +Dereferencing such a pointer may be undefined behavior if aliasing rules are not followed.
+A trivial example of sound address arithmetic: + +```rust +let mut values: [i32; 2] = [1, 2]; +let p1 = &mut values[0] as *mut i32; +let first_address = p1 as usize; +let second_address = first_address + 4; +let p2 = second_address as *mut i32; +unsafe { + *p2 += 1; +} +assert_eq!(values[1], 3); +``` + ## Assignment expressions > **Syntax**\ From 96a811a6a723ce3ae34a906b8f1bfe5078a54533 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Tue, 27 Apr 2021 22:48:12 -0700 Subject: [PATCH 06/10] Fix warning block for pointer<->integer cast expression. --- src/expressions/operator-expr.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 62e6ab6cc..f88c0caa7 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -388,10 +388,12 @@ If the integer type is smaller than the pointer type, the address may be truncat Casting from an integer to a raw pointer interprets the integer as a memory address and produces a pointer referencing that memory.
+ Warning: This interacts with the Rust memory model, which is still under development. A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. Dereferencing such a pointer may be undefined behavior if aliasing rules are not followed. +
A trivial example of sound address arithmetic: From c11c6494fd06d155ebafd8b7e0cbe1f8b6f567d4 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Tue, 27 Apr 2021 22:55:04 -0700 Subject: [PATCH 07/10] Fix reformatting mishap. --- src/expressions/operator-expr.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index f88c0caa7..4ac366a57 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -375,8 +375,10 @@ Casts an enum to its discriminant, then uses a numeric cast if needed. * `false` casts to `0`, `true` casts to `1` * `char` casts to the value of the code point, then uses a numeric cast if needed. -8` to `char` cast -* Casts to the `char` with the corresponding code point. + +#### `u8` to `char` cast + +Casts to the `char` with the corresponding code point. #### Pointer to address cast From a2cae390f8a96e0fadcb9b4f6150a8ef1793252a Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Wed, 28 Apr 2021 13:11:08 -0700 Subject: [PATCH 08/10] Make the pointer to address cast example sounder. Okay, "actually sound". Hopefully. --- src/expressions/operator-expr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 4ac366a57..9a8e28d5f 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -402,7 +402,7 @@ A trivial example of sound address arithmetic: ```rust let mut values: [i32; 2] = [1, 2]; -let p1 = &mut values[0] as *mut i32; +let p1: *mut i32 = values.as_mut_ptr(); let first_address = p1 as usize; let second_address = first_address + 4; let p2 = second_address as *mut i32; From 771cce3e578a083b1fd6461faef7b2f2add728c4 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Wed, 28 Apr 2021 13:11:36 -0700 Subject: [PATCH 09/10] Justify "4". --- src/expressions/operator-expr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 9a8e28d5f..582434fd3 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -404,7 +404,7 @@ A trivial example of sound address arithmetic: let mut values: [i32; 2] = [1, 2]; let p1: *mut i32 = values.as_mut_ptr(); let first_address = p1 as usize; -let second_address = first_address + 4; +let second_address = first_address + 4; // 4 == size_of::() let p2 = second_address as *mut i32; unsafe { *p2 += 1; From dc1931a41ad6d67e43ec07c5450dc999f5525268 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 17 May 2021 15:44:59 -0700 Subject: [PATCH 10/10] Use markdown link instead of HTML. --- src/expressions/operator-expr.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 582434fd3..e431146b0 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -394,7 +394,7 @@ Casting from an integer to a raw pointer interprets the integer as a memory addr Warning: This interacts with the Rust memory model, which is still under development. A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. -Dereferencing such a pointer may be undefined behavior if aliasing rules are not followed. +Dereferencing such a pointer may be [undefined behavior] if aliasing rules are not followed. @@ -520,6 +520,7 @@ See [this test] for an example of using this dependency. [logical xor]: ../types/boolean.md#logical-xor [mutable]: ../expressions.md#mutability [place expression]: ../expressions.md#place-expressions-and-value-expressions +[undefined behavior]: ../behavior-considered-undefined.md [unit]: ../types/tuple.md [value expression]: ../expressions.md#place-expressions-and-value-expressions [temporary value]: ../expressions.md#temporaries