From 6491ee0fd3c714a0915c8ef097d91e09a37987e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2026 13:13:39 +0200 Subject: [PATCH 01/14] document that extern statics may be bigger than the declared size --- src/items/external-blocks.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 8218b8f1c3..e4fb6118dd 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -74,6 +74,10 @@ Extern statics can be either immutable or mutable just like [statics] outside of r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. +r[items.extern.static.size] +The actual memory that the extern static resolves to must have *at least* the size and alignment of the type that it was declared with in the extern block. +If the actual memory is bigger, then it is permitted to access that extra memory. + r[items.extern.abi] ## ABI From ec8f4ef9c9d523203a85af8546b57fdf11601426 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Aug 2026 16:40:40 +0200 Subject: [PATCH 02/14] add UB: invalid extern static --- src/behavior-considered-undefined.md | 3 +++ src/items/external-blocks.md | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 935f0dd9fa..04a65fe520 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -61,6 +61,9 @@ r[undefined.invalid] r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. +r[undefined.extern-static] +* Declaring an `extern static` with some size/alignment/mutability, when the actual symbol this resolves to is smaller / less aligned / less mutable. + r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. * For assumptions specifically related to unwinding, see the [panic documentation][unwinding-ffi]. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index e4fb6118dd..86a9f907c2 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,7 +75,7 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The actual memory that the extern static resolves to must have *at least* the size and alignment of the type that it was declared with in the extern block. +The actual memory that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared with in the extern block. If the actual memory is bigger, then it is permitted to access that extra memory. r[items.extern.abi] @@ -470,6 +470,7 @@ Attributes on extern function parameters follow the same rules and restrictions [`verbatim` documentation for rustc]: ../../rustc/command-line-arguments.html#linking-modifiers-verbatim [`whole-archive` documentation for rustc]: ../../rustc/command-line-arguments.html#linking-modifiers-whole-archive [attributes]: ../attributes.md +[extern-static-ub]: ../behavior-considered-undefined.md#r-undefined.extern-static [functions]: functions.md [regular function parameters]: functions.md#attributes-on-function-parameters [statics]: static-items.md From 199eef1e14fb5b53a4dc56bbc4ca9f1aef1bcd77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Aug 2026 19:11:39 +0200 Subject: [PATCH 03/14] do not allow oversized raw-dylib statics --- src/behavior-considered-undefined.md | 1 + src/items/external-blocks.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 04a65fe520..ab2207e283 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -63,6 +63,7 @@ r[undefined.asm] r[undefined.extern-static] * Declaring an `extern static` with some size/alignment/mutability, when the actual symbol this resolves to is smaller / less aligned / less mutable. + For `extern static` with `raw-dylib` linkage, the actual symbol must have *exactly* the declared size. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 86a9f907c2..d8f101ccc0 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -372,6 +372,9 @@ Specifying `kind = "dylib"` instructs the Rust compiler to link an import librar r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. +r[items.extern.attributes.link.kind-raw-dylib.size] +Unlike regular external statics, a `raw-dylib` static is *not* allowed to be bigger than its declared size. + r[items.extern.attributes.link.import_name_type] #### The `import_name_type` key From 41a5230c24d291185413e5fef076da9c9a392281 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Sep 2026 22:31:59 +0200 Subject: [PATCH 04/14] fix typo Co-authored-by: Pete LeVasseur --- src/items/external-blocks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index d8f101ccc0..7c5af3dcdd 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,7 +75,7 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The actual memory that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared with in the extern block. +The actual memory that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared within the extern block. If the actual memory is bigger, then it is permitted to access that extra memory. r[items.extern.abi] From 68f84407c471e3fbe4641a44f52ecd784bceb8b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Sep 2026 08:40:52 +0200 Subject: [PATCH 05/14] tweak terminology, clarify --- src/behavior-considered-undefined.md | 4 ++-- src/items/external-blocks.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index ab2207e283..e514e9247b 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -62,8 +62,8 @@ r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. r[undefined.extern-static] -* Declaring an `extern static` with some size/alignment/mutability, when the actual symbol this resolves to is smaller / less aligned / less mutable. - For `extern static` with `raw-dylib` linkage, the actual symbol must have *exactly* the declared size. +* Declaring an `extern static` with some size/alignment/mutability, when the actual memory the extern static resolves to is smaller / less aligned / less mutable. + For `extern static` with `raw-dylib` linkage, the actual memory must have *exactly* the declared size. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 7c5af3dcdd..922e321ff5 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -373,7 +373,7 @@ r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. r[items.extern.attributes.link.kind-raw-dylib.size] -Unlike regular external statics, a `raw-dylib` static is *not* allowed to be bigger than its declared size. +Unlike regular external statics, a `raw-dylib` static is *not* allowed to be bigger than its declared size. The size needs to match exactly. r[items.extern.attributes.link.import_name_type] #### The `import_name_type` key From 1dc181cee69a4935486890e216bdcf6c077b4256 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Oct 2026 18:47:52 +0200 Subject: [PATCH 06/14] null is still special --- src/behavior-considered-undefined.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index e514e9247b..984a8123fb 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -62,7 +62,7 @@ r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. r[undefined.extern-static] -* Declaring an `extern static` with some size/alignment/mutability, when the actual memory the extern static resolves to is smaller / less aligned / less mutable. +* Declaring an `extern static` with some size/alignment/mutability, when the actual memory the extern static resolves to is smaller / less aligned / less mutable / located at address 0. For `extern static` with `raw-dylib` linkage, the actual memory must have *exactly* the declared size. r[undefined.runtime] From 1f9bdca3e0121d60c54cf608f08723f92169cbaf Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 07:33:27 +0000 Subject: [PATCH 07/14] Say that extern statics resolve to *allocations* The new rules talked about "the actual memory" that an extern static resolves to. It'd be better to talk about the *allocation*, as the Reference already does elsewhere. Let's do that, and let's talk about allocations being *larger* rather than *bigger*. --- src/behavior-considered-undefined.md | 4 ++-- src/items/external-blocks.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 984a8123fb..039680ef15 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -62,8 +62,8 @@ r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. r[undefined.extern-static] -* Declaring an `extern static` with some size/alignment/mutability, when the actual memory the extern static resolves to is smaller / less aligned / less mutable / located at address 0. - For `extern static` with `raw-dylib` linkage, the actual memory must have *exactly* the declared size. +* Declaring an `extern static` with some size/alignment/mutability, when the allocation the extern static resolves to is smaller / less aligned / less mutable / located at address 0. + For `extern static` with `raw-dylib` linkage, the allocation must have *exactly* the declared size. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 922e321ff5..d06fa1d4dc 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,8 +75,8 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The actual memory that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared within the extern block. -If the actual memory is bigger, then it is permitted to access that extra memory. +The allocation that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared within the extern block. +If the allocation is larger, then it is permitted to access the extra bytes. r[items.extern.abi] ## ABI @@ -373,7 +373,7 @@ r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. r[items.extern.attributes.link.kind-raw-dylib.size] -Unlike regular external statics, a `raw-dylib` static is *not* allowed to be bigger than its declared size. The size needs to match exactly. +Unlike regular external statics, a `raw-dylib` static is *not* allowed to be larger than its declared size. The size needs to match exactly. r[items.extern.attributes.link.import_name_type] #### The `import_name_type` key From 9c315ea379088d4214df105ff0638d4cdf628507 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 11 Oct 2026 09:50:54 +0000 Subject: [PATCH 08/14] Remove emphasis in new extern static rules Every word in the Reference is important, so we generally don't emphasize words such as *exactly*, *at least*, and *not*. This helps us reserve emphasis for when we're defining a term. Let's remove the stray emphasis added in the new rules. --- src/behavior-considered-undefined.md | 2 +- src/items/external-blocks.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 039680ef15..8cc4dbf98e 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -63,7 +63,7 @@ r[undefined.asm] r[undefined.extern-static] * Declaring an `extern static` with some size/alignment/mutability, when the allocation the extern static resolves to is smaller / less aligned / less mutable / located at address 0. - For `extern static` with `raw-dylib` linkage, the allocation must have *exactly* the declared size. + For `extern static` with `raw-dylib` linkage, the allocation must have exactly the declared size. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index d06fa1d4dc..afb6087759 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,7 +75,7 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The allocation that the extern static resolves to [must have][extern-static-ub] *at least* the size and alignment of the type that it was declared within the extern block. +The allocation that the extern static resolves to [must have][extern-static-ub] at least the size and alignment of the type that it was declared within the extern block. If the allocation is larger, then it is permitted to access the extra bytes. r[items.extern.abi] @@ -373,7 +373,7 @@ r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. r[items.extern.attributes.link.kind-raw-dylib.size] -Unlike regular external statics, a `raw-dylib` static is *not* allowed to be larger than its declared size. The size needs to match exactly. +Unlike regular external statics, a `raw-dylib` static is not allowed to be larger than its declared size. The size needs to match exactly. r[items.extern.attributes.link.import_name_type] #### The `import_name_type` key From d1d36bd5ea5397b22257b4e682f180753c0a6419 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 07:33:27 +0000 Subject: [PATCH 09/14] Reword the extern static size rule Let's revise this rule to match the Reference's style and to fix where two prepositions had been mistakenly fused. --- src/items/external-blocks.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index afb6087759..8efd0a3f61 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,8 +75,7 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The allocation that the extern static resolves to [must have][extern-static-ub] at least the size and alignment of the type that it was declared within the extern block. -If the allocation is larger, then it is permitted to access the extra bytes. +The allocation that an extern static resolves to must have at least the size and alignment of the type it is declared with (see [undefined.extern-static]). If the allocation is larger, accessing the extra bytes is allowed. r[items.extern.abi] ## ABI @@ -473,7 +472,6 @@ Attributes on extern function parameters follow the same rules and restrictions [`verbatim` documentation for rustc]: ../../rustc/command-line-arguments.html#linking-modifiers-verbatim [`whole-archive` documentation for rustc]: ../../rustc/command-line-arguments.html#linking-modifiers-whole-archive [attributes]: ../attributes.md -[extern-static-ub]: ../behavior-considered-undefined.md#r-undefined.extern-static [functions]: functions.md [regular function parameters]: functions.md#attributes-on-function-parameters [statics]: static-items.md From 97eb32c675cf5ed4cdda5524846c0358f99ff5b0 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 07:33:27 +0000 Subject: [PATCH 10/14] Separate out the `raw-dylib` size UB rule Rather than appending the bit about `raw-dylib` to the `undefined.extern-static` UB rule, let's add a separate rule for this. This reads better and makes for better internal links. --- src/behavior-considered-undefined.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 8cc4dbf98e..1a1fe4c9f5 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -63,7 +63,9 @@ r[undefined.asm] r[undefined.extern-static] * Declaring an `extern static` with some size/alignment/mutability, when the allocation the extern static resolves to is smaller / less aligned / less mutable / located at address 0. - For `extern static` with `raw-dylib` linkage, the allocation must have exactly the declared size. + +r[undefined.extern-static-raw-dylib] +* Declaring an `extern static` imported with the [`raw-dylib` link kind] when the allocation it resolves to does not have the same size as the type it is declared with. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. @@ -224,3 +226,4 @@ r[undefined.validity.undef] [const-promoted]: destructors.md#constant-promotion [lifetime-extended]: destructors.md#temporary-lifetime-extension [zero-sized]: glossary.zst +[`raw-dylib` link kind]: items.extern.attributes.link.raw-dylib From 45d409764edb307140acdcc5376339ad4007bcd6 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 07:33:27 +0000 Subject: [PATCH 11/14] Reword the extern static UB entry The `undefined.extern-static` rule was leaning heavily on slashed lists. It's better to not do this. Let's revise editorially. --- src/behavior-considered-undefined.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 1a1fe4c9f5..820428da72 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -62,7 +62,7 @@ r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. r[undefined.extern-static] -* Declaring an `extern static` with some size/alignment/mutability, when the allocation the extern static resolves to is smaller / less aligned / less mutable / located at address 0. +* Declaring an `extern static` when the allocation it resolves to is located at address 0 or is smaller, less aligned, or less mutable than declared. r[undefined.extern-static-raw-dylib] * Declaring an `extern static` imported with the [`raw-dylib` link kind] when the allocation it resolves to does not have the same size as the type it is declared with. From 617bb2ac321ef4be71e5e4e0291c3de16d43bd9d Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 07:33:27 +0000 Subject: [PATCH 12/14] Clarify the `raw-dylib` size exception The rule talked about a static being larger than its declared size, but this is a bit loose. The static is always the size of its declared type. What might be a different size is the allocation. Let's revise to be more precise. And let's add an admonition on the `items.extern.static.size` rule pointing to this rule so the exception isn't missed. --- src/items/external-blocks.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 8efd0a3f61..154eae9391 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -77,6 +77,9 @@ An immutable static *must* be initialized before any Rust code is executed. It i r[items.extern.static.size] The allocation that an extern static resolves to must have at least the size and alignment of the type it is declared with (see [undefined.extern-static]). If the allocation is larger, accessing the extra bytes is allowed. +> [!NOTE] +> See [items.extern.attributes.link.kind-raw-dylib.size] for an exception to this rule. + r[items.extern.abi] ## ABI @@ -372,7 +375,7 @@ r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. r[items.extern.attributes.link.kind-raw-dylib.size] -Unlike regular external statics, a `raw-dylib` static is not allowed to be larger than its declared size. The size needs to match exactly. +Unlike other extern statics, a `raw-dylib` static must resolve to an allocation whose size is exactly that of the type it is declared with (see [undefined.extern-static-raw-dylib]). r[items.extern.attributes.link.import_name_type] #### The `import_name_type` key From 8d110a90e8fcd87e4c64dda68eae186752473fff Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 12 Oct 2026 06:44:07 +0000 Subject: [PATCH 13/14] Clarify allocations start at an extern static's address The bytes used for an extern static will often fall within a linker *section* that starts earlier. Let's clarify that the *allocation* starts at the address of the extern static. --- src/items/external-blocks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 154eae9391..4eef9c2a12 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -75,7 +75,7 @@ r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens to bytes inside of an `UnsafeCell`. r[items.extern.static.size] -The allocation that an extern static resolves to must have at least the size and alignment of the type it is declared with (see [undefined.extern-static]). If the allocation is larger, accessing the extra bytes is allowed. +An extern static resolves to an allocation that starts at the address of the static; the allocation must have at least the size and alignment of the type it is declared with (see [undefined.extern-static]). If the allocation is larger, accessing the extra bytes is allowed. > [!NOTE] > See [items.extern.attributes.link.kind-raw-dylib.size] for an exception to this rule. From d3a25893a404d2eb0928b05e585e8a825e505ba6 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 12 Oct 2026 09:02:26 +0000 Subject: [PATCH 14/14] Clarify that extern static allocations are disjoint That some extern statics may be used to access more bytes than would be implied by the size of their types does not imply that they may be used to access the bytes of other statics (with different symbols), even if those bytes are in the same linker section. Let's make this explicit. And since statics with the same symbol do resolve to the same allocation, let's add a rule making that explicit too. --- src/items/external-blocks.md | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 4eef9c2a12..20dd363db5 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -80,6 +80,102 @@ An extern static resolves to an allocation that starts at the address of the sta > [!NOTE] > See [items.extern.attributes.link.kind-raw-dylib.size] for an exception to this rule. +r[items.extern.static.same-symbol] +An extern static resolves to the same allocation as any other static with the same symbol. + +```rust +#[unsafe(no_mangle)] +static mut COUNTER: u8 = 0; + +unsafe extern "C" { + #[link_name = "COUNTER"] + static mut COUNTER_ALIAS: u8; +} + +fn main() { + unsafe { + COUNTER += 1; + COUNTER_ALIAS += 2; + // The two statics share one allocation. + assert!(COUNTER == COUNTER_ALIAS && COUNTER == 3); + assert!(&raw const COUNTER == &raw const COUNTER_ALIAS); + } +} +``` + +r[items.extern.static.allocations-disjoint] +The allocation that an extern static resolves to does not include the bytes of any static with a different symbol, even when the linker places the statics in the same section. + +> [!NOTE] +> A pointer to one allocation can't be used, via offsetting, to access bytes in a different allocation. Since statics with different symbols have different allocations, you can't use a pointer derived from one static to access the bytes of another static that has a different symbol. +> +> In particular, an extern static that marks the start of a linker section cannot be used to access statics with different symbols placed in that section. + +```rust,standalone_crate +// Bytes placed in a section without a static may be read through the +// section's start symbol. + +// Three bytes placed in a section named `entries`. +# #[cfg(target_os = "linux")] +core::arch::global_asm!( + ".pushsection entries,\"aR\"", // `R` is like `#[used]`. + ".byte 1, 2, 3", + ".popsection", +); + +# #[cfg(target_os = "linux")] +unsafe extern "C" { + // On ELF targets, the linker defines these symbols at the start + // and the end of the `entries` section. + static __start_entries: [u8; 0]; + static __stop_entries: [u8; 0]; +} + +fn main() { +# #[cfg(target_os = "linux")] { + let start = &raw const __start_entries as *const u8; + let len = (&raw const __stop_entries).addr() - start.addr(); + // The bytes of the section belong to no static, so they are part + // of the allocation that `__start_entries` resolves to. + let entries = unsafe { core::slice::from_raw_parts(start, len) }; + assert_eq!(entries, &[1, 2, 3]); +# } +} +``` + +```rust,standalone_crate +// A static placed in a section is an allocation of its own, which the +// section's start symbol cannot be used to read. + +// A static placed in a section named `entries`. +# #[cfg(target_os = "linux")] +#[used] +#[unsafe(link_section = "entries")] +static ENTRY: [u8; 3] = [1, 2, 3]; + +# #[cfg(target_os = "linux")] +unsafe extern "C" { + // On ELF targets, the linker defines these symbols at the start + // and the end of the `entries` section. + static __start_entries: [u8; 0]; + static __stop_entries: [u8; 0]; +} + +fn main() { +# #[cfg(target_os = "linux")] { + let start = &raw const __start_entries as *const u8; + let stop = &raw const __stop_entries as *const u8; + // The section holds exactly the bytes of `ENTRY`. + assert_eq!(stop.addr() - start.addr(), 3); + assert_eq!(start.addr(), (&raw const ENTRY).addr()); + // But those bytes are the allocation of `ENTRY`, not of + // `__start_entries`, so reading them through `start` is undefined + // behavior. + //let x = unsafe { *start }; // UB. +# } +} +``` + r[items.extern.abi] ## ABI