Skip to content

Commit ead21f6

Browse files
committed
wrap llvm::TargetMachine and use pointers instead of &'static mut for creating/disposing
1 parent 3ecc563 commit ead21f6

File tree

7 files changed

+140
-40
lines changed

7 files changed

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

compiler/rustc_codegen_llvm/src/back/write.rs

+26-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::back::lto::ThinBuffer;
22
use crate::back::profiling::{
33
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
44
};
5+
use crate::back::target_machine_wrapper::TargetMachineWrapper;
56
use crate::base;
67
use crate::common;
78
use crate::errors::{
@@ -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) -> TargetMachineWrapper {
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) -> TargetMachineWrapper {
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+
TargetMachineWrapper::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

+1-2
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@ pub unsafe fn create_module<'ll>(
161161
// Ensure the data-layout values hardcoded remain the defaults.
162162
if sess.target.is_builtin {
163163
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
164-
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
165-
llvm::LLVMRustDisposeTargetMachine(tm);
164+
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
166165

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

compiler/rustc_codegen_llvm/src/lib.rs

+4-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::target_machine_wrapper::TargetMachineWrapper;
2526
use back::write::{create_informational_target_machine, create_target_machine};
2627

2728
use errors::ParseTargetMachineConfig;
@@ -53,6 +54,7 @@ mod back {
5354
pub mod archive;
5455
pub mod lto;
5556
mod profiling;
57+
pub mod target_machine_wrapper;
5658
pub mod write;
5759
}
5860

@@ -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 = TargetMachineWrapper;
166168
type TargetMachineError = crate::errors::LlvmError<'static>;
167169
type ThinData = back::lto::ThinData;
168170
type ThinBuffer = back::lto::ThinBuffer;
@@ -401,7 +403,7 @@ 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+
tm: TargetMachineWrapper,
405407
}
406408

407409
unsafe impl Send for ModuleLlvm {}
@@ -453,7 +455,6 @@ impl ModuleLlvm {
453455
impl Drop for ModuleLlvm {
454456
fn drop(&mut self) {
455457
unsafe {
456-
llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
457458
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
458459
}
459460
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2135,9 +2135,9 @@ extern "C" {
21352135
ForceEmulatedTls: bool,
21362136
ArgsCstrBuff: *const c_char,
21372137
ArgsCstrBuffLen: usize,
2138-
) -> Option<&'static mut TargetMachine>;
2138+
) -> *mut TargetMachine;
21392139

2140-
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
2140+
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
21412141
pub fn LLVMRustAddLibraryInfo<'a>(
21422142
PM: &PassManager<'a>,
21432143
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)