Dispose llvm::TargetMachines prior to llvm::Context being disposed

If the TargetMachine is disposed after the Context is disposed, it can
lead to use after frees in some cases.

I've observed this happening occasionally on code compiled for
aarch64-pc-windows-msvc using `-Zstack-protector=strong` but other users
have reported AVs from host aarch64-pc-windows-msvc compilers as well.
This commit is contained in:
Wesley Wiser 2023-11-29 17:36:45 -06:00
parent b10cfcd65f
commit 3323e4dc04
2 changed files with 18 additions and 6 deletions

View File

@ -25,6 +25,7 @@
use std::fs::File;
use std::io;
use std::iter;
use std::mem::ManuallyDrop;
use std::path::Path;
use std::slice;
use std::sync::Arc;
@ -734,7 +735,7 @@ pub unsafe fn optimize_thin_module(
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
let mut module = ModuleCodegen {
module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) },
name: thin_module.name().to_string(),
kind: ModuleKind::Regular,
};

View File

@ -52,6 +52,7 @@
use std::any::Any;
use std::ffi::CStr;
use std::io::Write;
use std::mem::ManuallyDrop;
mod back {
pub mod archive;
@ -407,8 +408,9 @@ pub struct ModuleLlvm {
llcx: &'static mut llvm::Context,
llmod_raw: *const llvm::Module,
// independent from llcx and llmod_raw, resources get disposed by drop impl
tm: OwnedTargetMachine,
// This field is `ManuallyDrop` because it is important that the `TargetMachine`
// is disposed prior to the `Context` being disposed otherwise UAFs can occur.
tm: ManuallyDrop<OwnedTargetMachine>,
}
unsafe impl Send for ModuleLlvm {}
@ -419,7 +421,11 @@ fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) }
ModuleLlvm {
llmod_raw,
llcx,
tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),
}
}
}
@ -427,7 +433,11 @@ fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
ModuleLlvm {
llmod_raw,
llcx,
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
}
}
}
@ -448,7 +458,7 @@ fn parse(
}
};
Ok(ModuleLlvm { llmod_raw, llcx, tm })
Ok(ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) })
}
}
@ -460,6 +470,7 @@ fn llmod(&self) -> &llvm::Module {
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
drop(ManuallyDrop::take(&mut self.tm));
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
}
}