Skip to content

Commit c08b9ab

Browse files
committed
validate link name parameter
specifically, do not allow NULL bytes and the empty string
1 parent 68ffae4 commit c08b9ab

6 files changed

Lines changed: 146 additions & 25 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::session_diagnostics::{
1717
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1818
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
1919
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
20-
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
20+
LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection, RawDylibOnlyWindows,
2121
WholeArchiveNeedsStatic,
2222
};
2323

@@ -46,6 +46,19 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
4646
return None;
4747
};
4848

49+
if name.as_str().contains('\0') {
50+
// `#[link_name = ...]` will be converted to a null-terminated string,
51+
// so it may not contain any null characters.
52+
cx.emit_err(NullOnLinkName { span: nv.value_span });
53+
return None;
54+
}
55+
if name.is_empty() {
56+
// Otherwise LLVM will just make up a name and the linker will fail
57+
// to find an empty symbol name.
58+
cx.emit_err(EmptyLinkName { span: nv.value_span });
59+
return None;
60+
}
61+
4962
Some(LinkName { name, span: cx.attr_span })
5063
}
5164
}
@@ -222,7 +235,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
222235
if wasm_import_module.is_some() {
223236
(name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
224237
}
225-
let Some((name, name_span)) = name else {
238+
let Some((name, _name_span)) = name else {
226239
cx.emit_err(LinkRequiresName { span: cx.attr_span });
227240
return None;
228241
};
@@ -234,12 +247,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
234247
}
235248
}
236249

237-
if let Some(NativeLibKind::RawDylib { .. }) = kind
238-
&& name.as_str().contains('\0')
239-
{
240-
cx.emit_err(RawDylibNoNul { span: name_span });
241-
}
242-
243250
Some(LinkEntry {
244251
span: cx.attr_span,
245252
kind: kind.unwrap_or(NativeLibKind::Unspecified),
@@ -270,9 +277,13 @@ impl LinkParser {
270277
return false;
271278
};
272279

280+
if link_name.as_str().contains('\0') {
281+
cx.emit_err(NullOnLinkName { span: nv.value_span });
282+
}
273283
if link_name.is_empty() {
274284
cx.emit_err(EmptyLinkName { span: nv.value_span });
275285
}
286+
276287
*name = Some((link_name, nv.value_span));
277288
true
278289
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,13 @@ pub(crate) struct NullOnLinkSection {
410410
pub span: Span,
411411
}
412412

413+
#[derive(Diagnostic)]
414+
#[diag("link name may not contain null characters", code = E0648)]
415+
pub(crate) struct NullOnLinkName {
416+
#[primary_span]
417+
pub span: Span,
418+
}
419+
413420
#[derive(Diagnostic)]
414421
#[diag("`objc::class!` may not contain null characters")]
415422
pub(crate) struct NullOnObjcClass {
@@ -984,13 +991,6 @@ pub(crate) struct LinkRequiresName {
984991
pub span: Span,
985992
}
986993

987-
#[derive(Diagnostic)]
988-
#[diag("link name must not contain NUL characters if link kind is `raw-dylib`")]
989-
pub(crate) struct RawDylibNoNul {
990-
#[primary_span]
991-
pub span: Span,
992-
}
993-
994994
#[derive(Diagnostic)]
995995
#[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)]
996996
pub(crate) struct RawDylibOnlyWindows {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#![crate_type = "lib"]
2+
3+
#[link(name = "")]
4+
//~^ ERROR link name must not be empty
5+
unsafe extern "C" {
6+
#[link_name = ""]
7+
//~^ ERROR link name must not be empty
8+
safe fn empty();
9+
}
10+
11+
#[link(name = " ")]
12+
unsafe extern "C" {
13+
#[link_name = " "]
14+
safe fn this_is_fine();
15+
}
16+
17+
#[export_name = " "]
18+
extern "C" fn bar() -> i32 {
19+
42
20+
}
21+
22+
#[link(name = "\0")]
23+
//~^ ERROR link name may not contain null characters
24+
unsafe extern "C" {}
25+
26+
#[link(name = "foo\0")]
27+
//~^ ERROR link name may not contain null characters
28+
unsafe extern "C" {}
29+
30+
#[link(name = "\0foo")]
31+
//~^ ERROR link name may not contain null characters
32+
unsafe extern "C" {}
33+
34+
#[link(name = "fo\0o")]
35+
//~^ ERROR link name may not contain null characters
36+
unsafe extern "C" {}
37+
38+
unsafe extern "C" {
39+
#[link_name = "\0"]
40+
//~^ ERROR link name may not contain null characters
41+
safe fn empty_null();
42+
43+
#[link_name = "foo\0"]
44+
//~^ ERROR link name may not contain null characters
45+
safe fn trailing_null();
46+
47+
#[link_name = "\0foo"]
48+
//~^ ERROR link name may not contain null characters
49+
safe fn leading_null();
50+
51+
#[link_name = "fo\0o"]
52+
//~^ ERROR link name may not contain null characters
53+
safe fn middle_null();
54+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
error[E0454]: link name must not be empty
2+
--> $DIR/invalid-link-name.rs:3:15
3+
|
4+
LL | #[link(name = "")]
5+
| ^^ empty link name
6+
7+
error[E0454]: link name must not be empty
8+
--> $DIR/invalid-link-name.rs:6:19
9+
|
10+
LL | #[link_name = ""]
11+
| ^^ empty link name
12+
13+
error[E0648]: link name may not contain null characters
14+
--> $DIR/invalid-link-name.rs:22:15
15+
|
16+
LL | #[link(name = "\0")]
17+
| ^^^^
18+
19+
error[E0648]: link name may not contain null characters
20+
--> $DIR/invalid-link-name.rs:26:15
21+
|
22+
LL | #[link(name = "foo\0")]
23+
| ^^^^^^^
24+
25+
error[E0648]: link name may not contain null characters
26+
--> $DIR/invalid-link-name.rs:30:15
27+
|
28+
LL | #[link(name = "\0foo")]
29+
| ^^^^^^^
30+
31+
error[E0648]: link name may not contain null characters
32+
--> $DIR/invalid-link-name.rs:34:15
33+
|
34+
LL | #[link(name = "fo\0o")]
35+
| ^^^^^^^
36+
37+
error[E0648]: link name may not contain null characters
38+
--> $DIR/invalid-link-name.rs:39:19
39+
|
40+
LL | #[link_name = "\0"]
41+
| ^^^^
42+
43+
error[E0648]: link name may not contain null characters
44+
--> $DIR/invalid-link-name.rs:43:19
45+
|
46+
LL | #[link_name = "foo\0"]
47+
| ^^^^^^^
48+
49+
error[E0648]: link name may not contain null characters
50+
--> $DIR/invalid-link-name.rs:47:19
51+
|
52+
LL | #[link_name = "\0foo"]
53+
| ^^^^^^^
54+
55+
error[E0648]: link name may not contain null characters
56+
--> $DIR/invalid-link-name.rs:51:19
57+
|
58+
LL | #[link_name = "fo\0o"]
59+
| ^^^^^^^
60+
61+
error: aborting due to 10 previous errors
62+
63+
Some errors have detailed explanations: E0454, E0648.
64+
For more information about an error, try `rustc --explain E0454`.

tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ unsafe extern "C" {
1111
pub safe fn exit_0(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
1212
#[link_name = "@GLIBC_2.2.5"]
1313
pub safe fn exit_1(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
14-
#[link_name = "ex\0it@GLIBC_2.2.5"]
15-
pub safe fn exit_2(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
1614
#[link_name = "exit@@GLIBC_2.2.5"]
17-
pub safe fn exit_3(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
15+
pub safe fn exit_2(status: i32) -> !; //~ ERROR link name must be well-formed if link kind is `raw-dylib`
1816
}
1917

2018
fn main() {}

tests/ui/linkage-attr/raw-dylib/elf/malformed-link-name.stderr

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,5 @@ error: link name must be well-formed if link kind is `raw-dylib`
1616
LL | pub safe fn exit_2(status: i32) -> !;
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818

19-
error: link name must be well-formed if link kind is `raw-dylib`
20-
--> $DIR/malformed-link-name.rs:17:5
21-
|
22-
LL | pub safe fn exit_3(status: i32) -> !;
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24-
25-
error: aborting due to 4 previous errors
19+
error: aborting due to 3 previous errors
2620

0 commit comments

Comments
 (0)