Skip to content

Commit a4f5c6e

Browse files
committed
error on invalid macho section specifier
1 parent fb76025 commit a4f5c6e

28 files changed

Lines changed: 288 additions & 129 deletions

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ use crate::attributes::cfg::parse_cfg_entry;
1616
use crate::session_diagnostics::{
1717
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1818
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
19-
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
20-
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
19+
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
20+
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
21+
WholeArchiveNeedsStatic,
2122
};
2223

2324
pub(crate) struct LinkNameParser;
@@ -462,6 +463,29 @@ impl LinkParser {
462463

463464
pub(crate) struct LinkSectionParser;
464465

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

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

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,3 +1137,22 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
11371137
#[label("the stability attribute annotates this item")]
11381138
pub item_span: Span,
11391139
}
1140+
1141+
#[derive(Diagnostic)]
1142+
#[diag("invalid Mach-O section specifier")]
1143+
pub(crate) struct InvalidMachoSection {
1144+
#[primary_span]
1145+
#[label("not a valid Mach-O section specifier")]
1146+
pub name_span: Span,
1147+
#[subdiagnostic]
1148+
pub reason: InvalidMachoSectionReason,
1149+
}
1150+
1151+
#[derive(Subdiagnostic)]
1152+
pub(crate) enum InvalidMachoSectionReason {
1153+
#[note("a Mach-O section specifier requires a segment and a section, separated by a comma")]
1154+
#[help("an example of a valid Mach-O section specifier is `__TEXT,__cstring`")]
1155+
MissingSection,
1156+
#[note("section name `{$section}` is longer than 16 bytes")]
1157+
SectionTooLong { section: String },
1158+
}

compiler/rustc_hir/src/attrs/data_structures.rs

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

10991099
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
11001100
LinkSection {
1101-
name: Symbol,
11021101
span: Span,
1102+
name: Symbol,
11031103
},
11041104

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

tests/codegen-llvm/link_section.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
#![crate_type = "lib"]
55

6-
// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one"
6+
// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section "__TEST,one"
77
#[no_mangle]
8-
#[link_section = ".test_one"]
8+
#[link_section = "__TEST,one"]
99
#[cfg(target_endian = "little")]
1010
pub static VAR1: u32 = 1;
1111

1212
#[no_mangle]
13-
#[link_section = ".test_one"]
13+
#[link_section = "__TEST,one"]
1414
#[cfg(target_endian = "big")]
1515
pub static VAR1: u32 = 0x01000000;
1616

@@ -19,17 +19,17 @@ pub enum E {
1919
B(f32),
2020
}
2121

22-
// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two"
22+
// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section "__TEST,two"
2323
#[no_mangle]
24-
#[link_section = ".test_two"]
24+
#[link_section = "__TEST,two"]
2525
pub static VAR2: E = E::A(666);
2626

27-
// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three"
27+
// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section "__TEST,three"
2828
#[no_mangle]
29-
#[link_section = ".test_three"]
29+
#[link_section = "__TEST,three"]
3030
pub static VAR3: E = E::B(1.);
3131

32-
// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" {
32+
// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section "__TEST,four" {
3333
#[no_mangle]
34-
#[link_section = ".test_four"]
34+
#[link_section = "__TEST,four"]
3535
pub fn fn1() {}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
//@[thumb] needs-llvm-components: arm
2323

2424
#![crate_type = "lib"]
25-
#![feature(no_core, lang_items, rustc_attrs)]
25+
#![feature(no_core, lang_items, rustc_attrs, cfg_target_object_format)]
2626
#![no_core]
2727

2828
extern crate minicore;
@@ -170,14 +170,17 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
170170
}
171171

172172
// linux,linux_no_function_sections: .pushsection .text.some_different_name,\22ax\22, @progbits
173-
// macos: .pushsection .text.some_different_name,regular,pure_instructions
173+
// macos: .pushsection __TEXT,different,regular,pure_instructions
174174
// win_x86_msvc,win_x86_gnu,win_i686_gnu: .section .text.some_different_name,\22xr\22
175175
// win_x86_gnu_function_sections: .section .text.some_different_name,\22xr\22
176176
// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits
177177
// CHECK-LABEL: test_link_section:
178178
#[no_mangle]
179179
#[unsafe(naked)]
180-
#[link_section = ".text.some_different_name"]
180+
#[link_section = cfg_select!(
181+
target_object_format = "mach-o" => "__TEXT,different",
182+
_ => ".text.some_different_name"
183+
)]
181184
pub extern "C" fn test_link_section() {
182185
cfg_select! {
183186
all(target_arch = "arm", target_feature = "thumb-mode") => {

tests/rustdoc-html/attributes-2021-edition.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ pub extern "C" fn f() {}
99
#[export_name = "bar"]
1010
pub extern "C" fn g() {}
1111

12-
//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]'
13-
#[link_section = ".text"]
12+
//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = "__TEXT,__text")]'
13+
#[link_section = "__TEXT,__text"]
1414
pub extern "C" fn example() {}

tests/rustdoc-html/attributes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@ edition: 2024
2+
//@ only-linux
23
#![crate_name = "foo"]
34

45
//@ has foo/fn.f.html '//*[@class="code-attribute"]' '#[unsafe(no_mangle)]'

tests/rustdoc-html/inline_cross/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
pub use attributes::no_mangle;
1010

1111
//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \
12-
// '#[unsafe(link_section = ".here")]'
12+
// '#[unsafe(link_section = "__TEXT,__here")]'
1313
pub use attributes::link_section;
1414

1515
//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \

tests/rustdoc-html/inline_cross/auxiliary/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[unsafe(no_mangle)]
22
pub fn no_mangle() {}
33

4-
#[unsafe(link_section = ".here")]
4+
#[unsafe(link_section = "__TEXT,__here")]
55
pub fn link_section() {}
66

77
#[unsafe(export_name = "exonym")]

tests/rustdoc-json/attrs/link_section_2021.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
#![no_std]
33

44
//@ count "$.index[?(@.name=='example')].attrs[*]" 1
5-
//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"'
6-
#[link_section = ".text"]
5+
//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '"__TEXT,__text"'
6+
#[link_section = "__TEXT,__text"]
77
pub extern "C" fn example() {}

0 commit comments

Comments
 (0)