1
Fork 0

Fix unsafe_op_in_unsafe_fn in compiler

This commit is contained in:
Michael Goulet 2024-07-14 14:27:57 -04:00
parent 71eb49c318
commit 28503d69ac
15 changed files with 386 additions and 311 deletions

View file

@ -120,7 +120,7 @@ pub unsafe fn create_module<'ll>(
) -> &'ll llvm::Module {
let sess = tcx.sess;
let mod_name = SmallCStr::new(mod_name);
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version();
@ -153,11 +153,14 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults.
{
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
}
let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod);
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes())
.expect("got a non-UTF8 data-layout from LLVM");
let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) };
let llvm_data_layout =
str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes())
.expect("got a non-UTF8 data-layout from LLVM");
if target_data_layout != llvm_data_layout {
tcx.dcx().emit_err(crate::errors::MismatchedDataLayout {
@ -170,20 +173,28 @@ pub unsafe fn create_module<'ll>(
}
let data_layout = SmallCStr::new(&target_data_layout);
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
unsafe {
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
}
let llvm_target = SmallCStr::new(&sess.target.llvm_target);
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
unsafe {
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
}
let reloc_model = sess.relocation_model();
if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) {
llvm::LLVMRustSetModulePICLevel(llmod);
unsafe {
llvm::LLVMRustSetModulePICLevel(llmod);
}
// PIE is potentially more effective than PIC, but can only be used in executables.
// If all our outputs are executables, then we can relax PIC to PIE.
if reloc_model == RelocModel::Pie
|| tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable)
{
llvm::LLVMRustSetModulePIELevel(llmod);
unsafe {
llvm::LLVMRustSetModulePIELevel(llmod);
}
}
}
@ -192,95 +203,109 @@ pub unsafe fn create_module<'ll>(
// longer jumps) if a larger code model is used with a smaller one.
//
// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323.
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model()));
unsafe {
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model()));
}
// If skipping the PLT is enabled, we need to add some module metadata
// to ensure intrinsic calls don't use it.
if !sess.needs_plt() {
let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
}
}
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
canonical_jump_tables,
1,
);
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
canonical_jump_tables,
1,
);
}
}
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
enable_split_lto_unit,
1,
);
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
enable_split_lto_unit,
1,
);
}
}
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() {
let kcfi = c"kcfi".as_ptr().cast();
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
}
}
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc {
match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
1,
)
}
CFGuard::Checks => {
// Set `cfguard=2` module flag to emit metadata and checks.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
2,
)
unsafe {
match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
1,
)
}
CFGuard::Checks => {
// Set `cfguard=2` module flag to emit metadata and checks.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
2,
)
}
}
}
}
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
if sess.target.arch == "aarch64" {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"branch-target-enforcement".as_ptr().cast(),
bti.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address".as_ptr().cast(),
pac_ret.is_some().into(),
);
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-all".as_ptr().cast(),
pac_opts.leaf.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-with-bkey".as_ptr().cast(),
u32::from(pac_opts.key == PAuthKey::B),
);
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"branch-target-enforcement".as_ptr().cast(),
bti.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address".as_ptr().cast(),
pac_ret.is_some().into(),
);
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-all".as_ptr().cast(),
pac_opts.leaf.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-with-bkey".as_ptr().cast(),
u32::from(pac_opts.key == PAuthKey::B),
);
}
} else {
bug!(
"branch-protection used on non-AArch64 target; \
@ -291,39 +316,47 @@ pub unsafe fn create_module<'ll>(
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-branch".as_ptr().cast(),
1,
)
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-branch".as_ptr().cast(),
1,
);
}
}
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-return".as_ptr().cast(),
1,
)
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-return".as_ptr().cast(),
1,
);
}
}
if sess.opts.unstable_opts.virtual_function_elimination {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"Virtual Function Elim".as_ptr().cast(),
1,
);
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"Virtual Function Elim".as_ptr().cast(),
1,
);
}
}
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
if sess.opts.unstable_opts.ehcont_guard {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"ehcontguard".as_ptr() as *const _,
1,
)
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"ehcontguard".as_ptr() as *const _,
1,
)
}
}
// Insert `llvm.ident` metadata.
@ -333,16 +366,20 @@ pub unsafe fn create_module<'ll>(
#[allow(clippy::option_env_unwrap)]
let rustc_producer =
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
let name_metadata = llvm::LLVMMDStringInContext(
llcx,
rustc_producer.as_ptr().cast(),
rustc_producer.as_bytes().len() as c_uint,
);
llvm::LLVMAddNamedMetadataOperand(
llmod,
c"llvm.ident".as_ptr(),
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
);
let name_metadata = unsafe {
llvm::LLVMMDStringInContext(
llcx,
rustc_producer.as_ptr().cast(),
rustc_producer.as_bytes().len() as c_uint,
)
};
unsafe {
llvm::LLVMAddNamedMetadataOperand(
llmod,
c"llvm.ident".as_ptr(),
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
);
}
// Emit RISC-V specific target-abi metadata
// to workaround lld as the LTO plugin not
@ -351,13 +388,15 @@ pub unsafe fn create_module<'ll>(
// If llvm_abiname is empty, emit nothing.
let llvm_abiname = &sess.target.options.llvm_abiname;
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
llvm::LLVMRustAddModuleFlagString(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"target-abi".as_ptr(),
llvm_abiname.as_ptr().cast(),
llvm_abiname.len(),
);
unsafe {
llvm::LLVMRustAddModuleFlagString(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"target-abi".as_ptr(),
llvm_abiname.as_ptr().cast(),
llvm_abiname.len(),
);
}
}
// Add module flags specified via -Z llvm_module_flag
@ -375,7 +414,7 @@ pub unsafe fn create_module<'ll>(
// We already checked this during option parsing
_ => unreachable!(),
};
llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value)
unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
}
llmod