Skip to content

Commit 6b93655

Browse files
authored
Rollup merge of #155515 - folkertdev:export-name-not-empty, r=jdonszelmann
error on empty `export_name` fixes #155495 Using an empty string as the name makes LLVM make up a name. However this name can be inconsistent between compilation units, which is UB and can cause linking errors, and some parts of LLVM just crash on the empty name (see the linked issue). As far as we know there is only one valid pattern that could use this, a `#[used]` static that is not referenced by the program at all. That is not UB, but the `export_name` is not required for that to work, just normal rust name mangling would do fine. Technically this is a breaking change, but it seems unlikely that this actually breaks code in the wild that wasn't already broken. I'll leave it up to T-lang to determine what is required here (crater run, FCW, ...), but my gut feeling is that we could just merge this and nobody would notice.
2 parents dd0746b + d0ea88e commit 6b93655

4 files changed

Lines changed: 71 additions & 2 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use rustc_span::edition::Edition::Edition2024;
55
use super::prelude::*;
66
use crate::attributes::AttributeSafety;
77
use crate::session_diagnostics::{
8-
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
9-
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
8+
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
9+
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
1010
};
1111
use crate::target_checking::Policy::AllowSilent;
1212

@@ -129,6 +129,12 @@ impl SingleAttributeParser for ExportNameParser {
129129
cx.emit_err(NullOnExport { span: cx.attr_span });
130130
return None;
131131
}
132+
if name.is_empty() {
133+
// LLVM will make up a name if the empty string is given, but that name will be
134+
// inconsistent between compilation units, causing linker errors.
135+
cx.emit_err(EmptyExportName { span: cx.attr_span });
136+
return None;
137+
}
132138
Some(AttributeKind::ExportName { name, span: cx.attr_span })
133139
}
134140
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,13 @@ pub(crate) struct UnusedMultiple {
396396
pub name: Symbol,
397397
}
398398

399+
#[derive(Diagnostic)]
400+
#[diag("`export_name` may not be empty")]
401+
pub(crate) struct EmptyExportName {
402+
#[primary_span]
403+
pub span: Span,
404+
}
405+
399406
#[derive(Diagnostic)]
400407
#[diag("`export_name` may not contain null characters", code = E0648)]
401408
pub(crate) struct NullOnExport {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![crate_type = "lib"]
2+
3+
#[export_name = "\0foo"]
4+
//~^ ERROR `export_name` may not contain null characters
5+
fn has_null_byte() {}
6+
7+
#[export_name = "foo\0"]
8+
//~^ ERROR `export_name` may not contain null characters
9+
fn null_terminated() {}
10+
11+
#[export_name = "\0"]
12+
//~^ ERROR `export_name` may not contain null characters
13+
fn empty_null() {}
14+
15+
#[export_name = ""]
16+
//~^ ERROR `export_name` may not be empty
17+
fn empty() {}
18+
19+
#[export_name = "\
20+
"]
21+
//~^^ ERROR `export_name` may not be empty
22+
fn empty_newline() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error[E0648]: `export_name` may not contain null characters
2+
--> $DIR/invalid-export-name.rs:3:1
3+
|
4+
LL | #[export_name = "\0foo"]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0648]: `export_name` may not contain null characters
8+
--> $DIR/invalid-export-name.rs:7:1
9+
|
10+
LL | #[export_name = "foo\0"]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0648]: `export_name` may not contain null characters
14+
--> $DIR/invalid-export-name.rs:11:1
15+
|
16+
LL | #[export_name = "\0"]
17+
| ^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: `export_name` may not be empty
20+
--> $DIR/invalid-export-name.rs:15:1
21+
|
22+
LL | #[export_name = ""]
23+
| ^^^^^^^^^^^^^^^^^^^
24+
25+
error: `export_name` may not be empty
26+
--> $DIR/invalid-export-name.rs:19:1
27+
|
28+
LL | / #[export_name = "\
29+
LL | | "]
30+
| |__^
31+
32+
error: aborting due to 5 previous errors
33+
34+
For more information about this error, try `rustc --explain E0648`.

0 commit comments

Comments
 (0)