diff options
| author | 许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com> | 2024-04-15 16:56:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-15 16:56:19 +0100 |
| commit | 4f3a39ba7925fe83d75e0bc7a2c65a200e55f0e4 (patch) | |
| tree | 5ed1c801a25da3303a69e18c92f28dec56813f4c /compiler/rustc_llvm/llvm-wrapper | |
| parent | 5580ae979579c7ca19b7fd5c55f7f82914ac4d5c (diff) | |
| parent | bf3deccdadffbd5903268cca74a60f7101f7e9c3 (diff) | |
| download | rust-4f3a39ba7925fe83d75e0bc7a2c65a200e55f0e4.tar.gz rust-4f3a39ba7925fe83d75e0bc7a2c65a200e55f0e4.zip | |
Rollup merge of #123941 - Mark-Simulacrum:fix-llvm-ub, r=nikic
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.
Diffstat (limited to 'compiler/rustc_llvm/llvm-wrapper')
| -rw-r--r-- | compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 35 |
1 files changed, 29 insertions, 6 deletions
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 37c2da4c23a..6e11fd629e4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -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) { @@ -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)); } @@ -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); @@ -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)); } |
