Skip to content

Commit

Permalink
Auto merge of rust-lang#123941 - Mark-Simulacrum:fix-llvm-ub, r=nikic
Browse files Browse the repository at this point in the history
Fix UB in LLVM FFI when passing zero or >1 bundle

Rust passes a `*const &OperandBundleDef` to these APIs, usually from a `Vec<&OperandBundleDef>` or so. Previously we were dereferencing that pointer and passing it to the ArrayRef constructor with some length (N).

This meant that if the length was 0, we were dereferencing a pointer to nowhere (if the vector on the Rust side didn't actually get allocated or so), and if the length was >1 then loading the *second* element somewhere in LLVM would've been reading past the end.

Since Rust can't hold OperandBundleDef by-value we're forced to indirect through a vector that copies out the OperandBundleDefs from the by-reference list on the Rust side in order to match the LLVM expected API.
  • Loading branch information
bors committed Apr 15, 2024
2 parents 9db7a74 + bf3decc commit 55779ee
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Expand Up @@ -1524,13 +1524,21 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {

extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
OperandBundleDef **OpBundles,
OperandBundleDef **OpBundlesIndirect,
unsigned NumOpBundles) {
Value *Callee = unwrap(Fn);
FunctionType *FTy = unwrap<FunctionType>(Ty);

// FIXME: Is there a way around this?
SmallVector<OperandBundleDef> OpBundles;
OpBundles.reserve(NumOpBundles);
for (unsigned i = 0; i < NumOpBundles; ++i) {
OpBundles.push_back(*OpBundlesIndirect[i]);
}

return wrap(unwrap(B)->CreateCall(
FTy, Callee, ArrayRef<Value*>(unwrap(Args), NumArgs),
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles)));
ArrayRef<OperandBundleDef>(OpBundles)));
}

extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
Expand Down Expand Up @@ -1570,13 +1578,21 @@ extern "C" LLVMValueRef
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
OperandBundleDef **OpBundles, unsigned NumOpBundles,
OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
const char *Name) {
Value *Callee = unwrap(Fn);
FunctionType *FTy = unwrap<FunctionType>(Ty);

// FIXME: Is there a way around this?
SmallVector<OperandBundleDef> OpBundles;
OpBundles.reserve(NumOpBundles);
for (unsigned i = 0; i < NumOpBundles; ++i) {
OpBundles.push_back(*OpBundlesIndirect[i]);
}

return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
ArrayRef<Value*>(unwrap(Args), NumArgs),
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
ArrayRef<OperandBundleDef>(OpBundles),
Name));
}

Expand All @@ -1585,7 +1601,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMBasicBlockRef DefaultDest,
LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
LLVMValueRef *Args, unsigned NumArgs,
OperandBundleDef **OpBundles, unsigned NumOpBundles,
OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
const char *Name) {
Value *Callee = unwrap(Fn);
FunctionType *FTy = unwrap<FunctionType>(Ty);
Expand All @@ -1597,11 +1613,18 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i]));
}

// FIXME: Is there a way around this?
SmallVector<OperandBundleDef> OpBundles;
OpBundles.reserve(NumOpBundles);
for (unsigned i = 0; i < NumOpBundles; ++i) {
OpBundles.push_back(*OpBundlesIndirect[i]);
}

return wrap(unwrap(B)->CreateCallBr(
FTy, Callee, unwrap(DefaultDest),
ArrayRef<BasicBlock*>(IndirectDestsUnwrapped),
ArrayRef<Value*>(unwrap(Args), NumArgs),
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
ArrayRef<OperandBundleDef>(OpBundles),
Name));
}

Expand Down

0 comments on commit 55779ee

Please sign in to comment.