mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 01:34:21 +00:00
Do not allow LLVM to increase a TLS's alignment on macOS.
This commit is contained in:
parent
3b50455c61
commit
e3d113eca9
@ -250,7 +250,7 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
unsafe {
|
||||
let g = get_static(cx, def_id);
|
||||
|
||||
let v = match ::mir::codegen_static_initializer(cx, def_id) {
|
||||
let (v, alloc) = match ::mir::codegen_static_initializer(cx, def_id) {
|
||||
Ok(v) => v,
|
||||
// Error has already been reported
|
||||
Err(_) => return,
|
||||
@ -309,6 +309,44 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
||||
if attr::contains_name(attrs, "thread_local") {
|
||||
llvm::set_thread_local_mode(g, cx.tls_model);
|
||||
|
||||
// Do not allow LLVM to change the alignment of a TLS on macOS.
|
||||
//
|
||||
// By default a global's alignment can be freely increased.
|
||||
// This allows LLVM to generate more performant instructions
|
||||
// e.g. using load-aligned into a SIMD register.
|
||||
//
|
||||
// However, on macOS 10.10 or below, the dynamic linker does not
|
||||
// respect any alignment given on the TLS (radar 24221680).
|
||||
// This will violate the alignment assumption, and causing segfault at runtime.
|
||||
//
|
||||
// This bug is very easy to trigger. In `println!` and `panic!`,
|
||||
// the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
|
||||
// which the values would be `mem::replace`d on initialization.
|
||||
// The implementation of `mem::replace` will use SIMD
|
||||
// whenever the size is 32 bytes or higher. LLVM notices SIMD is used
|
||||
// and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
|
||||
// which macOS's dyld disregarded and causing crashes
|
||||
// (see issues #51794, #51758, #50867, #48866 and #44056).
|
||||
//
|
||||
// To workaround the bug, we trick LLVM into not increasing
|
||||
// the global's alignment by explicitly assigning a section to it
|
||||
// (equivalent to automatically generating a `#[link_section]` attribute).
|
||||
// See the comment in the `GlobalValue::canIncreaseAlignment()` function
|
||||
// of `lib/IR/Globals.cpp` for why this works.
|
||||
//
|
||||
// When the alignment is not increased, the optimized `mem::replace`
|
||||
// will use load-unaligned instructions instead, and thus avoiding the crash.
|
||||
//
|
||||
// We could remove this hack whenever we decide to drop macOS 10.10 support.
|
||||
if cx.tcx.sess.target.target.options.is_like_osx {
|
||||
let sect_name = if alloc.bytes.iter().all(|b| *b == 0) {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
|
||||
} else {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
|
||||
};
|
||||
llvm::LLVMSetSection(g, sect_name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
base::set_link_section(cx, g, attrs);
|
||||
|
@ -118,7 +118,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
|
||||
pub fn codegen_static_initializer<'a, 'tcx>(
|
||||
cx: &CodegenCx<'a, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> Result<ValueRef, Lrc<ConstEvalErr<'tcx>>>
|
||||
-> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>>
|
||||
{
|
||||
let instance = ty::Instance::mono(cx.tcx, def_id);
|
||||
let cid = GlobalId {
|
||||
@ -132,7 +132,7 @@ pub fn codegen_static_initializer<'a, 'tcx>(
|
||||
ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
|
||||
_ => bug!("static const eval returned {:#?}", static_),
|
||||
};
|
||||
Ok(const_alloc_to_llvm(cx, alloc))
|
||||
Ok((const_alloc_to_llvm(cx, alloc), alloc))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
|
40
src/test/codegen/issue-44056-macos-tls-align.rs
Normal file
40
src/test/codegen/issue-44056-macos-tls-align.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
// only-macos
|
||||
// no-system-llvm
|
||||
// min-llvm-version 6.0
|
||||
// compile-flags: -O
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(thread_local)]
|
||||
|
||||
// CHECK: @STATIC_VAR_1 = internal thread_local unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
|
||||
#[no_mangle]
|
||||
#[allow(private_no_mangle_statics)]
|
||||
#[thread_local]
|
||||
static mut STATIC_VAR_1: [u32; 8] = [0; 8];
|
||||
|
||||
// CHECK: @STATIC_VAR_2 = internal thread_local unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
|
||||
#[no_mangle]
|
||||
#[allow(private_no_mangle_statics)]
|
||||
#[thread_local]
|
||||
static mut STATIC_VAR_2: [u32; 8] = [4; 8];
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn f(x: &mut [u32; 8]) {
|
||||
std::mem::swap(x, &mut STATIC_VAR_1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn g(x: &mut [u32; 8]) {
|
||||
std::mem::swap(x, &mut STATIC_VAR_2)
|
||||
}
|
15
src/test/run-pass/issue-44056.rs
Normal file
15
src/test/run-pass/issue-44056.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// only-x86_64
|
||||
// no-prefer-dynamic
|
||||
// compile-flags: -Ctarget-feature=+avx -Clto
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user