Skip to content

Commit 30b9c6e

Browse files
committed
error on invalid macho section specifier
1 parent 1fe72d3 commit 30b9c6e

6 files changed

Lines changed: 158 additions & 5 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use crate::attributes::cfg::parse_cfg_entry;
1414
use crate::session_diagnostics::{
1515
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1616
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
17-
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
18-
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
17+
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
18+
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
19+
WholeArchiveNeedsStatic,
1920
};
2021

2122
pub(crate) struct LinkNameParser;
@@ -465,6 +466,29 @@ impl LinkParser {
465466

466467
pub(crate) struct LinkSectionParser;
467468

469+
fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
470+
let mut parts = name.as_str().split(',').map(|s| s.trim());
471+
472+
// The segment can be empty.
473+
let _segment = parts.next();
474+
475+
// But the section is required.
476+
let section = match parts.next() {
477+
None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
478+
Some(section) => section,
479+
};
480+
481+
if section.len() > 16 {
482+
return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
483+
}
484+
485+
// LLVM also checks the other components of the section specifier, but that logic is hard to
486+
// keep in sync. We skip it here for now, assuming that if you got that far you'll be able
487+
// to interpret the LLVM errors.
488+
489+
Ok(())
490+
}
491+
468492
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
469493
const PATH: &[Symbol] = &[sym::link_section];
470494
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
@@ -497,6 +521,18 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
497521
return None;
498522
}
499523

524+
// We (currently) only validate macho section specifiers.
525+
match cx.sess.target.binary_format {
526+
BinaryFormat::MachO => match check_link_section_macho(name) {
527+
Ok(()) => {}
528+
Err(reason) => {
529+
cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
530+
return None;
531+
}
532+
},
533+
BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
534+
}
535+
500536
Some(LinkSection { name, span: cx.attr_span })
501537
}
502538
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,3 +1149,22 @@ pub(crate) struct UnknownToolInScopedLint {
11491149
#[help("add `#![register_tool({$tool_name})]` to the crate root")]
11501150
pub is_nightly_build: bool,
11511151
}
1152+
1153+
#[derive(Diagnostic)]
1154+
#[diag("invalid macho section specifier")]
1155+
pub(crate) struct InvalidMachoSection {
1156+
#[primary_span]
1157+
#[label("not a valid macho section specifier")]
1158+
pub name_span: Span,
1159+
#[subdiagnostic]
1160+
pub reason: InvalidMachoSectionReason,
1161+
}
1162+
1163+
#[derive(Subdiagnostic)]
1164+
pub(crate) enum InvalidMachoSectionReason {
1165+
#[note("a macho section specifier requires a segment and a section, separated by a comma")]
1166+
#[help("an example of a valid macho section specifier is `__TEXT,__cstring`")]
1167+
MissingSection,
1168+
#[note("section name `{$section}` is longer than 16 bytes")]
1169+
SectionTooLong { section: String },
1170+
}

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1229,8 +1229,8 @@ pub enum AttributeKind {
12291229

12301230
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
12311231
LinkSection {
1232-
name: Symbol,
12331232
span: Span,
1233+
name: Symbol,
12341234
},
12351235

12361236
/// Represents `#[linkage]`.

tests/codegen-llvm/naked-fn/naked-functions.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,16 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
145145
}
146146

147147
// linux: .pushsection .text.some_different_name,\22ax\22, @progbits
148-
// macos: .pushsection .text.some_different_name,regular,pure_instructions
148+
// macos: .pushsection __TEXT,different,regular,pure_instructions
149149
// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22
150150
// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits
151151
// CHECK-LABEL: test_link_section:
152152
#[no_mangle]
153153
#[unsafe(naked)]
154-
#[link_section = ".text.some_different_name"]
154+
// FIXME: configure this with `cfg(target_binary_format = "mach-o")`,
155+
// see https://github.com/rust-lang/rust/issues/152586.
156+
#[cfg_attr(not(target_vendor = "apple"), link_section = ".text.some_different_name")]
157+
#[cfg_attr(target_vendor = "apple", link_section = "__TEXT,different")]
155158
pub extern "C" fn test_link_section() {
156159
cfg_select! {
157160
all(target_arch = "arm", target_feature = "thumb-mode") => {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//@ add-minicore
2+
//@ compile-flags: --target aarch64-apple-darwin
3+
//@ needs-llvm-components: aarch64
4+
//@ ignore-backends: gcc
5+
#![feature(no_core, rustc_attrs, lang_items)]
6+
#![no_core]
7+
#![crate_type = "lib"]
8+
9+
extern crate minicore;
10+
use minicore::*;
11+
12+
#[unsafe(link_section = "foo")]
13+
//~^ ERROR invalid macho section specifier
14+
#[unsafe(no_mangle)]
15+
fn missing_section() {}
16+
17+
#[unsafe(link_section = "foo,")]
18+
//~^ ERROR invalid macho section specifier
19+
#[unsafe(no_mangle)]
20+
fn empty_section() {}
21+
22+
#[unsafe(link_section = "foo, ")]
23+
//~^ ERROR invalid macho section specifier
24+
#[unsafe(no_mangle)]
25+
fn whitespace_section() {}
26+
27+
#[unsafe(link_section = "foo,somelongwindedthing")]
28+
//~^ ERROR invalid macho section specifier
29+
#[unsafe(no_mangle)]
30+
fn section_too_long() {}
31+
32+
#[unsafe(link_section = "foo,bar")]
33+
#[unsafe(no_mangle)]
34+
fn segment_and_section() {}
35+
36+
#[unsafe(link_section = "foo,bar,")]
37+
#[unsafe(no_mangle)]
38+
fn segment_and_section_and_comma() {}
39+
40+
#[unsafe(link_section = ",foo")]
41+
#[unsafe(no_mangle)]
42+
fn missing_segment_is_fine() {}
43+
44+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,16")]
45+
#[unsafe(no_mangle)]
46+
fn stub_size_decimal() {}
47+
48+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,0x10")]
49+
#[unsafe(no_mangle)]
50+
fn stub_size_hex() {}
51+
52+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020")]
53+
#[unsafe(no_mangle)]
54+
fn stub_size_oct() {}
55+
56+
#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020,rest,is,ignored")]
57+
#[unsafe(no_mangle)]
58+
fn rest_is_ignored() {}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error: invalid macho section specifier
2+
--> $DIR/link-section-macho.rs:12:25
3+
|
4+
LL | #[unsafe(link_section = "foo")]
5+
| ^^^^^ not a valid macho section specifier
6+
|
7+
= note: a macho section specifier requires a segment and a section, separated by a comma
8+
= help: an example of a valid macho section specifier is `__TEXT,__cstring`
9+
10+
error: invalid macho section specifier
11+
--> $DIR/link-section-macho.rs:17:25
12+
|
13+
LL | #[unsafe(link_section = "foo,")]
14+
| ^^^^^^ not a valid macho section specifier
15+
|
16+
= note: a macho section specifier requires a segment and a section, separated by a comma
17+
= help: an example of a valid macho section specifier is `__TEXT,__cstring`
18+
19+
error: invalid macho section specifier
20+
--> $DIR/link-section-macho.rs:22:25
21+
|
22+
LL | #[unsafe(link_section = "foo, ")]
23+
| ^^^^^^^ not a valid macho section specifier
24+
|
25+
= note: a macho section specifier requires a segment and a section, separated by a comma
26+
= help: an example of a valid macho section specifier is `__TEXT,__cstring`
27+
28+
error: invalid macho section specifier
29+
--> $DIR/link-section-macho.rs:27:25
30+
|
31+
LL | #[unsafe(link_section = "foo,somelongwindedthing")]
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a valid macho section specifier
33+
|
34+
= note: section name `somelongwindedthing` is longer than 16 bytes
35+
36+
error: aborting due to 4 previous errors
37+

0 commit comments

Comments
 (0)