From 710f0eab6e83f391cc5de4813dd5d9479cd99f57 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 22:54:06 -0600 Subject: [PATCH 01/15] break Validity Invariant and Safety Invariant apart --- reference/src/glossary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 3b9cf4f7..5510bfd2 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -14,7 +14,7 @@ If data immediately pointed to by a `*const T` or `&*const T` is mutated, that's *Interior mutability* refers to the ability to perform interior mutation without causing UB. All interior mutation in Rust has to happen inside an [`UnsafeCell`](https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html), so all data structures that have interior mutability must (directly or indirectly) use `UnsafeCell` for this purpose. -#### Validity and safety invariant +#### Validity Invariant The *validity invariant* is an invariant that all data must uphold any time it is accessed or copied in a typed manner. This invariant is known to the compiler and exploited by optimizations such as improved enum layout or eliding in-bounds checks. @@ -31,6 +31,8 @@ fn main() { unsafe { } } ``` +#### Safety Invariant + The *safety* invariant is an invariant that safe code may assume all data to uphold. This invariant is used to justify which operations safe code can perform. The safety invariant can be temporarily violated by unsafe code, but must always be upheld when interfacing with unknown safe code. From f4683c81b414262dd4949eb78c895598237e1db4 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 22:56:35 -0600 Subject: [PATCH 02/15] alphabetize the entries --- reference/src/glossary.md | 43 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 5510bfd2..ce627978 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -14,22 +14,13 @@ If data immediately pointed to by a `*const T` or `&*const T` is mutated, that's *Interior mutability* refers to the ability to perform interior mutation without causing UB. All interior mutation in Rust has to happen inside an [`UnsafeCell`](https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html), so all data structures that have interior mutability must (directly or indirectly) use `UnsafeCell` for this purpose. -#### Validity Invariant - -The *validity invariant* is an invariant that all data must uphold any time it is accessed or copied in a typed manner. -This invariant is known to the compiler and exploited by optimizations such as improved enum layout or eliding in-bounds checks. +#### Layout -In terms of MIR statements, "accessed or copied" means whenever an assignment statement is executed. -That statement has a type (LHS and RHS must have the same type), and the data being assigned must be valid at that type. -Moreover, arguments passed to a function must be valid at the type given in the callee signature, and the return value of a function must be valid at the type given in the caller signature. -OPEN QUESTION: Are there more cases where data must be valid? +The *layout* of a type defines its size and alignment as well as the offsets of its subobjects (e.g. fields of structs/unions/enum/... or elements of arrays). +Moreover, the layout of a type records its *function call ABI* (or just *ABI* for short): how the type is passed *by value* across a function boundary. -In terms of code, some data computed by `TERM` is valid at type `T` if and only if the following program does not have UB: -```rust,ignore -fn main() { unsafe { - let t: T = std::mem::transmute(TERM); -} } -``` +Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. +In this document, *layout* and *representation* are not synonyms. #### Safety Invariant @@ -53,14 +44,6 @@ Moreover, such unsafe code must not return a non-UTF-8 string to the "outside" o To summarize: *Data must always be valid, but it only must be safe in safe code.* For some more information, see [this blog post](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html). -#### Layout - -The *layout* of a type defines its size and alignment as well as the offsets of its subobjects (e.g. fields of structs/unions/enum/... or elements of arrays). -Moreover, the layout of a type records its *function call ABI* (or just *ABI* for short): how the type is passed *by value* across a function boundary. - -Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. -In this document, *layout* and *representation* are not synonyms. - #### Niche The *niche* of a type determines invalid bit-patterns that will be used by layout optimizations. @@ -75,6 +58,22 @@ niches. For example, the "all bits uninitialized" is an invalid bit-pattern for `&mut T`, but this bit-pattern cannot be used by layout optimizations, and is not a niche. +#### Validity Invariant + +The *validity invariant* is an invariant that all data must uphold any time it is accessed or copied in a typed manner. +This invariant is known to the compiler and exploited by optimizations such as improved enum layout or eliding in-bounds checks. + +In terms of MIR statements, "accessed or copied" means whenever an assignment statement is executed. +That statement has a type (LHS and RHS must have the same type), and the data being assigned must be valid at that type. +Moreover, arguments passed to a function must be valid at the type given in the callee signature, and the return value of a function must be valid at the type given in the caller signature. +OPEN QUESTION: Are there more cases where data must be valid? + +In terms of code, some data computed by `TERM` is valid at type `T` if and only if the following program does not have UB: +```rust,ignore +fn main() { unsafe { + let t: T = std::mem::transmute(TERM); +} } +``` ### TODO From 4b720a3df7a2de462a60d67965e5c487403fec87 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 23:26:27 -0600 Subject: [PATCH 03/15] Initial definition for Aliasing Not precise, but something we can point beginners to for the moment while more is worked on. --- reference/src/glossary.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index ce627978..044551d8 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -1,5 +1,42 @@ ## Glossary +#### Aliasing + +(Please note: a full aliasing model for Rust has not yet been constructed, but +at the moment we can give the following guidelines.) + +*Aliasing* is any time two pointers and/or references point to the same "span" +of memory. A span of memory is similar to how a slice works: there's a base byte +address as well as a length in bytes. + +Consider the following example: + +```rust +fn main() { + let u: u64 = 7_u64; + let r: &u64 = &u; + let s: &[u8] = unsafe { + core::slice::from_raw_parts(&u as *const u64 as *const u8, 8) + }; + let (head, tail) = s.split_first().unwrap(); +} +``` + +In this case, both `r` and `s` alias each other, since they both point to the +memory of `u`. + +However, `head` and `tail` do not alias each other: `head` points to the first +byte of `u` and `tail` points to the other seven bytes of `u` after it. + +* The span length of `&T`, `&mut T`, `*const T`, or `*mut T` when `T` is + [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) is + `size_of()`. +* When `T` is not `Sized` the span length is `size_of_val(t)`. + +One interesting side effect of these rules is that references and pointers to +Zero Sized Types _never_ alias each other, because their span length is always 0 +bytes. + #### Interior mutability *Interior Mutation* means mutating memory where there also exists a live shared reference pointing to the same memory; or mutating memory through a pointer derived from a shared reference. From 75bc547ca60fa3223f4032e34b54a5e50ecc36ce Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 23:26:58 -0600 Subject: [PATCH 04/15] Improve wording --- reference/src/glossary.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 044551d8..d6e1a920 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -5,9 +5,10 @@ (Please note: a full aliasing model for Rust has not yet been constructed, but at the moment we can give the following guidelines.) -*Aliasing* is any time two pointers and/or references point to the same "span" -of memory. A span of memory is similar to how a slice works: there's a base byte -address as well as a length in bytes. +*Aliasing* is any time one pointer or reference points to a "span" of memory +that overlaps with the span of another pointer or reference. A span of memory is +similar to how a slice works: there's a base byte address as well as a length in +bytes. Consider the following example: From 4b2327bd1b5e7407547da07f72664c80c61705f7 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 23:32:09 -0600 Subject: [PATCH 05/15] WHOOPS wrong word to put there for sure --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index d6e1a920..5a7d1682 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -3,7 +3,7 @@ #### Aliasing (Please note: a full aliasing model for Rust has not yet been constructed, but -at the moment we can give the following guidelines.) +at the moment we can give the following definition.) *Aliasing* is any time one pointer or reference points to a "span" of memory that overlaps with the span of another pointer or reference. A span of memory is From a12166079711b88c79bc2b607a343bff7c4a0a78 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 18 Jul 2019 23:36:03 -0600 Subject: [PATCH 06/15] make both examples use as close of wording as possible. --- reference/src/glossary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 5a7d1682..bebff46d 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -23,8 +23,8 @@ fn main() { } ``` -In this case, both `r` and `s` alias each other, since they both point to the -memory of `u`. +In this case, both `r` and `s` alias each other, since they both point to all of +the bytes of `u`. However, `head` and `tail` do not alias each other: `head` points to the first byte of `u` and `tail` points to the other seven bytes of `u` after it. From 3241b8ffe82a8a07861e1029623ba88f5b3f4e46 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 19 Jul 2019 10:11:00 -0600 Subject: [PATCH 07/15] Change to JUST the aliasing entry other formatting cleanup will be other PRs --- reference/src/glossary.md | 45 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index bebff46d..9aaf403f 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -52,15 +52,22 @@ If data immediately pointed to by a `*const T` or `&*const T` is mutated, that's *Interior mutability* refers to the ability to perform interior mutation without causing UB. All interior mutation in Rust has to happen inside an [`UnsafeCell`](https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html), so all data structures that have interior mutability must (directly or indirectly) use `UnsafeCell` for this purpose. -#### Layout +#### Validity and safety invariant -The *layout* of a type defines its size and alignment as well as the offsets of its subobjects (e.g. fields of structs/unions/enum/... or elements of arrays). -Moreover, the layout of a type records its *function call ABI* (or just *ABI* for short): how the type is passed *by value* across a function boundary. +The *validity invariant* is an invariant that all data must uphold any time it is accessed or copied in a typed manner. +This invariant is known to the compiler and exploited by optimizations such as improved enum layout or eliding in-bounds checks. -Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. -In this document, *layout* and *representation* are not synonyms. +In terms of MIR statements, "accessed or copied" means whenever an assignment statement is executed. +That statement has a type (LHS and RHS must have the same type), and the data being assigned must be valid at that type. +Moreover, arguments passed to a function must be valid at the type given in the callee signature, and the return value of a function must be valid at the type given in the caller signature. +OPEN QUESTION: Are there more cases where data must be valid? -#### Safety Invariant +In terms of code, some data computed by `TERM` is valid at type `T` if and only if the following program does not have UB: +```rust,ignore +fn main() { unsafe { + let t: T = std::mem::transmute(TERM); +} } +``` The *safety* invariant is an invariant that safe code may assume all data to uphold. This invariant is used to justify which operations safe code can perform. @@ -82,6 +89,14 @@ Moreover, such unsafe code must not return a non-UTF-8 string to the "outside" o To summarize: *Data must always be valid, but it only must be safe in safe code.* For some more information, see [this blog post](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html). +#### Layout + +The *layout* of a type defines its size and alignment as well as the offsets of its subobjects (e.g. fields of structs/unions/enum/... or elements of arrays). +Moreover, the layout of a type records its *function call ABI* (or just *ABI* for short): how the type is passed *by value* across a function boundary. + +Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. +In this document, *layout* and *representation* are not synonyms. + #### Niche The *niche* of a type determines invalid bit-patterns that will be used by layout optimizations. @@ -96,26 +111,10 @@ niches. For example, the "all bits uninitialized" is an invalid bit-pattern for `&mut T`, but this bit-pattern cannot be used by layout optimizations, and is not a niche. -#### Validity Invariant - -The *validity invariant* is an invariant that all data must uphold any time it is accessed or copied in a typed manner. -This invariant is known to the compiler and exploited by optimizations such as improved enum layout or eliding in-bounds checks. - -In terms of MIR statements, "accessed or copied" means whenever an assignment statement is executed. -That statement has a type (LHS and RHS must have the same type), and the data being assigned must be valid at that type. -Moreover, arguments passed to a function must be valid at the type given in the callee signature, and the return value of a function must be valid at the type given in the caller signature. -OPEN QUESTION: Are there more cases where data must be valid? - -In terms of code, some data computed by `TERM` is valid at type `T` if and only if the following program does not have UB: -```rust,ignore -fn main() { unsafe { - let t: T = std::mem::transmute(TERM); -} } -``` ### TODO * *tag* * *rvalue* * *lvalue* -* *representation* +* *representation* \ No newline at end of file From 94429de8d714dfa58f45b0d8d5121bcb55e1b6c1 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 19 Jul 2019 10:17:56 -0600 Subject: [PATCH 08/15] note `noalias` attribute --- reference/src/glossary.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 9aaf403f..83b8807b 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -38,6 +38,11 @@ One interesting side effect of these rules is that references and pointers to Zero Sized Types _never_ alias each other, because their span length is always 0 bytes. +It is also important to know that LLVM IR has a `noalias` attribute that works +somewhat differently from this definition. However, that's considered a low +level detail of a particular Rust implementation. When programming Rust, the +Abstract Rust Machine is intended to operate according to the definition here. + #### Interior mutability *Interior Mutation* means mutating memory where there also exists a live shared reference pointing to the same memory; or mutating memory through a pointer derived from a shared reference. From b4ae21f9d54e88b1ed5f67f3a84e87781aa276e5 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 23 Jul 2019 11:45:42 -0600 Subject: [PATCH 09/15] requested clarification --- reference/src/glossary.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 83b8807b..fd1f2c9a 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -27,7 +27,8 @@ In this case, both `r` and `s` alias each other, since they both point to all of the bytes of `u`. However, `head` and `tail` do not alias each other: `head` points to the first -byte of `u` and `tail` points to the other seven bytes of `u` after it. +byte of `u` and `tail` points to the other seven bytes of `u` after it. Also, +both `head` and `tail` alias `s`. * The span length of `&T`, `&mut T`, `*const T`, or `*mut T` when `T` is [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) is From 9f2e32efbf5d89e1fa09d98325503b1ebf4a6f15 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 24 Jul 2019 17:40:49 -0600 Subject: [PATCH 10/15] Improve the explanation of how to find the span. --- reference/src/glossary.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index fd1f2c9a..2117d045 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -27,13 +27,19 @@ In this case, both `r` and `s` alias each other, since they both point to all of the bytes of `u`. However, `head` and `tail` do not alias each other: `head` points to the first -byte of `u` and `tail` points to the other seven bytes of `u` after it. Also, -both `head` and `tail` alias `s`. - -* The span length of `&T`, `&mut T`, `*const T`, or `*mut T` when `T` is - [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) is - `size_of()`. -* When `T` is not `Sized` the span length is `size_of_val(t)`. +byte of `u` and `tail` points to the other seven bytes of `u` after it. Both `head` +and `tail` alias `s`, any overlap is sufficient to count as an alias. + +* The span of a pointer or reference is the size of the value being pointed to or referenced. +* For some type `T` that is [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) + The span length of a pointer or reference to `T` is found with `size_of::()`. +* When `T` is not `Sized` the story is a little tricker: + * If you have a reference `r` you can use `size_of_val(r)` to determine the + span of the reference. + * If you have a pointer `p` you must unsafely convert that to a reference before + you can use `size_of_val`. There is not currently a safe way to determine the + span of a pointer to an unsized type. +* The Data Layout chapter also has more information on the sizes of different types. One interesting side effect of these rules is that references and pointers to Zero Sized Types _never_ alias each other, because their span length is always 0 @@ -123,4 +129,4 @@ niche. * *tag* * *rvalue* * *lvalue* -* *representation* \ No newline at end of file +* *representation* From 13c4c62a9b1a6f8ba869c9dc7190510d5e1dedd2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 25 Jul 2019 01:12:40 -0600 Subject: [PATCH 11/15] link to potenial aliasing model --- reference/src/glossary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 2117d045..096b72c4 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -3,7 +3,9 @@ #### Aliasing (Please note: a full aliasing model for Rust has not yet been constructed, but -at the moment we can give the following definition.) +at the moment we can give the following definition. The most developed potential +aliasing model so far is known as "Stacked Borrows", and can be found +[here](https://github.com/Lokathor/unsafe-code-guidelines/blob/lokathor/wip/stacked-borrows.md).) *Aliasing* is any time one pointer or reference points to a "span" of memory that overlaps with the span of another pointer or reference. A span of memory is From 4d0eacff6d4970ca1c7e1757ad527b4e2314b626 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 25 Jul 2019 02:05:43 -0600 Subject: [PATCH 12/15] Update reference/src/glossary.md Co-Authored-By: Ralf Jung --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 096b72c4..a8124af4 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -33,7 +33,7 @@ byte of `u` and `tail` points to the other seven bytes of `u` after it. Both `he and `tail` alias `s`, any overlap is sufficient to count as an alias. * The span of a pointer or reference is the size of the value being pointed to or referenced. -* For some type `T` that is [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) +* For a type `T` that is [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) The span length of a pointer or reference to `T` is found with `size_of::()`. * When `T` is not `Sized` the story is a little tricker: * If you have a reference `r` you can use `size_of_val(r)` to determine the From 3649a770fefe817e6497088e0014d14409a76691 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 25 Jul 2019 02:08:42 -0600 Subject: [PATCH 13/15] fixed linking to the fork on accident --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 096b72c4..7181f6f0 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -5,7 +5,7 @@ (Please note: a full aliasing model for Rust has not yet been constructed, but at the moment we can give the following definition. The most developed potential aliasing model so far is known as "Stacked Borrows", and can be found -[here](https://github.com/Lokathor/unsafe-code-guidelines/blob/lokathor/wip/stacked-borrows.md).) +[here](https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md).) *Aliasing* is any time one pointer or reference points to a "span" of memory that overlaps with the span of another pointer or reference. A span of memory is From ab1c05f507b5a18b2c617e8a7bd10354b65da774 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 25 Jul 2019 03:17:34 -0600 Subject: [PATCH 14/15] break apart the bulleted list --- reference/src/glossary.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index fc8864f6..af7c9b38 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -32,7 +32,10 @@ However, `head` and `tail` do not alias each other: `head` points to the first byte of `u` and `tail` points to the other seven bytes of `u` after it. Both `head` and `tail` alias `s`, any overlap is sufficient to count as an alias. -* The span of a pointer or reference is the size of the value being pointed to or referenced. +The span of a pointer or reference is the size of the value being pointed to or referenced. + +Depending on the type, you can determine the size as follows: + * For a type `T` that is [`Sized`](https://doc.rust-lang.org/core/marker/trait.Sized.html) The span length of a pointer or reference to `T` is found with `size_of::()`. * When `T` is not `Sized` the story is a little tricker: @@ -41,7 +44,8 @@ and `tail` alias `s`, any overlap is sufficient to count as an alias. * If you have a pointer `p` you must unsafely convert that to a reference before you can use `size_of_val`. There is not currently a safe way to determine the span of a pointer to an unsized type. -* The Data Layout chapter also has more information on the sizes of different types. + +The Data Layout chapter also has more information on the sizes of different types. One interesting side effect of these rules is that references and pointers to Zero Sized Types _never_ alias each other, because their span length is always 0 From 37b3055305282d0e5f0cca52fdb8e700a02c299c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 25 Jul 2019 03:21:01 -0600 Subject: [PATCH 15/15] Attempt to link to the Data Layout chapter? I honestly don't know if this link will work because there isn't a layout.md in the repo, the SUMMARY has always been messed up and mdbook has just been generating a blank page because of it this whole time. --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index af7c9b38..ba1d0f93 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -45,7 +45,7 @@ Depending on the type, you can determine the size as follows: you can use `size_of_val`. There is not currently a safe way to determine the span of a pointer to an unsized type. -The Data Layout chapter also has more information on the sizes of different types. +The [Data layout](./layout.md) chapter also has more information on the sizes of different types. One interesting side effect of these rules is that references and pointers to Zero Sized Types _never_ alias each other, because their span length is always 0