Skip to content

Commit 3409ca6

Browse files
committed
Add OwnedTargetMachine to manage llvm:TargetMachine. Uses pointers
instead of &'static mut and provides safe interface to create/dispose it.
1 parent fc61fab commit 3409ca6

File tree

7 files changed

+148
-40
lines changed

7 files changed

+148
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::{
2+
ffi::{c_char, CStr},
3+
marker::PhantomData,
4+
ops::Deref,
5+
ptr::NonNull,
6+
};
7+
8+
use rustc_data_structures::small_c_str::SmallCStr;
9+
10+
use crate::{errors::LlvmError, llvm};
11+
12+
/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
13+
/// Not cloneable as there is no clone function for llvm::TargetMachine.
14+
#[repr(transparent)]
15+
pub struct OwnedTargetMachine {
16+
tm_unique: NonNull<llvm::TargetMachine>,
17+
phantom: PhantomData<llvm::TargetMachine>,
18+
}
19+
20+
impl OwnedTargetMachine {
21+
pub fn new(
22+
triple: &CStr,
23+
cpu: &CStr,
24+
features: &CStr,
25+
abi: &CStr,
26+
model: llvm::CodeModel,
27+
reloc: llvm::RelocModel,
28+
level: llvm::CodeGenOptLevel,
29+
use_soft_fp: bool,
30+
function_sections: bool,
31+
data_sections: bool,
32+
unique_section_names: bool,
33+
trap_unreachable: bool,
34+
singletree: bool,
35+
asm_comments: bool,
36+
emit_stack_size_section: bool,
37+
relax_elf_relocations: bool,
38+
use_init_array: bool,
39+
split_dwarf_file: &CStr,
40+
debug_info_compression: &CStr,
41+
force_emulated_tls: bool,
42+
args_cstr_buff: &[u8],
43+
) -> Result<Self, LlvmError<'static>> {
44+
assert!(args_cstr_buff.len() > 0);
45+
assert!(
46+
*args_cstr_buff.last().unwrap() == 0,
47+
"The last character must be a null terminator."
48+
);
49+
50+
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
51+
let tm_ptr = unsafe {
52+
llvm::LLVMRustCreateTargetMachine(
53+
triple.as_ptr(),
54+
cpu.as_ptr(),
55+
features.as_ptr(),
56+
abi.as_ptr(),
57+
model,
58+
reloc,
59+
level,
60+
use_soft_fp,
61+
function_sections,
62+
data_sections,
63+
unique_section_names,
64+
trap_unreachable,
65+
singletree,
66+
asm_comments,
67+
emit_stack_size_section,
68+
relax_elf_relocations,
69+
use_init_array,
70+
split_dwarf_file.as_ptr(),
71+
debug_info_compression.as_ptr(),
72+
force_emulated_tls,
73+
args_cstr_buff.as_ptr() as *const c_char,
74+
args_cstr_buff.len(),
75+
)
76+
};
77+
78+
NonNull::new(tm_ptr)
79+
.map(|tm_unique| Self { tm_unique, phantom: PhantomData })
80+
.ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
81+
}
82+
}
83+
84+
impl Deref for OwnedTargetMachine {
85+
type Target = llvm::TargetMachine;
86+
87+
fn deref(&self) -> &Self::Target {
88+
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
89+
unsafe { self.tm_unique.as_ref() }
90+
}
91+
}
92+
93+
impl Drop for OwnedTargetMachine {
94+
fn drop(&mut self) {
95+
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
96+
// OwnedTargetMachine is not copyable so there is no double free or use after free
97+
unsafe {
98+
llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut());
99+
}
100+
}
101+
}

compiler/rustc_codegen_llvm/src/back/write.rs

+26-30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::back::lto::ThinBuffer;
2+
use crate::back::owned_target_machine::OwnedTargetMachine;
23
use crate::back::profiling::{
34
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
45
};
@@ -98,7 +99,7 @@ pub fn write_output_file<'ll>(
9899
}
99100
}
100101

101-
pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
102+
pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
102103
let config = TargetMachineFactoryConfig { split_dwarf_file: None };
103104
// Can't use query system here quite yet because this function is invoked before the query
104105
// system/tcx is set up.
@@ -107,7 +108,7 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
107108
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
108109
}
109110

110-
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
111+
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine {
111112
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
112113
tcx.output_filenames(()).split_dwarf_path(
113114
tcx.sess.split_debuginfo(),
@@ -259,34 +260,29 @@ pub fn target_machine_factory(
259260
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
260261
let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
261262

262-
let tm = unsafe {
263-
llvm::LLVMRustCreateTargetMachine(
264-
triple.as_ptr(),
265-
cpu.as_ptr(),
266-
features.as_ptr(),
267-
abi.as_ptr(),
268-
code_model,
269-
reloc_model,
270-
opt_level,
271-
use_softfp,
272-
ffunction_sections,
273-
fdata_sections,
274-
funique_section_names,
275-
trap_unreachable,
276-
singlethread,
277-
asm_comments,
278-
emit_stack_size_section,
279-
relax_elf_relocations,
280-
use_init_array,
281-
split_dwarf_file.as_ptr(),
282-
debuginfo_compression.as_ptr(),
283-
force_emulated_tls,
284-
args_cstr_buff.as_ptr() as *const c_char,
285-
args_cstr_buff.len(),
286-
)
287-
};
288-
289-
tm.ok_or_else(|| LlvmError::CreateTargetMachine { triple: triple.clone() })
263+
OwnedTargetMachine::new(
264+
&triple,
265+
&cpu,
266+
&features,
267+
&abi,
268+
code_model,
269+
reloc_model,
270+
opt_level,
271+
use_softfp,
272+
ffunction_sections,
273+
fdata_sections,
274+
funique_section_names,
275+
trap_unreachable,
276+
singlethread,
277+
asm_comments,
278+
emit_stack_size_section,
279+
relax_elf_relocations,
280+
use_init_array,
281+
&split_dwarf_file,
282+
&debuginfo_compression,
283+
force_emulated_tls,
284+
&args_cstr_buff,
285+
)
290286
})
291287
}
292288

compiler/rustc_codegen_llvm/src/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ pub unsafe fn create_module<'ll>(
160160

161161
// Ensure the data-layout values hardcoded remain the defaults.
162162
if sess.target.is_builtin {
163+
// tm is disposed by its drop impl
163164
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
164-
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
165-
llvm::LLVMRustDisposeTargetMachine(tm);
165+
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
166166

167167
let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod);
168168
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes())

compiler/rustc_codegen_llvm/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern crate rustc_macros;
2222
#[macro_use]
2323
extern crate tracing;
2424

25+
use back::owned_target_machine::OwnedTargetMachine;
2526
use back::write::{create_informational_target_machine, create_target_machine};
2627

2728
use errors::ParseTargetMachineConfig;
@@ -52,6 +53,7 @@ use std::io::Write;
5253
mod back {
5354
pub mod archive;
5455
pub mod lto;
56+
pub mod owned_target_machine;
5557
mod profiling;
5658
pub mod write;
5759
}
@@ -162,7 +164,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
162164
impl WriteBackendMethods for LlvmCodegenBackend {
163165
type Module = ModuleLlvm;
164166
type ModuleBuffer = back::lto::ModuleBuffer;
165-
type TargetMachine = &'static mut llvm::TargetMachine;
167+
type TargetMachine = OwnedTargetMachine;
166168
type TargetMachineError = crate::errors::LlvmError<'static>;
167169
type ThinData = back::lto::ThinData;
168170
type ThinBuffer = back::lto::ThinBuffer;
@@ -401,7 +403,9 @@ impl CodegenBackend for LlvmCodegenBackend {
401403
pub struct ModuleLlvm {
402404
llcx: &'static mut llvm::Context,
403405
llmod_raw: *const llvm::Module,
404-
tm: &'static mut llvm::TargetMachine,
406+
407+
// independent from llcx and llmod_raw, resources get disposed by drop impl
408+
tm: OwnedTargetMachine,
405409
}
406410

407411
unsafe impl Send for ModuleLlvm {}
@@ -453,7 +457,6 @@ impl ModuleLlvm {
453457
impl Drop for ModuleLlvm {
454458
fn drop(&mut self) {
455459
unsafe {
456-
llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
457460
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
458461
}
459462
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,8 @@ extern "C" {
21122112
);
21132113

21142114
pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char;
2115+
2116+
// This function makes copies of pointed to data, so the data's lifetime may end after this function returns
21152117
pub fn LLVMRustCreateTargetMachine(
21162118
Triple: *const c_char,
21172119
CPU: *const c_char,
@@ -2135,9 +2137,9 @@ extern "C" {
21352137
ForceEmulatedTls: bool,
21362138
ArgsCstrBuff: *const c_char,
21372139
ArgsCstrBuffLen: usize,
2138-
) -> Option<&'static mut TargetMachine>;
2140+
) -> *mut TargetMachine;
21392141

2140-
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
2142+
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
21412143
pub fn LLVMRustAddLibraryInfo<'a>(
21422144
PM: &PassManager<'a>,
21432145
M: &'a Module,

compiler/rustc_codegen_llvm/src/llvm_util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
303303
// check that all features in a given smallvec are enabled
304304
for llvm_feature in to_llvm_features(sess, feature) {
305305
let cstr = SmallCStr::new(llvm_feature);
306-
if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
306+
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
307307
return false;
308308
}
309309
}
@@ -422,14 +422,14 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess
422422
}
423423
unsafe {
424424
llvm::LLVMRustPrintTargetCPUs(
425-
tm,
425+
&tm,
426426
cpu_cstring.as_ptr(),
427427
callback,
428428
&mut out as *mut &mut dyn PrintBackendInfo as *mut c_void,
429429
);
430430
}
431431
}
432-
PrintKind::TargetFeatures => print_target_features(out, sess, tm),
432+
PrintKind::TargetFeatures => print_target_features(out, sess, &tm),
433433
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
434434
}
435435
}

compiler/rustc_data_structures/src/small_c_str.rs

+6
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,9 @@ impl<'a> FromIterator<&'a str> for SmallCStr {
7979
Self { data }
8080
}
8181
}
82+
83+
impl From<&ffi::CStr> for SmallCStr {
84+
fn from(s: &ffi::CStr) -> Self {
85+
Self { data: SmallVec::from_slice(s.to_bytes()) }
86+
}
87+
}

0 commit comments

Comments
 (0)